Fixed an obvious bug in LucyCache. Improved code quality in mass transfer of glyphs
This commit is contained in:
parent
0258b946bb
commit
36396a0a7d
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user