diff --git a/src/l1/anne/lucy.h b/src/l1/anne/lucy.h index 46ccb83..740ae02 100644 --- a/src/l1/anne/lucy.h +++ b/src/l1/anne/lucy.h @@ -9,6 +9,7 @@ void generate_l1_lucy_headers(){ generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){ .T = cstr("LucyImage"), .t_primitive = true}); generate_eve_span_company_for_primitive(l, ns, cstr("OptionLucyImage"), true, false); + generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyPrepMassTransferImage"), true, false); generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyStoredGlyph"), true, false); generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyFaceFixedSize"), true, false); diff --git a/src/l2/lucy/glyph_cache.h b/src/l2/lucy/glyph_cache.h index ad5a5ce..2a62ac8 100644 --- a/src/l2/lucy/glyph_cache.h +++ b/src/l2/lucy/glyph_cache.h @@ -1,5 +1,8 @@ #pragma once +#define DARIA_ROOT "" +#define _DARIA "asdasd" + #include "../margaret/vulkan_utils.h" #include "../../../gen/l1/VecAndSpan_U32Segment.h" #include "../../../gen/l1/vulkan/VecVkDescriptorImageInfo.h" @@ -16,8 +19,6 @@ typedef struct { MargaretTexture tex; U64 usage; - /* I just could not avoid storing this here. But yeah, after the copying is done, this field stops being used */ - void* staging; } LucyImage; #include "../../../gen/l1/eve/lucy/OptionLucyImage.h" @@ -142,7 +143,8 @@ typedef struct { TextureDataR8 bitmap; /* Will be determined in the next phase */ uvec2 pos; - U32 img_slot_id; + /* But img_slot_id isn't stored here because structure itself will be relocated to the + * corresponding LucyPrepMassTransfer record for the right image */ } LucyPositionedStagingGlyph; bool LucyPositionedStagingGlyph_less_LucyPositionedStagingGlyph( @@ -157,8 +159,20 @@ void LucyPositionedStagingGlyph_drop(LucyPositionedStagingGlyph self){ /* Instantiation for helper type */ #include "../../../gen/l1/eve/lucy/VecLucyPositionedStagingGlyph.h" +typedef struct { + U32 img_slot_id; + void* staging; + VecLucyPositionedStagingGlyph glyphs_inside; +} LucyPrepMassTransferImage; + +void LucyPrepMassTransferImage_drop(LucyPrepMassTransferImage self) { + VecLucyPositionedStagingGlyph_drop(self.glyphs_inside); +} + +#include "../../../gen/l1/eve/lucy/VecLucyPrepMassTransferImage.h" + /* Helper function */ -U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){ +U32 LucyGlyphCache__find_image_slot(LucyGlyphCache* cache){ for (U32 i = 0; i < cache->image_slots.len; i++) { OptionLucyImage* slot = &cache->image_slots.buf[i]; if (slot->variant == Option_None) { @@ -171,10 +185,20 @@ U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){ "You better add up on them\n"); } +/* Helper function */ +LucyPrepMassTransferImage LucyGlyphCache_add_glyphs__another_image(LucyGlyphCache* cache) { + return (LucyPrepMassTransferImage){ + .img_slot_id = LucyGlyphCache__find_image_slot(cache), + .glyphs_inside = VecLucyPositionedStagingGlyph_new(), + }; +} + /* Helper function */ void LucyGlyphCache_add_glyphs__close_img( - LucyGlyphCache* cache, U32 img_slot_id, U32 img_width, U32 img_height + LucyGlyphCache* cache, VecLucyPrepMassTransferImage* mass_transfer, + LucyPrepMassTransferImage image_to_prep, U32 img_width, U32 img_height ){ + U32 img_slot_id = image_to_prep.img_slot_id; OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, img_slot_id); assert(img_slot->variant == Option_Some); LucyImage* img = &img_slot->some; @@ -185,8 +209,8 @@ void LucyGlyphCache_add_glyphs__close_img( img->tex = Abigail_register_new_texture(cache->abigail, img_width, img_height, sizeof(U8), VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, cache->ve.transfer_cmd_buffer, - cache->ve.staging_buffers, cache->ve.dev_local_images, &(img->staging)); - assert(img->staging); + cache->ve.staging_buffers, cache->ve.dev_local_images, &(image_to_prep.staging)); + assert(image_to_prep.staging); /* We are writing to descriptor set RIGHT NOW. That is why this function, and as such * LucyGlyphCache_add_glyphs too, must be called when no frame is in flight */ @@ -200,6 +224,8 @@ void LucyGlyphCache_add_glyphs__close_img( .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } }, 0, NULL); + /* Added with a staging buffer data pointer in it */ + VecLucyPrepMassTransferImage_append(mass_transfer, image_to_prep); } void LucyGlyphCache_add_glyphs(LucyGlyphCache* cache, VecLucyGlyphCachingRequest requests_for_faces){ @@ -236,6 +262,7 @@ void LucyGlyphCache_add_glyphs(LucyGlyphCache* cache, VecLucyGlyphCachingRequest if (slot->format != FT_GLYPH_FORMAT_BITMAP) { check(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL) == 0); } + check(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY); /* Here we dismiss very big glyphs. This guarantees that each glyph on it's own fits into VkImage */ check(bitmap->width <= max_dim && bitmap->rows <= max_dim); assert(bitmap->rows == 0 || bitmap->width != 0 || bitmap->buffer != NULL); @@ -252,73 +279,90 @@ void LucyGlyphCache_add_glyphs(LucyGlyphCache* cache, VecLucyGlyphCachingRequest }); VecLucyPositionedStagingGlyph_append(&ready, (LucyPositionedStagingGlyph){ .sized_face = &req.sized_face->value, .codepoint = codepoint, .bitmap = my_bitmap, - /* pos and img will be filled later by packing algorithm */ + /* pos be filled later by packing algorithm */ }); } } - /* Phase 2. Here we determine (in ready vector) where each new glyph sits (atlas image + pos). - * But we won't copy TextureDataR8 to staging buffer before everything is known */ - VecLucyPositionedStagingGlyph_sort(&ready); - /* Variables, that have to be reset after each image overflow */ - U32 starting_x = 0; - VecU32 landscape = VecU32_new_reserved(200); - U32 img_width = 0, img_height = 0; - U32 img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache); - for (size_t j = 0; j < ready.len; j++) { - LucyPositionedStagingGlyph* p_glyph; - one_more_chance: - {} - p_glyph = &ready.buf[j]; - LucyImage* img = &VecOptionLucyImage_mat(&cache->image_slots, img_slot_id)->some; - U64 new_width_required = p_glyph->bitmap.width + starting_x; - if (new_width_required > max_dim) { - /* Resetting row */ - starting_x = 0; - goto one_more_chance; - } - for (U32 h = img_width; h < new_width_required; h++) { - VecU32_append(&landscape, 0); - } - img_width = MAX_U64(img_width, new_width_required); - U32 height_here = 0; - for (size_t x = 0; x < p_glyph->bitmap.width; x++) { - height_here = MAX_U32(height_here, *VecU32_at(&landscape, starting_x + x)); - } - U64 new_height_required = height_here + p_glyph->bitmap.height; - if (new_height_required > max_dim) { - /* Resetting image */ - LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height); - starting_x = 0; - landscape.len = 0; - img_width = 0; - img_height = 0; - img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache); - goto one_more_chance; - } - /* Success */ - for (size_t x = 0; x < p_glyph->bitmap.width; x++) { - *VecU32_mat(&landscape, starting_x + x) = new_height_required; - } - img_height = MAX_U64(img_height, new_height_required); - p_glyph->img_slot_id = img_slot_id; - p_glyph->pos = (uvec2){starting_x, height_here}; - img->usage++; /* p_glyph uses it, that's a rock fact */ - BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &p_glyph->sized_face->glyphs; - U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, p_glyph->codepoint); - assert(map_it > 0 && map_it < glyphs->tree.len); - LucyStoredGlyph* actual_glyph = &glyphs->el.buf[map_it - 1].value; - actual_glyph->pos_on_atlas = (uvec2){starting_x, height_here}; - actual_glyph->img_slot_id = img_slot_id; - starting_x += p_glyph->bitmap.width; + } + /* Phase 2. Here we determine (in ready vector) where each new glyph sits (atlas image + pos). + * But we won't copy TextureDataR8 to staging buffer before everything is known */ + VecLucyPositionedStagingGlyph_sort(&ready); + + VecLucyPrepMassTransferImage mass_transfer = VecLucyPrepMassTransferImage_new(); + /* Variables, that have to be reset after each image overflow */ + U32 starting_x = 0; + VecU32 landscape = VecU32_new_reserved(200); + U32 img_width = 0, img_height = 0; + LucyPrepMassTransferImage unprepared_image = LucyGlyphCache_add_glyphs__another_image(cache); + for (size_t j = 0; j < ready.len; j++) { + one_more_chance: + {} + U32 img_slot_id = unprepared_image.img_slot_id; + LucyPositionedStagingGlyph* p_glyph = &ready.buf[j]; + LucyImage* img = &VecOptionLucyImage_mat(&cache->image_slots, img_slot_id)->some; + U64 new_width_required = p_glyph->bitmap.width + starting_x; + if (new_width_required > max_dim) { + /* Resetting row */ + starting_x = 0; + goto one_more_chance; } - LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height); - /* Phase 3. We have all the data. Now what? - * Now we fill staging buffers with glyphs bitsets from `ready` vector */ - for (size_t j = 0; j < ready.len; j++) { - LucyPositionedStagingGlyph* p_glyph = &ready.buf[j]; - LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some; - U64 staging_width = image->tex.img.width; - U8* staging = (U8*)image->staging; + // todo: replace with resize method + // todo: Add expand method to vector + for (U32 h = img_width; h < new_width_required; h++) { + VecU32_append(&landscape, 0); + } + img_width = MAX_U64(img_width, new_width_required); + U32 height_here = 0; + for (size_t x = 0; x < p_glyph->bitmap.width; x++) { + height_here = MAX_U32(height_here, *VecU32_at(&landscape, starting_x + x)); + } + U64 new_height_required = height_here + p_glyph->bitmap.height; + if (new_height_required > max_dim) { + /* Resetting image */ + LucyGlyphCache_add_glyphs__close_img(cache, &mass_transfer, unprepared_image, img_width, img_height); + starting_x = 0; + landscape.len = 0; + img_width = 0; + img_height = 0; + unprepared_image = LucyGlyphCache_add_glyphs__another_image(cache); + goto one_more_chance; + } + /* Success */ + for (size_t x = 0; x < p_glyph->bitmap.width; x++) { + *VecU32_mat(&landscape, starting_x + x) = new_height_required; + } + img_height = MAX_U64(img_height, new_height_required); + + img->usage++; /* p_glyph uses it, that's a rock fact */ + BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &p_glyph->sized_face->glyphs; + U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, p_glyph->codepoint); + assert(map_it > 0 && map_it < glyphs->tree.len); + LucyStoredGlyph* actual_glyph = &glyphs->el.buf[map_it - 1].value; + actual_glyph->pos_on_atlas = (uvec2){starting_x, height_here}; + actual_glyph->img_slot_id = img_slot_id; + + p_glyph->pos = (uvec2){starting_x, height_here}; + + starting_x += p_glyph->bitmap.width; + + /* p_glyph is made empty because we are MOVING it to unprepared_image */ + VecLucyPositionedStagingGlyph_append(&unprepared_image.glyphs_inside, *p_glyph); + /* Can't afford owning one texture in two places */ + p_glyph->bitmap = (TextureDataR8){.width = 0, .height = 0, .pixels = (VecU8){.buf = NULL, .len = 0, .capacity = 0}}; + } + LucyGlyphCache_add_glyphs__close_img(cache, &mass_transfer, unprepared_image, img_width, img_height); + VecLucyPositionedStagingGlyph_drop(ready); + + /* Phase 3. We have all the data. Now what? + * Now we fill staging buffers with glyphs bitsets from `mass_transfer` vector */ + for (size_t ii = 0; ii < mass_transfer.len; ii++) { + LucyPrepMassTransferImage* new_img_rec = &mass_transfer.buf[ii]; + assert(VecOptionLucyImage_mat(&cache->image_slots, new_img_rec->img_slot_id)->variant == Option_Some); + LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, new_img_rec->img_slot_id)->some; + U64 staging_width = image->tex.img.width; + U8* staging = (U8*)new_img_rec->staging; + for (size_t j = 0; j < new_img_rec->glyphs_inside.len; j++) { + LucyPositionedStagingGlyph* p_glyph = &new_img_rec->glyphs_inside.buf[j]; for (U64 y = 0; y < p_glyph->bitmap.height; y++) { U64 Y = y + p_glyph->pos.y; for (U64 x = 0; x < p_glyph->bitmap.width; x++) { @@ -328,7 +372,7 @@ void LucyGlyphCache_add_glyphs(LucyGlyphCache* cache, VecLucyGlyphCachingRequest } } } - VecLucyPositionedStagingGlyph_drop(ready); + VecLucyPrepMassTransferImage_drop(mass_transfer); VecLucyGlyphCachingRequest_drop(requests_for_faces); } diff --git a/src/l3/r4/r4b.c b/src/l3/r4/r4b.c index 02f8ce3..386f031 100644 --- a/src/l3/r4/r4b.c +++ b/src/l3/r4/r4b.c @@ -306,7 +306,7 @@ void main_h_on_another_frame(void* data, float fl){ VecU8 text = VecU8_new(); - VecU8_append_fmt(&text, "Bullet mass = %v ; bullet velocity = %v\n", + VecU8_append_fmt(&text, "Масса пули = %v ; Скорость пули = %v\n", VecU8_format("%.4f", st->bullet_config.mass), VecU8_format("%.4f", st->bullet_config.velocity)); if (st->misses_count == 0 && st->hits_count == 0) { VecU8_append_cstr(&text, "Press BTN_LEFT to shoot\n"); @@ -330,7 +330,8 @@ void run_app(){ Alice* alice = Alice_new(); st.alice = alice; - 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/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(); @@ -338,8 +339,6 @@ void run_app(){ 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); - lucy_requests = VecLucyGlyphCachingRequest_new(); ranges_needed = VecU32Segment_new(); VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x430, .len = 0x44f - 0x430 + 1}); VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){