diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..7f39683 --- /dev/null +++ b/README.txt @@ -0,0 +1,4 @@ +Fonts used: +DM Serif Text made by Colophon Foundry +Roboto made by Christian Robertson, Paratype, Font Bureau +Great Vibes made by Robert Leuschke diff --git a/src/l1/anne/lucy.h b/src/l1/anne/lucy.h index 120fe3d..73334e0 100644 --- a/src/l1/anne/lucy.h +++ b/src/l1/anne/lucy.h @@ -7,14 +7,13 @@ void generate_l1_lucy_headers(){ SpanU8 l = cstr("l1"), ns = cstr("lucy"); mkdir_nofail("l1/eve/lucy"); - generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){ - .T = cstr("LucyImage"), .t_primitive = true}, true); + 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_primitive(l, ns, cstr("KVPU32ToLucyStoredGlyph"), true, false); generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyFaceFixedSize"), true, false); generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyGlyphCachingRequest"), true, true); - /* Vector of iterators */ - generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeLucyImage"), true, false); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ .T = cstr("LucyPositionedStagingGlyph"), .vec = true, .sort = true, diff --git a/src/l1/core/VecU8_as_str.h b/src/l1/core/VecU8_as_str.h index 90ac0ee..2922b50 100644 --- a/src/l1/core/VecU8_as_str.h +++ b/src/l1/core/VecU8_as_str.h @@ -235,7 +235,7 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){ if (rem->len < (size_t)sz) return 0; U32 res = first & (b - 1); - for (int i = 1; i < sz; i++) { + for (int i = 1; i <= sz; i++) { U8 th = rem->data[0]; if ((th & 0b11000000) != 0b10000000) return 0; diff --git a/src/l2/allie/allie.c b/src/l2/allie/allie.c index 7933d8d..9a9c79f 100644 --- a/src/l2/allie/allie.c +++ b/src/l2/allie/allie.c @@ -660,7 +660,6 @@ void Jane_alice_destroy(VkDevice device, Jane_alice jane) { vkDestroyFence(device, jane.roxy, NULL); } -// todo: handle case where presentation and graphics are from the same family typedef struct { VkQueue graphics_queue; VkQueue presentation_queue; @@ -1897,8 +1896,13 @@ Alice* Alice_new(){ alice->device = margaret_create_logical_device(alice->physical_device, alice->queue_fam); - vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue); - vkGetDeviceQueue(alice->device, alice->queue_fam.for_presentation, 0, &alice->queues.presentation_queue); + if (alice->queue_fam.for_graphics == alice->queue_fam.for_presentation) { + vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue); + alice->queues.presentation_queue = alice->queues.graphics_queue; + } else { + vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue); + vkGetDeviceQueue(alice->device, alice->queue_fam.for_presentation, 0, &alice->queues.presentation_queue); + } ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( alice->physical_device, alice->surface, alice->wl.sane_image_extent_limit); diff --git a/src/l2/lucy/glyph_cache.h b/src/l2/lucy/glyph_cache.h index 01f7345..7c8c227 100644 --- a/src/l2/lucy/glyph_cache.h +++ b/src/l2/lucy/glyph_cache.h @@ -7,12 +7,15 @@ #include "../../../gen/l1/VecAndSpan_U32Segment.h" #include "../../../gen/l1/vulkan/VecVkDescriptorImageInfo.h" #include "../../../gen/l1/pixel_masses.h" +#include "../../../gen/l1/VecAndSpan_U32.h" #include "../../l1_5/core/buff_rb_tree_node.h" #include "../../l1_5/core/rb_tree_node.h" #define LUCY_MAX_DESCRIPTOR_COUNT 100 +typedef U32 lucy_image_index_t; + typedef struct { /* This value is actually Option. If staging_buffer is already deleted (after it is no longer used), * staging_buffer.len will be 0 */ @@ -20,18 +23,16 @@ typedef struct { MargaretImg img; VkImageView img_view; U64 usage; - U64 pos_in_desc_array; /* 0 if this image isn't scheduled for deletion on th next cycle. * 1 if it is */ int scheduled_for_deletion; } LucyImage; -#include "../../../gen/l1/eve/lucy/ListLucyImage.h" -typedef ListNodeLucyImage* RefListNodeLucyImage; -#include "../../../gen/l1/eve/lucy/VecRefListNodeLucyImage.h" +#include "../../../gen/l1/eve/lucy/OptionLucyImage.h" +#include "../../../gen/l1/eve/lucy/VecOptionLucyImage.h" typedef struct { - ListNodeLucyImage* img; + U32 img_slot_id; U32 w, h; U32 advance_x; ivec2 bearing; @@ -71,26 +72,28 @@ struct LucyFace { struct LucyGlyphCache { MargaretEngineReference ve; - ListLucyImage images; + VecOptionLucyImage image_slots; VkDescriptorSetLayout descriptor_set_layout; VkDescriptorSet descriptor_set; /* to_be_freed_of_old_staging_next_cycle never intersect with to_be_copied_to_device_next_cycle */ - VecRefListNodeLucyImage to_be_freed_of_old_staging_next_cycle; - VecRefListNodeLucyImage to_be_copied_to_device_next_cycle; + VecU32 to_be_freed_of_old_staging_next_cycle; + VecU32 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; + VecU32 to_be_deleted; }; LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){ VkDescriptorSetLayout my_desc_set_layout; + VkDescriptorSetLayoutBindingFlagsCreateInfo set_layout_crinfo_flags = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + .bindingCount = 1, + .pBindingFlags = (VkDescriptorBindingFlags[]){ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT } + }; check(vkCreateDescriptorSetLayout(ve.device, &(VkDescriptorSetLayoutCreateInfo){ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = &set_layout_crinfo_flags, .bindingCount = 1, .pBindings = (VkDescriptorSetLayoutBinding[]){{ .binding = 0, @@ -101,23 +104,31 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){ }, NULL, &my_desc_set_layout) == VK_SUCCESS); VkDescriptorSet descriptor_set = margaret_allocate_descriptor_set(ve.device, ve.descriptor_pool, my_desc_set_layout); - return (LucyGlyphCache){.ve = ve, .images = ListLucyImage_new(), + VecOptionLucyImage image_slots = VecOptionLucyImage_new_zeroinit(LUCY_MAX_DESCRIPTOR_COUNT); + for (size_t i = 0; i < LUCY_MAX_DESCRIPTOR_COUNT; i++) { + image_slots.buf[i].variant = Option_None; + } + return (LucyGlyphCache){ + .ve = ve, .image_slots = image_slots, .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}; + .to_be_freed_of_old_staging_next_cycle = VecU32_new(), + .to_be_copied_to_device_next_cycle = VecU32_new(), + .to_be_deleted = VecU32_new()}; } void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){ LucyGlyphCache* cache = self->p->p; BufRBTree_MapU32ToLucyStoredGlyph* glyphs = &self->glyphs; for (size_t gid = 0; gid < glyphs->el.len; gid++) { - ListNodeLucyImage* img = glyphs->el.buf[gid].value.img; - assert(img->el.usage > 0); - if (--img->el.usage) { - assert(!img->el.scheduled_for_deletion); - img->el.scheduled_for_deletion = 1; - VecRefListNodeLucyImage_append(&cache->to_be_deleted, img); + 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) { + assert(!img->scheduled_for_deletion); + img->scheduled_for_deletion = 1; + VecU32_append(&cache->to_be_deleted, slot_id); } } BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs); @@ -141,7 +152,7 @@ typedef struct { TextureDataR8 bitmap; /* Will be determined in the next phase */ uvec2 pos; - ListNodeLucyImage* img; + U32 img_slot_id; } LucyPositionedStagingGlyph; bool LucyPositionedStagingGlyph_less_LucyPositionedStagingGlyph( @@ -156,18 +167,37 @@ void LucyPositionedStagingGlyph_drop(LucyPositionedStagingGlyph self){ /* Instantiation for helper type */ #include "../../../gen/l1/eve/lucy/VecLucyPositionedStagingGlyph.h" +/* Helper function */ +U32 LucyGlyphCache_add_glyphs__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) { + slot->variant = Option_Some; + slot->some.scheduled_for_deletion = 0; + slot->some.usage = 0; + return i; + } + } + abortf("LucyCache run out of image descriptor in a descriptor set (dictated by layout).\n" + "You better add up on them\n"); +} + /* Helper function */ void LucyGlyphCache_add_glyphs__close_img( - LucyGlyphCache* cache, ListNodeLucyImage* img, U32 img_width, U32 img_height + LucyGlyphCache* cache, U32 img_slot_id, U32 img_width, U32 img_height ){ - assert(img->el.usage > 0); + OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, img_slot_id); + assert(img_slot->variant == Option_Some); + LucyImage* img = &img_slot->some; + assert(img->usage > 0); + assert(!img->scheduled_for_deletion); img_width = MAX_U32(img_width, 10); // Just a precaution. empty buffers aren't supported by Margaret img_height = MAX_U32(img_height, 10); - VecRefListNodeLucyImage_append(&cache->to_be_copied_to_device_next_cycle, img); - img->el.staging_buffer = MargaretBufAllocator_alloc(cache->ve.staging_buffers, img_width * img_height * 1); - img->el.img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, img_width, img_height, VK_FORMAT_R8_UNORM, + VecU32_append(&cache->to_be_copied_to_device_next_cycle, img_slot_id); + img->staging_buffer = MargaretBufAllocator_alloc(cache->ve.staging_buffers, img_width * img_height * 1); + img->img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, img_width, img_height, VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - img->el.img_view = margaret_create_view_for_image(cache->ve.device, img->el.img.a.image, + img->img_view = margaret_create_view_for_image(cache->ve.device, img->img.a.image, VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); } @@ -235,11 +265,14 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ U32 starting_x = 0; VecU32 landscape = VecU32_new_reserved(200); U32 img_width = 0, img_height = 0; - ListNodeLucyImage* img = ListLucyImage_insert(&cache->images, (LucyImage){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: + {} + int s = 23123; 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 */ @@ -257,12 +290,12 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ 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, img_width, img_height); + 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 = ListLucyImage_insert(&cache->images, (LucyImage){0}); + img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache); goto one_more_chance; } /* Success */ @@ -270,24 +303,25 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ *VecU32_mat(&landscape, starting_x + x) = new_height_required; } img_height = MAX_U64(img_height, new_height_required); - p_glyph->img = img; + p_glyph->img_slot_id = img_slot_id; p_glyph->pos = (uvec2){starting_x, height_here}; - img->el.usage++; /* p_glyph uses it, that's a rock fact */ + 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 = img; + actual_glyph->img_slot_id = img_slot_id; starting_x += p_glyph->bitmap.width; } - LucyGlyphCache_add_glyphs__close_img(cache, img, img_width, img_height); + 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]; - U64 staging_width = p_glyph->img->el.img.width; - U8* staging = (U8*)MargaretSubbuf_get_mapped(&p_glyph->img->el.staging_buffer); + LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some; + U64 staging_width = image->img.width; + U8* staging = (U8*)MargaretSubbuf_get_mapped(&image->staging_buffer); 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++) { @@ -303,69 +337,59 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ /* This must not happen before all the LucyFaceFixedSizes are destroyed */ void LucyGlyphCache_drop(LucyGlyphCache self){ - assert(self.images.first == NULL); - VecRefListNodeLucyImage_drop(self.to_be_freed_of_old_staging_next_cycle); - VecRefListNodeLucyImage_drop(self.to_be_copied_to_device_next_cycle); - VecRefListNodeLucyImage_drop(self.to_be_deleted); + for (size_t i = 0; i < self.image_slots.len; i++) { + assert(self.image_slots.buf[i].variant == Option_None); + } + VecU32_drop(self.to_be_freed_of_old_staging_next_cycle); + VecU32_drop(self.to_be_copied_to_device_next_cycle); + VecU32_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; + U32 slot_id = self->to_be_freed_of_old_staging_next_cycle.buf[i]; + LucyImage* img = &self->image_slots.buf[slot_id].some; assert(img->staging_buffer.len != 0); MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer); img->staging_buffer.len = 0; } for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) { - ListNodeLucyImage* img_node = self->to_be_copied_to_device_next_cycle.buf[i]; - LucyImage* img = &img_node->el; + U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i]; + OptionLucyImage* img_slot = &self->image_slots.buf[slot_id]; + assert(img_slot->variant == Option_Some); + LucyImage* img = &img_slot->some; assert(img->staging_buffer.len != 0); if (img->scheduled_for_deletion) continue; margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(self->ve.transfer_cmd_buffer, &img->staging_buffer, &img->img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT); - VecRefListNodeLucyImage_append(&self->to_be_freed_of_old_staging_next_cycle, img_node); + VecU32_append(&self->to_be_freed_of_old_staging_next_cycle, slot_id); + + vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = slot_id, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &(VkDescriptorImageInfo){ + .sampler = self->ve.nearest_sampler, .imageView = img->img_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + } + }, 0, NULL); } /* We technically could carry out each deletion request in O(1) and each img creation request in O(1), * but who cares, it's no problem going over the entire descriptor set when something get's added or deleted */ for (size_t i = 0; i < self->to_be_deleted.len; i++) { - ListNodeLucyImage* img_node = self->to_be_deleted.buf[i]; - LucyImage* img = &img_node->el; + U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i]; + OptionLucyImage* img_slot = &self->image_slots.buf[slot_id]; + assert(img_slot->variant == Option_Some); + LucyImage* img = &img_slot->some; assert(img->scheduled_for_deletion); assert(img->usage == 0); if (img->staging_buffer.len != 0) MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer); MargaretImgAllocator_free(self->ve.dev_local_images, img->img.a); - ListLucyImage_erase_by_it(&self->images, img_node); - } - if ((self->to_be_copied_to_device_next_cycle.len > 0) || (self->to_be_deleted.len > 0)) { - U32 descriptor_i = 0; - VecVkDescriptorImageInfo desc_elements = VecVkDescriptorImageInfo_new(); - for (ListNodeLucyImage* list_node = self->images.first; list_node; list_node = list_node->next) { - if (descriptor_i == LUCY_MAX_DESCRIPTOR_COUNT) { - abortf("Today you are out of luck\n"); - } - LucyImage* img = &list_node->el; - img->pos_in_desc_array = descriptor_i; - VecVkDescriptorImageInfo_append(&desc_elements, (VkDescriptorImageInfo){ - .sampler = self->ve.nearest_sampler, .imageView = img->img_view, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }); - descriptor_i++; - } - vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){ - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = 0, - .descriptorCount = desc_elements.len, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = desc_elements.buf - }, 0, NULL); - VecVkDescriptorImageInfo_drop(desc_elements); - self->changes_happened = true; + img_slot->variant = Option_None; } self->to_be_freed_of_old_staging_next_cycle.len = 0; self->to_be_copied_to_device_next_cycle.len = 0; diff --git a/src/l2/lucy/glyph_render.h b/src/l2/lucy/glyph_render.h index e8bea21..11d05dc 100644 --- a/src/l2/lucy/glyph_render.h +++ b/src/l2/lucy/glyph_render.h @@ -13,16 +13,6 @@ 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; @@ -38,7 +28,7 @@ typedef struct { VkPipelineLayout pipeline_layout; VkPipeline pipeline; - VecLucyRenderedGlyphRecord rendered_glyphs; + U64 glyphs_count; MargaretSubbuf staging_vbo; MargaretSubbuf vbo; bool need_to_transfer; @@ -86,7 +76,7 @@ LucyRenderer LucyRenderer_new( }); return (LucyRenderer){.ve = ve, .cache = cache, .pipeline_layout = pipeline_layout, .pipeline = pipeline, - .rendered_glyphs = VecLucyRenderedGlyphRecord_new(), .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67), + .glyphs_count = 0, .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67), .vbo = MargaretBufAllocator_alloc(ve.dev_local_buffers, 67) }; } @@ -95,7 +85,7 @@ LucyRenderer LucyRenderer_new( * before LucyRenderer_another_frame */ void LucyRenderer_clear(LucyRenderer* self){ - self->rendered_glyphs.len = 0; + self->glyphs_count = 0; } /* When another_frame starts, you are safe to call this function, but you also have to call it @@ -125,40 +115,25 @@ 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; - } -} + OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id); + assert(img_slot->variant == Option_Some); + LucyImage* img = &img_slot->some; + float atlas_w = (float)img->img.width; + float atlas_h = (float)img->img.height; + U32 desc_elem_id = glyph->img_slot_id; + ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing); -/* 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"); + U64 needed_vbo_length = (self->glyphs_count + 1) * 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); + } + + LucyVertex* vbo_data = (LucyVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo); + vbo_data += self->glyphs_count * 6; - 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; - vec4 color = glyph->color; - ivec2 positioned = glyph->positioned; LucyVertex v0 = { .color = color, .pos = (vec2){(float)positioned.x, (float)positioned.y}, .tex_cord = (vec2){ @@ -187,13 +162,27 @@ void LucyRenderer_another_frame(LucyRenderer* self){ (float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h }, .tex_ind = desc_elem_id }; - 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; + *(vbo_data++) = v1; + *(vbo_data++) = v0; + *(vbo_data++) = v2; + *(vbo_data++) = v1; + *(vbo_data++) = v2; + *(vbo_data++) = v3; + + self->glyphs_count++; } + 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->glyphs_count * 6 * sizeof(LucyVertex); + if (self->vbo.len < needed_vbo_length) { + MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length); + } + if ((self->need_to_transfer) && self->glyphs_count > 0) { + printf("LucyRenderer: we are doing copying\n"); self->need_to_transfer = false; margaret_rec_cmd_copy_buffer_one_to_one_part(self->ve.transfer_cmd_buffer, @@ -212,7 +201,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->rendered_glyphs.len * 6, 1, 0, 0); + vkCmdDraw(drawing_cmd_buf, self->glyphs_count * 6, 1, 0, 0); } #endif \ No newline at end of file diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index d06c2c3..8b5fa05 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -309,20 +309,27 @@ NODISCARD VecU8 margaret_stringify_device_memory_properties_2(VkPhysicalDevice p VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, MargaretChosenQueueFamilies queue_fam) { VkPhysicalDeviceFeatures physical_features; vkGetPhysicalDeviceFeatures(physical_device, &physical_features); - // todo: handle case of `two in one` - float qfam_instance_priorities[1] = {1.f}; - VkDeviceQueueCreateInfo logical_device_queue_crinfo[2] = { 0 }; - for (int i = 0; i < 2; i++) { - logical_device_queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - logical_device_queue_crinfo[i].queueCount = 1; - logical_device_queue_crinfo[i].pQueuePriorities = qfam_instance_priorities; + float qfam_queue_priorities[1] = {1.f}; + VkDeviceQueueCreateInfo queue_crinfo[2] = { 0 }; + int queue_c = 0; + if (queue_fam.for_graphics == queue_fam.for_presentation) { + queue_c = 1; + queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics; + } else { + queue_c = 2; + queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics; + queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation; + } + for (int i = 0; i < queue_c; i++) { + queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_crinfo[i].queueCount = 1; + queue_crinfo[i].pQueuePriorities = qfam_queue_priorities; } - logical_device_queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics; - logical_device_queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation; VkPhysicalDeviceVulkan12Features used_vk12_features = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .runtimeDescriptorArray = true, + .descriptorBindingPartiallyBound = true, .shaderSampledImageArrayNonUniformIndexing = true, }; // We DEMAND synchronization2 @@ -345,8 +352,8 @@ VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, Margar VkDeviceCreateInfo device_crinfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = (const void*)&used_features2, - .queueCreateInfoCount = ARRAY_SIZE(logical_device_queue_crinfo), - .pQueueCreateInfos = logical_device_queue_crinfo, + .queueCreateInfoCount = queue_c, + .pQueueCreateInfos = queue_crinfo, .enabledExtensionCount = ARRAY_SIZE(needed_extensions), .ppEnabledExtensionNames = needed_extensions, // We leave that filed because we have specified features2 in `.pNext` @@ -583,6 +590,8 @@ MargaretScoredPhysicalDevice margaret_score_physical_device( return (MargaretScoredPhysicalDevice){dev, -1, cstr("No shaderSampledImageArrayNonUniformIndexing")}; if (!vk12_features.runtimeDescriptorArray) return (MargaretScoredPhysicalDevice){dev, -1, cstr("No runtimeDescriptorArray")}; + if (!vk12_features.descriptorBindingPartiallyBound) + return (MargaretScoredPhysicalDevice){dev, -1, cstr("No descriptorBindingPartiallyBound")}; ResultMargaretChosenQueueFamiliesOrSpanU8 queue_families = margaret_choose_good_queue_families(dev, surface); if (queue_families.variant == Result_Err) return (MargaretScoredPhysicalDevice){dev, -1, queue_families.err}; diff --git a/src/l3/fonts/GreatVibes-Regular.ttf b/src/l3/fonts/GreatVibes-Regular.ttf new file mode 100644 index 0000000..acc5d37 Binary files /dev/null and b/src/l3/fonts/GreatVibes-Regular.ttf differ diff --git a/src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf b/src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..bba55f6 Binary files /dev/null and b/src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf differ diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index 6835e90..8133923 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -31,11 +31,11 @@ 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}); + // 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(){ @@ -44,9 +44,11 @@ int main(){ st.alice = alice; st.alice->guest = &st; + // st.font_face = LucyFace_new(st.alice->ft_library, &st.alice->lucy_cache, + // VecU8_fmt("%s/src/l3/fonts/DMSerifText-Regular.ttf", cstr("."))); st.font_face = LucyFace_new(st.alice->ft_library, &st.alice->lucy_cache, - VecU8_fmt("%s/src/l3/fonts/DMSerifText-Regular.ttf", cstr("."))); - st.font_face_of_size_40 = LucyFace_of_size(st.font_face, 13); + VecU8_fmt("%s/src/l3/fonts/GreatVibes-Regular.ttf", cstr("."))); + 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}); @@ -62,8 +64,8 @@ int main(){ }); 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}); + LucyRenderer_add_text(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, + cstr("Bebra budet\nотнюхана\n"), (ivec2){10, 10}); 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);