Found a serious flaw in Lucy design. A very very serious flaw. Gonna rewrite everything

This commit is contained in:
Андреев Григорий 2026-01-01 15:29:05 +03:00
parent 91f6b8e2f6
commit 284b0b711b
4 changed files with 115 additions and 58 deletions

View File

@ -80,6 +80,10 @@ struct LucyGlyphCache {
VecRefListNodeLucyImage to_be_copied_to_device_next_cycle;
/* deletion will be performed last */
VecRefListNodeLucyImage to_be_deleted;
/* This filed is actually used in later stages of 'another_frame' sequence. It is used by font renderer
* to know if sus stuff had occurred. At the beginning of my _another_frame method it gets turned false
* automatically, but during my _another_frame it can get raised true to indicate reshuffling of images */
bool changes_happened;
};
@ -98,7 +102,10 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){
VkDescriptorSet descriptor_set = margaret_allocate_descriptor_set(ve.device, ve.descriptor_pool,
my_desc_set_layout);
return (LucyGlyphCache){.ve = ve, .images = ListLucyImage_new(),
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set};
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set,
.to_be_freed_of_old_staging_next_cycle = VecRefListNodeLucyImage_new(),
.to_be_copied_to_device_next_cycle = VecRefListNodeLucyImage_new(),
.to_be_deleted = VecRefListNodeLucyImage_new(), .changes_happened = false};
}
void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
@ -302,7 +309,10 @@ void LucyGlyphCache_drop(LucyGlyphCache self){
VecRefListNodeLucyImage_drop(self.to_be_deleted);
}
void
void LucyGlyphCache_another_frame(LucyGlyphCache* self){
self->changes_happened = false;
for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) {
LucyImage* img = &self->to_be_freed_of_old_staging_next_cycle.buf[i]->el;
assert(img->staging_buffer.len != 0);
@ -355,6 +365,7 @@ void LucyGlyphCache_another_frame(LucyGlyphCache* self){
.pImageInfo = desc_elements.buf
}, 0, NULL);
VecVkDescriptorImageInfo_drop(desc_elements);
self->changes_happened = true;
}
self->to_be_freed_of_old_staging_next_cycle.len = 0;
self->to_be_copied_to_device_next_cycle.len = 0;

View File

