So far nothing broke. Key word so far. Can't wait to run _LucyGlyphCache_get_glyph_on_the_fly and enter infinite loop of sigsegvs
This commit is contained in:
parent
74c2b8007e
commit
76a3469e4e
@ -11,11 +11,11 @@
|
||||
|
||||
typedef struct {
|
||||
VecMargaretSubbuf to_del_buffers;
|
||||
VecMargaretTexture to_del_images;
|
||||
VecMargaretTexture to_del_textures;
|
||||
} Abigail;
|
||||
|
||||
Abigail Abigail_new() {
|
||||
return (Abigail){.to_del_buffers = VecMargaretSubbuf_new(), .to_del_images = VecMargaretTexture_new(), };
|
||||
return (Abigail){.to_del_buffers = VecMargaretSubbuf_new(), .to_del_textures = VecMargaretTexture_new(), };
|
||||
}
|
||||
|
||||
/* You know the deal, the buffer, returned in ret_dev_local_buf, cannot be deleted in the same `_another_frame`
|
||||
@ -63,15 +63,15 @@ void Abigail_wipe(Abigail* self) {
|
||||
MargaretSubbuf_free(self->to_del_buffers.buf[i]);
|
||||
}
|
||||
self->to_del_buffers.len = 0;
|
||||
for (U64 i = 0; i < self->to_del_images.len; i++) {
|
||||
MargaretTexture_free(self->to_del_images.buf[i]);
|
||||
for (U64 i = 0; i < self->to_del_textures.len; i++) {
|
||||
MargaretTexture_free(self->to_del_textures.buf[i]);
|
||||
}
|
||||
self->to_del_images.len = 0;
|
||||
self->to_del_textures.len = 0;
|
||||
}
|
||||
|
||||
void Abigail_drop(Abigail self) {
|
||||
assert(self.to_del_buffers.len == 0);
|
||||
VecMargaretSubbuf_drop(self.to_del_buffers);
|
||||
assert(self.to_del_images.len == 0);
|
||||
VecMargaretTexture_drop(self.to_del_images);
|
||||
assert(self.to_del_textures.len == 0);
|
||||
VecMargaretTexture_drop(self.to_del_textures);
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ struct LucyGlyphCache {
|
||||
VkDescriptorSet descriptor_set;
|
||||
|
||||
MargaretSubbuf dyn_staging;
|
||||
U32 dyn_stating_usage;
|
||||
U32 dyn_staging_usage;
|
||||
U32 dynamic_image_slot;
|
||||
VecU32 dynamic_image_landscape;
|
||||
U32 dynamic_landscape_progress_x;
|
||||
@ -176,7 +176,7 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, Abigail* abigail){
|
||||
.ve = ve, .abigail = abigail, .max_dim = max_dim,
|
||||
.image_slots = image_slots,
|
||||
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set,
|
||||
.dyn_staging = dyn_staging, .dyn_stating_usage = 0,
|
||||
.dyn_staging = dyn_staging, .dyn_staging_usage = 0,
|
||||
.dynamic_image_slot = 67,
|
||||
/* .dynamic_image_landscape will be initialized later */
|
||||
.dynamic_landscape_progress_x = 0
|
||||
@ -193,15 +193,28 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, Abigail* abigail){
|
||||
return cache;
|
||||
}
|
||||
|
||||
void LucyGlyphCache__extract_bitmap(FT_Face ft_face, U32 codepoint, U32 max_dim,
|
||||
TextureDataR8* ret_my_bitmap, FT_GlyphSlot* ret_slot
|
||||
) {
|
||||
/* return true if the image was put in deletion queue (it happens when usage reaches zero) */
|
||||
bool LucyGlyphCache__decrease_image_usage(LucyGlyphCache* cache, U32 slot_id) {
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
if (--img->usage == 0) {
|
||||
printf("Deleting LucyImage %u\n", slot_id);
|
||||
/* Nothing is written to descriptor set. And luckily, we don't have to */
|
||||
img_slot->variant = Option_None;
|
||||
VecMargaretTexture_append(&cache->abigail->to_del_textures, img->tex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Helper for a helper function */
|
||||
FT_GlyphSlot LucyGlyphCache__prepare_slot(FT_Face ft_face, U32 codepoint, U32 max_dim) {
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, (FT_ULong)codepoint);
|
||||
check(FT_Load_Glyph(ft_face, glyph_index, 0) == 0);
|
||||
FT_GlyphSlot slot = ft_face->glyph;
|
||||
*ret_slot = slot;
|
||||
FT_Bitmap* bitmap = &slot->bitmap;
|
||||
*ret_my_bitmap = TextureDataR8_new(bitmap->width, bitmap->rows);
|
||||
check(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (slot->format != FT_GLYPH_FORMAT_BITMAP) {
|
||||
check(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL) == 0);
|
||||
@ -210,6 +223,16 @@ void LucyGlyphCache__extract_bitmap(FT_Face ft_face, U32 codepoint, U32 max_dim,
|
||||
/* 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);
|
||||
return slot;
|
||||
}
|
||||
|
||||
/* Helper function */
|
||||
void LucyGlyphCache__extract_bitmap(FT_Face ft_face, U32 codepoint, U32 max_dim,
|
||||
TextureDataR8* ret_my_bitmap, FT_GlyphSlot* ret_slot
|
||||
) {
|
||||
*ret_slot = LucyGlyphCache__prepare_slot(ft_face, codepoint, max_dim);
|
||||
FT_Bitmap* bitmap = &((*ret_slot)->bitmap);
|
||||
*ret_my_bitmap = TextureDataR8_new(bitmap->width, bitmap->rows);
|
||||
for (S64 y = 0; y < bitmap->rows; y++) {
|
||||
for (S64 x = 0; x < bitmap->width; x++) {
|
||||
*TextureDataR8_mat(ret_my_bitmap, x, y) = *(bitmap->buffer + y * bitmap->pitch + x * sizeof(U8));
|
||||
@ -218,14 +241,20 @@ void LucyGlyphCache__extract_bitmap(FT_Face ft_face, U32 codepoint, U32 max_dim,
|
||||
}
|
||||
|
||||
/* pos on atlas may be left undefined */
|
||||
void LucyGlyphCache__add_glyph_to_glyph_set(BufRBTree_MapU32ToLucyStoredGlyph* glyph_set,
|
||||
LucyStoredGlyph* LucyGlyphCache__add_glyph_to_glyph_set(BufRBTree_MapU32ToLucyStoredGlyph* glyph_set,
|
||||
U32 codepoint, FT_GlyphSlot slot, uvec2 pos_on_atlas) {
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_insert(glyph_set, codepoint, (LucyStoredGlyph){
|
||||
bool iret = BufRBTree_MapU32ToLucyStoredGlyph_insert(glyph_set, codepoint, (LucyStoredGlyph){
|
||||
.w = slot->bitmap.width, .h = slot->bitmap.rows,
|
||||
.advance_x = slot->advance.x >> 6,
|
||||
.bearing = (ivec2){ slot->bitmap_left, -slot->bitmap_top },
|
||||
.pos_on_atlas = pos_on_atlas,
|
||||
});
|
||||
assert(iret);
|
||||
U64 it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyph_set, codepoint);
|
||||
assert(it != 0);
|
||||
const LucyStoredGlyph* stored_glyph;
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_at_iter(glyph_set, it, &codepoint, &stored_glyph);
|
||||
return (LucyStoredGlyph*)stored_glyph;
|
||||
}
|
||||
|
||||
U32 LucyGlyphCache__pick_size_next_dyn_img(U32 max_dim, U32 cur_dyn_img_dim) {
|
||||
@ -233,7 +262,7 @@ U32 LucyGlyphCache__pick_size_next_dyn_img(U32 max_dim, U32 cur_dyn_img_dim) {
|
||||
}
|
||||
|
||||
/* Returned pointer will be invalidated after you modify the set of codepoints for this size of this face */
|
||||
LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs_node, U32 codepoint) {
|
||||
LucyStoredGlyph* LucyGlyphCache_get_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs_node, U32 codepoint) {
|
||||
LucyFaceFixedSize* ffs = &ffs_node->value;
|
||||
BufRBTree_MapU32ToLucyStoredGlyph* glyph_set = &ffs->glyphs;
|
||||
U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyph_set, codepoint);
|
||||
@ -246,10 +275,9 @@ LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs
|
||||
U32 font_height = ffs_node->key;
|
||||
check(FT_Set_Pixel_Sizes(ft_face, 0, font_height) == 0);
|
||||
|
||||
TextureDataR8 my_bitmap;
|
||||
FT_GlyphSlot slot;
|
||||
LucyGlyphCache__extract_bitmap(ft_face, codepoint, cache->max_dim, &my_bitmap, &slot);
|
||||
if (my_bitmap.width > max_dim || my_bitmap.height > max_dim) {
|
||||
FT_GlyphSlot ft_slot = LucyGlyphCache__prepare_slot(ft_face, codepoint, cache->max_dim);
|
||||
FT_Bitmap* bitmap = &ft_slot->bitmap;
|
||||
if (bitmap->width > max_dim || bitmap->rows > max_dim) {
|
||||
abortf("LucyCache_add_glyph_on_the_fly there is no way to fit this monstrosity\n");
|
||||
}
|
||||
another_attempt:
|
||||
@ -258,21 +286,25 @@ LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs
|
||||
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);
|
||||
U32 required_atlas_width = cache->dynamic_landscape_progress_x + my_bitmap.width;
|
||||
U32 required_atlas_width = cache->dynamic_landscape_progress_x + ft_slot->bitmap.width;
|
||||
if (required_atlas_width > cur_dyn_img_dim) {
|
||||
cache->dynamic_landscape_progress_x = 0;
|
||||
goto another_attempt;
|
||||
}
|
||||
U32 start_y = 0;
|
||||
for (size_t gx = 0; gx < my_bitmap.width; gx++) {
|
||||
for (size_t gx = 0; gx < ft_slot->bitmap.width; gx++) {
|
||||
start_y = MAX_U32(start_y, cache->dynamic_image_landscape.buf[gx]);
|
||||
}
|
||||
U32 ceiling = start_y + my_bitmap.height;
|
||||
U32 ceiling = start_y + ft_slot->bitmap.rows;
|
||||
if (ceiling > cur_dyn_img_dim) {
|
||||
/* This is serious. We need to issue a new image */
|
||||
// todo: decrease usage on the previous dyn_image. If we see that usage is zero, we want to pop the last img
|
||||
// todo: from accumulated_syn_images and send it to deleter (for images)
|
||||
// todo: it is the second place where we need a deleter for images. I REALLY REALLY NEED A DELETER, other than Abigail
|
||||
|
||||
// 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);
|
||||
@ -289,9 +321,31 @@ LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs
|
||||
cache->dynamic_landscape_progress_x = 0;
|
||||
goto another_attempt;
|
||||
}
|
||||
// todo: but we forgot to even write LucyAccumDynTransferImage, that would contain LucyPositionedDynGlyph
|
||||
// todo: write swap, that would change the LucyAccumDynTransferImage we are writing to.
|
||||
return NULL; // todo: fix
|
||||
|
||||
VecVkBufferImageCopy_append(&cache->accumulated_dyn_images.buf[cache->accumulated_dyn_images.len - 1].glyphs,
|
||||
(VkBufferImageCopy){ .bufferOffset = cache->dyn_staging_usage,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource = (VkImageSubresourceLayers){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, .baseArrayLayer = 0, .layerCount = 1,
|
||||
},
|
||||
.imageOffset = {(S32)cache->dynamic_landscape_progress_x, (S32)start_y, 0},
|
||||
.imageExtent = { .width = ft_slot->bitmap.width, .height = ft_slot->bitmap.rows, .depth = 1 },
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
LucyStoredGlyph* res = LucyGlyphCache__add_glyph_to_glyph_set(glyph_set, codepoint, ft_slot,
|
||||
(uvec2){cache->dynamic_landscape_progress_x, start_y});
|
||||
return res;
|
||||
}
|
||||
|
||||
/* This function must be called at the end of another_frame callback, after every single operation with glyph cache
|
||||
@ -310,7 +364,7 @@ void LucyGlyphCache__flush_dyn_images_transfer(LucyGlyphCache* cache) {
|
||||
VecLucyAccumDynTransferImage_append(&cache->accumulated_dyn_images, (LucyAccumDynTransferImage){
|
||||
.img_slot_id = cache->dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(),
|
||||
});
|
||||
cache->dyn_stating_usage = 0;
|
||||
cache->dyn_staging_usage = 0;
|
||||
}
|
||||
|
||||
void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
|
||||
@ -318,15 +372,7 @@ void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
|
||||
BufRBTree_MapU32ToLucyStoredGlyph* glyphs = &self->glyphs;
|
||||
for (size_t gid = 0; gid < glyphs->el.len; gid++) {
|
||||
U32 slot_id = glyphs->el.buf[gid].value.img_slot_id;
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
if (--img->usage == 0) {
|
||||
/* Nothing is written to descriptor set. And luckily, we don't have to */
|
||||
img_slot->variant = Option_None;
|
||||
// todo: add image to deletion queue. I NEED IMAGE DELETER SO SO BADLY.
|
||||
}
|
||||
LucyGlyphCache__decrease_image_usage(cache, slot_id);
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs);
|
||||
}
|
||||
|
||||
@ -4,15 +4,6 @@
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "../../../gen/l1/geom.h"
|
||||
|
||||
// todo: rewrite this crrp crap using instances
|
||||
// typedef struct{
|
||||
// vec4 color;
|
||||
// vec2 pos;
|
||||
// vec2 tex_cord;
|
||||
// U32 tex_ind;
|
||||
// } LucyVertex;
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec4 color;
|
||||
vec2 lt_pos;
|
||||
@ -140,15 +131,7 @@ void LucyRenderer_add_simple_label(
|
||||
pos = (ivec2){start_pos.x, pos.y + (S32)font_height + additional_y_advance};
|
||||
continue;
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &ffs->value.glyphs;
|
||||
U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, codepoint);
|
||||
if (map_it == 0) {
|
||||
/* We probably should have requested LucyCache to load more glyphs or draw 'unknown character'
|
||||
* character, but we just skip things. We will force someone else to do that job */
|
||||
continue;
|
||||
}
|
||||
assert(map_it > 0 && map_it < glyphs->tree.len);
|
||||
LucyStoredGlyph* glyph = &glyphs->el.buf[map_it - 1].value;
|
||||
LucyStoredGlyph* glyph = LucyGlyphCache_get_glyph_on_the_fly(ffs, codepoint);
|
||||
LucyRenderer_draw_char_glyph(self, color, pos, glyph);
|
||||
pos.x += (S32)glyph->advance_x;
|
||||
}
|
||||
|
||||
@ -1325,12 +1325,17 @@ void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(
|
||||
/* (destination_stage_mask, destination_access_mask) are probably
|
||||
* (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT)
|
||||
*
|
||||
* aspect_mask is probably VK_IMAGE_ASPECT_COLOR_BIT. Don't forget that each region also specifies aspect mask */
|
||||
* aspect_mask is probably VK_IMAGE_ASPECT_COLOR_BIT. Don't forget that each region also specifies aspect mask
|
||||
*
|
||||
* If `regions` is empty, you are allowed to pass incorrect buffer, incorrect image, incorrect everything
|
||||
*/
|
||||
void margaret_rec_cmd_copy_buffer_to_image(VkCommandBuffer cmd_buf, const MargaretSubbuf* src, MargaretImg* dst,
|
||||
VkImageLayout dst_new_layout,
|
||||
VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask,
|
||||
VkImageAspectFlags aspect_mask, SpanVkBufferImageCopy regions
|
||||
) {
|
||||
if (regions.len == 0)
|
||||
return;
|
||||
margaret_rec_pipeline_barrier__begin_copy_to_image(cmd_buf, dst, aspect_mask);
|
||||
|
||||
vkCmdCopyBufferToImage(cmd_buf, MargaretSubbuf_get_buffer(src), dst->a.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user