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:
parent
284b0b711b
commit
9a9a5b1b0f
4
README.txt
Normal file
4
README.txt
Normal 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
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
@ -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};
|
||||
|
||||
BIN
src/l3/fonts/GreatVibes-Regular.ttf
Normal file
BIN
src/l3/fonts/GreatVibes-Regular.ttf
Normal file
Binary file not shown.
BIN
src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf
Normal file
BIN
src/l3/fonts/Roboto-VariableFont_wdth,wght.ttf
Normal file
Binary file not shown.
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user