@ -13,13 +13,32 @@ typedef struct{
U32 tex_ind;
} LucyVertex;
typedef struct {
ListNodeLucyImage* img;
vec4 color;
ivec2 positioned;
uvec2 pos_on_atlas;
U32 w;
U32 h;
} LucyRenderedGlyphRecord;
#include "../../../gen/l1/eve/lucy/VecLucyRenderedGlyphRecord.h"
typedef struct {
vec4 color;
vec2 lt_pos;
vec2 br_pos;
vec2 lt_tex;
vec2 br_tex;
} LucyGlyphInstance;
typedef struct {
MargaretEngineReference ve;
LucyGlyphCache* cache;
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
U64 vertex_count;
VecLucyRenderedGlyphRecord rendered_glyphs;
MargaretSubbuf staging_vbo;
MargaretSubbuf vbo;
bool need_to_transfer;
@ -67,7 +86,7 @@ LucyRenderer LucyRenderer_new(
});
return (LucyRenderer){.ve = ve, .cache = cache, .pipeline_layout = pipeline_layout, .pipeline = pipeline,
.vertex_count = 0, .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67),
.rendered_glyphs = VecLucyRenderedGlyphRecord_new(), .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67),
.vbo = MargaretBufAllocator_alloc(ve.dev_local_buffers, 67)
};
}
@ -76,14 +95,7 @@ LucyRenderer LucyRenderer_new(
* before LucyRenderer_another_frame
*/
void LucyRenderer_clear(LucyRenderer* self){
self->vertex_count = 0;
}
void LucyRenderer__append_vertex_to_vao(LucyRenderer* self, LucyVertex vert_data){
self->vertex_count++;
assert(self->vertex_count * sizeof(LucyVertex) <= self->staging_vbo.len);
LucyVertex* staging = (LucyVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo);
staging[self->vertex_count - 1] = vert_data;
self->rendered_glyphs.len = 0;
}
/* When another_frame starts, you are safe to call this function, but you also have to call it
@ -113,10 +125,40 @@ void LucyRenderer_add_text(
assert(map_it > 0 && map_it < glyphs->tree.len);
LucyStoredGlyph* glyph = &glyphs->el.buf[map_it - 1].value;
if (glyph->w > 0 && glyph->h > 0) {
VecLucyRenderedGlyphRecord_append(&self->rendered_glyphs, (LucyRenderedGlyphRecord){
.color = color, .img = glyph->img,
.positioned = ivec2_add_ivec2(pos, glyph->bearing),
.pos_on_atlas = glyph->pos_on_atlas, .w = glyph->w, .h = glyph->h
});
}
pos.x += (S32)glyph->advance_x;
}
}
/* It only records transfer commands (transfer command buffer is passed in MargaretEngineReference object) */
void LucyRenderer_another_frame(LucyRenderer* self){
U64 needed_vbo_length = self->rendered_glyphs.len * 6 * sizeof(LucyVertex);
if (self->staging_vbo.len < needed_vbo_length) {
printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n",
self->staging_vbo.len, needed_vbo_length);
MargaretBufAllocator_expand_or_move_old_host_visible(
self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length);
}
if (self->vbo.len < needed_vbo_length) {
MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length);
}
size_t vertex_id = 0; // todo: rewrite using instances
LucyVertex* vbo_data = (LucyVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo);
if ((self->cache->changes_happened || self->need_to_transfer) && self->rendered_glyphs.len > 0) {
printf("LucyRenderer: we are doing copying\n");
for (size_t i = 0; i < self->rendered_glyphs.len; i++) {
LucyRenderedGlyphRecord* glyph = &self->rendered_glyphs.buf[i];
float atlas_w = (float)glyph->img->el.img.width;
float atlas_h = (float)glyph->img->el.img.height;
U32 desc_elem_id = glyph->img->el.pos_in_desc_array;
ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing);
vec4 color = glyph->color;
ivec2 positioned = glyph->positioned;
LucyVertex v0 = {
.color = color, .pos = (vec2){(float)positioned.x, (float)positioned.y},
.tex_cord = (vec2){
@ -145,36 +187,17 @@ void LucyRenderer_add_text(
(float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h
}, .tex_ind = desc_elem_id
};
/* What if we run out of space? */
U64 needed_vbo_length = (self->vertex_count + 6) * sizeof(LucyVertex);
if (self->staging_vbo.len < needed_vbo_length) {
printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n",
self->staging_vbo.len, needed_vbo_length);
MargaretBufAllocator_expand_or_move_old_host_visible(
self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length);
}
LucyRenderer__append_vertex_to_vao(self, v1);
LucyRenderer__append_vertex_to_vao(self, v0);
LucyRenderer__append_vertex_to_vao(self, v2);
LucyRenderer__append_vertex_to_vao(self, v1);
LucyRenderer__append_vertex_to_vao(self, v2);
LucyRenderer__append_vertex_to_vao(self, v3);
vbo_data[vertex_id++] = v1;
vbo_data[vertex_id++] = v0;
vbo_data[vertex_id++] = v2;
vbo_data[vertex_id++] = v1;
vbo_data[vertex_id++] = v2;
vbo_data[vertex_id++] = v3;
}
pos.x += (S32)glyph->advance_x;
}
}
/* It only records transfer commands (transfer command buffer is passed in MargaretEngineReference object) */
void LucyRenderer_another_frame(LucyRenderer* self){
if (self->vbo.len < self->vertex_count * sizeof(LucyVertex)) {
MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo,
self->vertex_count * sizeof(LucyVertex));
}
if (self->need_to_transfer && self->vertex_count > 0) {
self->need_to_transfer = false;
margaret_rec_cmd_copy_buffer_one_to_one_part(self->ve.transfer_cmd_buffer,
&self->staging_vbo, &self->vbo, 0, self->vertex_count * sizeof(LucyVertex));
&self->staging_vbo, &self->vbo, 0, needed_vbo_length);
}
}
@ -189,7 +212,7 @@ void LucyRenderer_another_frame_rec_drawing(
(VkBuffer[]){MargaretSubbuf_get_buffer(&self->vbo)}, (VkDeviceSize[]){self->vbo.start});
vkCmdBindDescriptorSets(drawing_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, self->pipeline_layout, 0,
1, (VkDescriptorSet[]){self->cache->descriptor_set}, 0, NULL);
vkCmdDraw(drawing_cmd_buf, self->vertex_count, 1, 0, 0);
vkCmdDraw(drawing_cmd_buf, self->rendered_glyphs.len * 6, 1, 0, 0);
}
#endif

View File

@ -6,9 +6,9 @@ import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef)
import Data.Word(Word32, Word64)
lucyFaceAddGlyphRange :: LucyFaceFixedSize -> Char -> Char -> IO ()
lucyFaceAddGlyphRange ffs a b = lucyFaceAddGlyphs ffs A (B - A + 1) where
A = ((fromIntegral $ ord a) :: Word32)
B = ((fromIntegral $ ord b) :: Word32)
lucyFaceAddGlyphRange ffs a b = lucyFaceAddGlyphs ffs aInt (bInt - aInt + 1)
where aInt = ((fromIntegral $ ord a) :: Word32)
bInt = ((fromIntegral $ ord b) :: Word32)
-- Game configurable
@ -40,8 +40,9 @@ main = do
aliceSetCamPos alice (Vec3 0 heroHeight 0)
face <- aliceNewLucyFace alice "src/l3/fonts/DMSerifText-Regular.ttf"
faceOf40 <- aliceLucyFaceOfSize face 40
lucyFaceAddGlyphs faceOf40 32 (126 - 32 + 1)
lucyFaceAddGlyphs faceOf40 (fromIntegral) (126 - 32 + 1)
lucyFaceAddGlyphRange faceOf40 ' ' '~'
lucyFaceAddGlyphRange faceOf40 'а' 'я'
lucyFaceAddGlyphRange faceOf40 'А' 'Я'
aliceAddText alice faceOf40 (Vec4 1 1 0 1) "Privet" 100 200
weirdStructure <- aliceAddGenericMeshHand alice "gen/l2/models/log_10_2_6.AliceGenericMesh"

