Fixed VkDevice initialization mistake. Single queue family case is now handled correctly. Fixed Lucy bug, removed a lot of bloat, now LucyImages are stored in a vector each slot taking one descriptor array element. It should be noted that my previous"lucy fix" from prev commit is a complete crap and got removed. Also I downloaded some cool fonts yay :]

This commit is contained in:
Андреев Григорий 2026-01-01 21:07:55 +03:00
parent 284b0b711b
commit 9a9a5b1b0f
10 changed files with 189 additions and 158 deletions

4
README.txt Normal file
View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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<MargaretSubbuf>. 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;

View File

@ -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

View File

@ -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};

Binary file not shown.

Binary file not shown.

View File

@ -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);