diff --git a/.codex b/.codex new file mode 100644 index 0000000..e69de29 diff --git a/src/l2/alice/engine.h b/src/l2/alice/engine.h index f3278d2..545285f 100644 --- a/src/l2/alice/engine.h +++ b/src/l2/alice/engine.h @@ -1077,6 +1077,7 @@ void alice_frame_drawing(Alice* alice) { // MutRefWidget_draw(alice->overlay_ui_root, (ivec2){0}, (uvec2){win_width, win_height}, (BorderS32){.lt = {0}, // .rb.x = (S32)win_width, .rb.y = (S32)win_height}); Plain2dShapeRenderer_another_frame(&alice->plain_shape_renderer); + LucyGlyphCache_another_frame_flush_dyn_images_transfer(&alice->lucy_cache); LucyRenderer_another_frame(&alice->lucy_renderer); margaret_end_command_buffer(alice->transfer_command_buf); margaret_end_command_buffer(alice->compute_command_buf); diff --git a/src/l2/lucy/glyph_cache.h b/src/l2/lucy/glyph_cache.h index d1ef6f1..14315cc 100644 --- a/src/l2/lucy/glyph_cache.h +++ b/src/l2/lucy/glyph_cache.h @@ -13,7 +13,7 @@ #include FT_FREETYPE_H #define LUCY_MAX_DESCRIPTOR_COUNT 100 -#define LUCY_INITIAL_DYN_IMAGE_DIM 300 +#define LUCY_INITIAL_DYN_IMAGE_DIM 1 #define LUCY_INITIAL_DYN_STAGING_BUF_SIZE 30000 typedef struct { @@ -113,16 +113,15 @@ U32 LucyGlyphCache__find_image_slot(LucyGlyphCache* cache){ void LucyGlyphCache__create_dyn_texture(LucyGlyphCache* cache, U32 new_atlas_dim) { assert(new_atlas_dim <= cache->max_dim); U32 image_slot_id = LucyGlyphCache__find_image_slot(cache); - MargaretImg dev_local = MargaretImgAllocator_alloc(cache->ve.dev_local_images, + MargaretImg dev_local_img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, new_atlas_dim, new_atlas_dim, VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); VkImageView view = margaret_create_view_for_image( - cache->ve.device, dev_local.a.image, VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + cache->ve.device, dev_local_img.a.image, VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, image_slot_id); assert(img_slot->variant == Option_Some); img_slot->some.usage = 1; - img_slot->some.tex = (MargaretTexture){}; - + img_slot->some.tex = (MargaretTexture){ .img = dev_local_img, .view = view}; vkUpdateDescriptorSets(cache->ve.device, 1, &(VkWriteDescriptorSet){ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, @@ -240,10 +239,11 @@ void LucyGlyphCache__extract_bitmap(FT_Face ft_face, U32 codepoint, U32 max_dim, } } -/* pos on atlas may be left undefined */ +/* pos_on_atlas may be left undefined, img_slot_id may be left undefined */ LucyStoredGlyph* LucyGlyphCache__add_glyph_to_glyph_set(BufRBTree_MapU32ToLucyStoredGlyph* glyph_set, - U32 codepoint, FT_GlyphSlot slot, uvec2 pos_on_atlas) { + U32 codepoint, FT_GlyphSlot slot, uvec2 pos_on_atlas, U32 img_slot_id) { bool iret = BufRBTree_MapU32ToLucyStoredGlyph_insert(glyph_set, codepoint, (LucyStoredGlyph){ + .img_slot_id = img_slot_id, .w = slot->bitmap.width, .h = slot->bitmap.rows, .advance_x = slot->advance.x >> 6, .bearing = (ivec2){ slot->bitmap_left, -slot->bitmap_top }, @@ -261,6 +261,27 @@ U32 LucyGlyphCache__pick_size_next_dyn_img(U32 max_dim, U32 cur_dyn_img_dim) { return cur_dyn_img_dim * 2 <= max_dim ? cur_dyn_img_dim * 2 : max_dim; } +/* Recurring piece of code in LucyGlyphCache_get_glyph_on_the_fly() to reset current atlas */ +void LucyGlyphCache_get_glyph_on_the_fly__another_dyn_atlas(LucyGlyphCache* cache, U32 cur_dyn_img_dim) { + /* Suppose we sent some dynamic atlas to deleter. Ok, so what? We will first perform some meaningless + * copying from staging to device local image. */ + LucyGlyphCache__decrease_image_usage(cache, cache->dynamic_image_slot); + + U32 new_dyn_img_dim = LucyGlyphCache__pick_size_next_dyn_img(cache->max_dim, cur_dyn_img_dim); + LucyGlyphCache__create_dyn_texture(cache, new_dyn_img_dim); + /* cache->dynamic_img_slot was updated */ + VecLucyAccumDynTransferImage_append(&cache->accumulated_dyn_images, (LucyAccumDynTransferImage){ + .img_slot_id = cache->dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(), + }); + + for (size_t x = 0; x < cur_dyn_img_dim; x++) { + cache->dynamic_image_landscape.buf[x] = 0; + } + VecU32_expand(&cache->dynamic_image_landscape, new_dyn_img_dim, 0); + + cache->dynamic_landscape_progress_x = 0; +} + /* Returned pointer will be invalidated after you modify the set of codepoints for this size of this face */ LucyStoredGlyph* LucyGlyphCache_get_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs_node, U32 codepoint) { LucyFaceFixedSize* ffs = &ffs_node->value; @@ -282,48 +303,45 @@ LucyStoredGlyph* LucyGlyphCache_get_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize } another_attempt: {} + printf("DEBUG: Attempting to add %u\n", codepoint); assert(cache->image_slots.buf[cache->dynamic_image_slot].variant == Option_Some); LucyImage* dyn_img = &cache->image_slots.buf[cache->dynamic_image_slot].some; U32 cur_dyn_img_dim = dyn_img->tex.img.width; assert(cur_dyn_img_dim == dyn_img->tex.img.height); + if (ft_slot->bitmap.width > cur_dyn_img_dim) { + LucyGlyphCache_get_glyph_on_the_fly__another_dyn_atlas(cache, cur_dyn_img_dim); + printf("Cause 0: %u > %u\n", ft_slot->bitmap.width, cur_dyn_img_dim); + goto another_attempt; + } + U32 required_atlas_width = cache->dynamic_landscape_progress_x + ft_slot->bitmap.width; if (required_atlas_width > cur_dyn_img_dim) { + printf("Cause 1: %u > %u\n", required_atlas_width, cur_dyn_img_dim); cache->dynamic_landscape_progress_x = 0; goto another_attempt; } + assert(cur_dyn_img_dim == cache->dynamic_image_landscape.len); U32 start_y = 0; for (size_t gx = 0; gx < ft_slot->bitmap.width; gx++) { - start_y = MAX_U32(start_y, cache->dynamic_image_landscape.buf[gx]); + start_y = MAX_U32(start_y, cache->dynamic_image_landscape.buf[cache->dynamic_landscape_progress_x + gx]); } U32 ceiling = start_y + ft_slot->bitmap.rows; if (ceiling > cur_dyn_img_dim) { /* This is serious. We need to issue a new image */ - - // If we see that usage is zero, we want to pop the last img - // from accumulated_syn_images and send it to deleter (for images) - if (LucyGlyphCache__decrease_image_usage(cache, cache->dynamic_image_slot)) { - assert(cache->accumulated_dyn_images.buf[cache->accumulated_dyn_images.len - 1].glyphs.capacity == 0); - cache->accumulated_dyn_images.len--; - } - - U32 new_dyn_img_dim = LucyGlyphCache__pick_size_next_dyn_img(max_dim, cur_dyn_img_dim); - LucyGlyphCache__create_dyn_texture(cache, new_dyn_img_dim); - /* cache->dynamic_img_slot was updated */ - VecLucyAccumDynTransferImage_append(&cache->accumulated_dyn_images, (LucyAccumDynTransferImage){ - .img_slot_id = cache->dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(), - }); - - for (size_t x = 0; x < cur_dyn_img_dim; x++) { - cache->dynamic_image_landscape.buf[x] = 0; - } - VecU32_expand(&cache->dynamic_image_landscape, new_dyn_img_dim, 0); - - cache->dynamic_landscape_progress_x = 0; + LucyGlyphCache_get_glyph_on_the_fly__another_dyn_atlas(cache, cur_dyn_img_dim); goto another_attempt; } + /* Successful placement */ + for (size_t gx = 0; gx < ft_slot->bitmap.width; gx++) { + cache->dynamic_image_landscape.buf[cache->dynamic_landscape_progress_x + gx] = ceiling; + } + dyn_img->usage++; + + /* This is actually annoying, I may todo: make a function that forms VkBufferImageCopy for me */ VecVkBufferImageCopy_append(&cache->accumulated_dyn_images.buf[cache->accumulated_dyn_images.len - 1].glyphs, - (VkBufferImageCopy){ .bufferOffset = cache->dyn_staging_usage, + (VkBufferImageCopy){ + .bufferOffset = cache->dyn_staging.start + cache->dyn_staging_usage, .bufferRowLength = 0, .bufferImageHeight = 0, .imageSubresource = (VkImageSubresourceLayers){ @@ -333,25 +351,33 @@ LucyStoredGlyph* LucyGlyphCache_get_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize .imageExtent = { .width = ft_slot->bitmap.width, .height = ft_slot->bitmap.rows, .depth = 1 }, }); + U64 needed_staging_sz = cache->dyn_staging_usage + bitmap->rows * bitmap->width * sizeof(U8); + if (cache->dyn_staging.len < needed_staging_sz) { + MargaretSubbuf_expand_or_move_old_host_visible(&cache->dyn_staging, + Vec_get_new_capacity(cache->dyn_staging.len, needed_staging_sz)); + } + assert(cache->dyn_staging.len >= needed_staging_sz); U8* staging_pixels = (U8*)MargaretSubbuf_get_mapped(&cache->dyn_staging) + cache->dyn_staging_usage; for (S64 y = 0; y < bitmap->rows; y++) { for (S64 x = 0; x < bitmap->width; x++) { *(staging_pixels + (y * bitmap->width + x) * sizeof(U8)) = *(bitmap->buffer + (y * bitmap->pitch + x) * sizeof(U8)); } - } - cache->dyn_staging_usage += bitmap->rows * bitmap->width * sizeof(U8); + cache->dyn_staging_usage = needed_staging_sz; LucyStoredGlyph* res = LucyGlyphCache__add_glyph_to_glyph_set(glyph_set, codepoint, ft_slot, - (uvec2){cache->dynamic_landscape_progress_x, start_y}); + (uvec2){cache->dynamic_landscape_progress_x, start_y}, cache->dynamic_image_slot); + + cache->dynamic_landscape_progress_x += bitmap->width; + return res; } /* This function must be called at the end of another_frame callback, after every single operation with glyph cache * has been done. It will record copy commands for transferring dynamic images. All the accumulated dyn-glyph * records will be cleared */ -void LucyGlyphCache__flush_dyn_images_transfer(LucyGlyphCache* cache) { +void LucyGlyphCache_another_frame_flush_dyn_images_transfer(LucyGlyphCache* cache) { for (size_t ii = 0; ii < cache->accumulated_dyn_images.len; ii++) { LucyAccumDynTransferImage* img_regions = &cache->accumulated_dyn_images.buf[ii]; margaret_rec_cmd_copy_buffer_to_image(cache->ve.transfer_cmd_buffer, @@ -489,8 +515,8 @@ void LucyGlyphCache_add_glyphs(LucyGlyphCache* cache, VecLucyGlyphCachingRequest TextureDataR8 my_bitmap; FT_GlyphSlot slot; LucyGlyphCache__extract_bitmap(ft_face, codepoint, cache->max_dim, &my_bitmap, &slot); - /* x_on_atlas, y_on_atlas and img will be set later, when `ready` vector is ready */ - LucyGlyphCache__add_glyph_to_glyph_set(glyph_set, codepoint, slot, (uvec2){0}); + /* x_on_atlas, y_on_atlas and img_slot_id will be set later, when `ready` vector is ready */ + LucyGlyphCache__add_glyph_to_glyph_set(glyph_set, codepoint, slot, (uvec2){0}, 0); VecLucyPositionedStagingGlyph_append(&ready, (LucyPositionedStagingGlyph){ .sized_face = &req.sized_face->value, .codepoint = codepoint, .bitmap = my_bitmap, /* pos be filled later by packing algorithm */ diff --git a/src/l2/lucy/glyph_render.h b/src/l2/lucy/glyph_render.h index 9812337..3d75026 100644 --- a/src/l2/lucy/glyph_render.h +++ b/src/l2/lucy/glyph_render.h @@ -94,7 +94,8 @@ void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, Luc U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance); if (self->staging_vbo.len < needed_vbo_length) { - MargaretSubbuf_expand_or_move_old_host_visible(&self->staging_vbo, needed_vbo_length); + MargaretSubbuf_expand_or_move_old_host_visible(&self->staging_vbo, + Vec_get_new_capacity(self->staging_vbo.len, needed_vbo_length)); } LucyRenderInstance* vbo_data = (LucyRenderInstance*)MargaretSubbuf_get_mapped(&self->staging_vbo); diff --git a/src/l3/r4/r4b.c b/src/l3/r4/r4b.c index 3aeac28..dae4fa0 100644 --- a/src/l3/r4/r4b.c +++ b/src/l3/r4/r4b.c @@ -333,19 +333,19 @@ void run_app(){ // st.font_face = Alice_new_LucyFace(alice, vcstr("./src/l3/fonts/DMSerifText-Regular.ttf")); st.font_face = Alice_new_LucyFace(alice, vcstr("./src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf")); st.font_face_of_size_40 = LucyFace_of_size(st.font_face, 40); - 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 = st.font_face_of_size_40, .codepoint_ranges = ranges_needed, - }); - ranges_needed = VecU32Segment_new(); - VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x430, .len = 0x44f - 0x430 + 1}); - VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x410, .len = 0x42f - 0x410 + 1}); - VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){ - .sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed, - }); - Alice_lucy_cache_add_glyphs(alice, lucy_requests); + // 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 = st.font_face_of_size_40, .codepoint_ranges = ranges_needed, + // }); + // ranges_needed = VecU32Segment_new(); + // VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x430, .len = 0x44f - 0x430 + 1}); + // VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x410, .len = 0x42f - 0x410 + 1}); + // VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){ + // .sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed, + // }); + // Alice_lucy_cache_add_glyphs(alice, lucy_requests); Alice_lucy_renderer_add_simple_label(alice, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, cstr("..."), (ivec2){10, 10});