View File

@ -18,33 +18,55 @@ AliceGenericMeshPath AliceGenericMeshPath_for_puck(){
};
}
void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){
typedef struct{
Alice* alice;
LucyFace* font_face;
RBTreeNodeLucyFaceFixedSize* font_face_of_size_40;
} R4AlphaStuff;
void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){
}
void main_h_on_another_frame(void* data, float fl){
R4AlphaStuff *st = data;
Alice* alice = st->alice;
margaret_ns_time TIME = margaret_clock_gettime_monotonic_raw();
printf("Updating text\n");
LucyRenderer_clear(&alice->lucy_renderer);
VecU8 text = VecU8_fmt("Time is %u.%u\nHave a good day sir\n", (U64)TIME.tv_sec, (U64)TIME.tv_nsec);
LucyRenderer_add_text(&alice->lucy_renderer, st->font_face_of_size_40, (vec4){0.1f, 0.2f, 0, 1}, 0,
VecU8_to_span(&text), (ivec2){100, 100});
}
int main(){
R4AlphaStuff st;
Alice* alice = Alice_new();
st.alice = alice;
st.alice->guest = &st;
LucyFace* font_face = LucyFace_new(alice->ft_library, &alice->lucy_cache,
st.font_face = LucyFace_new(st.alice->ft_library, &st.alice->lucy_cache,
VecU8_fmt("%s/src/l3/fonts/DMSerifText-Regular.ttf", cstr(".")));
RBTreeNodeLucyFaceFixedSize* font_face_of_size_40 = LucyFace_of_size(font_face, 40);
st.font_face_of_size_40 = LucyFace_of_size(st.font_face, 13);
VecLucyGlyphCachingRequest lucy_requests = VecLucyGlyphCachingRequest_new();
VecU32Segment ranges_needed = VecU32Segment_new();
VecU32Segment_append(&ranges_needed, (U32Segment){.start = 32, .len = 126 - 32 + 1});
VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){
.sized_face = font_face_of_size_40, .codepoint_ranges = ranges_needed,
.sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed,
});
LucyGlyphCache_add_glyphs(lucy_requests);
lucy_requests = VecLucyGlyphCachingRequest_new();
ranges_needed = VecU32Segment_new();
VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x430, .len = 0x44f - 0x430 + 1});
VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){
.sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed,
});
LucyRenderer_add_text(&alice->lucy_renderer, font_face_of_size_40, (vec4){1, 0, 0, 1}, 0,
LucyGlyphCache_add_glyphs(lucy_requests);
LucyRenderer_add_text(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){1, 0, 0, 1}, 0,
cstr("Bebra budet\notnyahana"), (ivec2){10, 10});
ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
AliceGenericMeshHand_resize_instance_arr(alice, &model_gen->el, 1);
ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1);
for (int X = 0; X < 1; X++) {
for (int Z = 0; Z < 1; Z++) {
@ -54,8 +76,8 @@ int main(){
}
}
// ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
// AliceShinyMeshHand_resize_instance_arr(alice, &model_sh->el, 100);
// ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(st->alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
// AliceShinyMeshHand_resize_instance_arr(st->alice, &model_sh->el, 100);
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
@ -66,7 +88,7 @@ int main(){
// }
// }
// Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&alice->pipeline0_ubo.staging);
// Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&st->alice->pipeline0_ubo.staging);
// assert(pipeline_0_ubo_point_light_max_count >= 100);
// ubo->point_light_count = 100;
// ubo->spotlight_count = 0;
@ -81,8 +103,8 @@ int main(){
// ubo->point_light_arr[0].color = (vec3){100, 100, 100};
// ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(alice, AliceGenericMeshPath_for_puck());
// AliceGenericMeshHand_resize_instance_arr(alice, &model_puck->el, 100);
// ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(st->alice, AliceGenericMeshPath_for_puck());
// AliceGenericMeshHand_resize_instance_arr(st->alice, &model_puck->el, 100);
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// AliceGenericMeshHand_set_inst(&model_puck->el, X * 10 + Z, (GenericMeshInstanceInc){
@ -90,7 +112,7 @@ int main(){
// });
// }
// }
Alice_mainloop(alice, &(AliceCallbacks){
Alice_mainloop(st.alice, &(AliceCallbacks){
.on_wl_keyboard_key = main_h_on_wayland_keyboard_key,
.on_another_frame = main_h_on_another_frame,
});