diff --git a/src/l1/anne/margaret/margaret_misc.h b/src/l1/anne/margaret/margaret_misc.h index 8103797..0323e51 100644 --- a/src/l1/anne/margaret/margaret_misc.h +++ b/src/l1/anne/margaret/margaret_misc.h @@ -26,4 +26,7 @@ void generate_margaret_eve_for_vulkan_utils() { generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("MargaretImgAllocatorOneBlock"), true, false); generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){.T = cstr("MargaretBufAllocatorOneBlock")}, true); + + generate_guarded_span_company_for_primitive(l, ns, cstr("MargaretSubbuf"), + cstr("#include \"../../../src/l2/margaret/vulkan_utils.h\"\n"), true, false); } diff --git a/src/l1/codegen/list_template_inst.h b/src/l1/codegen/list_template_inst.h index d941d7b..019fd65 100644 --- a/src/l1/codegen/list_template_inst.h +++ b/src/l1/codegen/list_template_inst.h @@ -30,7 +30,7 @@ NODISCARD VecU8 generate_List_template_instantiation(list_instantiation_op op, b "} List%s;\n\n", /* op.T */ op.T, op.T); VecU8_append_fmt(&res, - "#define List%s_new() {0}\n\n" /* op.T */ + "#define List%s_new() ((List%s){0})\n\n" /* op.T, op.T */ "void List%s_drop(List%s self) {\n" /* op.T, op.T */ SPACE "ListNode%s* cur = self.first;\n" /* op.T */ SPACE "while (cur){\n" @@ -40,7 +40,7 @@ NODISCARD VecU8 generate_List_template_instantiation(list_instantiation_op op, b SPACE SPACE "cur = next;\n" SPACE "}\n" "}\n\n", - op.T, op.T, op.T, op.T, op.T, + op.T, op.T, op.T, op.T, op.T, op.T, op.t_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE "%s_drop(cur->el);\n", op.T)); VecU8_append_fmt(&res, "ListNode%s* List%s_insert(List%s* self, %s el) {\n" /* op.T, op.T, op.T, op.T */ diff --git a/src/l2/alice/engine.h b/src/l2/alice/engine.h index 4aea084..06a0d28 100644 --- a/src/l2/alice/engine.h +++ b/src/l2/alice/engine.h @@ -6,12 +6,6 @@ #include "transfer_in_mainloop.h" #include "../lucy/glyph_render.h" -typedef struct { - U64 count; - MargaretSubbuf staging; - MargaretSubbuf device_local; -} PatriciaBuf; - typedef struct { /* Each generic model has its own descriptor set * It's because it has its own textures. But it also has copies of references to light UBO @@ -27,30 +21,25 @@ typedef struct { TextureDataR8G8B8A8 pixels_normal; TextureDataR8 pixels_specular; - AliceBufferUplOnce* vbo; - AliceBufferUplOnce* ebo; + MargaretSubbuf vbo; + MargaretSubbuf ebo; - AliceTextureUplOnce* diffuse_texture; - AliceTextureUplOnce* normal_texture; - AliceTextureUplOnce* specular_texture; + MargaretTexture diffuse_texture; + MargaretTexture normal_texture; + MargaretTexture specular_texture; PatriciaBuf instance_attr; AliceGenericMeshMemDependantVkObj mem_dependant_vk_obj; - - bool scheduled_for_deletion; } AliceGenericMeshHand; #include "../../../gen/l1/eve/alice/ListAliceGenericMeshHand.h" typedef struct { size_t indexes; - - AliceBufferUplOnce* vbo; - AliceBufferUplOnce* ebo; + MargaretSubbuf vbo; + MargaretSubbuf ebo; PatriciaBuf instance_attr; - - bool scheduled_for_deletion; } AliceShinyMeshHand; #include "../../../gen/l1/eve/alice/ListAliceShinyMeshHand.h" @@ -712,34 +701,9 @@ float AliceWaylandApp_get_elapsed_time(const AliceWaylandApp* self){ typedef struct ListNodeAliceGenericMeshHand* RefListNodeAliceGenericMeshHand; #include "../../../gen/l1/eve/alice/VecRefListNodeAliceGenericMeshHand.h" -typedef struct { - ListAliceGenericMeshHand hands; - VecRefListNodeAliceGenericMeshHand to_be_deleted; -} AliceAllMeshesGeneric; - -AliceAllMeshesGeneric AliceAllMeshesGeneric_new(){ - return (AliceAllMeshesGeneric){ - .hands = ListAliceGenericMeshHand_new(), - .to_be_deleted = VecRefListNodeAliceGenericMeshHand_new(), - }; -} - typedef struct ListNodeAliceShinyMeshHand* RefListNodeAliceShinyMeshHand; #include "../../../gen/l1/eve/alice/VecRefListNodeAliceShinyMeshHand.h" -typedef struct { - ListAliceShinyMeshHand hands; - /* Ah */ - VecRefListNodeAliceShinyMeshHand to_be_deleted; -} AliceAllMeshesShiny; - -AliceAllMeshesShiny AliceAllMeshesShiny_new(){ - return (AliceAllMeshesShiny){ - .hands = ListAliceShinyMeshHand_new(), - .to_be_deleted = VecRefListNodeAliceShinyMeshHand_new(), - }; -} - struct Alice { AliceCallbacks callbacks; @@ -780,12 +744,11 @@ struct Alice { Jane_alice jane; // todo: figure out my own design MargaretSwapchainBundle swfb; - AliceAllSingleUploadBuffers single_upload_buffers; - AliceAllSingleUploadTextures single_upload_textures; + Abigail abigail; AlicePipline0LightConf pipeline0_light_conf; - AliceAllMeshesGeneric generic_models; - AliceAllMeshesShiny shiny_models; + ListAliceGenericMeshHand generic_models; + ListAliceShinyMeshHand shiny_models; AliceCamVerticalControl cam_info; /* stuff like background color, hdr factor and * postprocessing kernel. Mostly related to renderpass 1 */ @@ -803,6 +766,13 @@ struct Alice { VkFramebuffer IT1_framebuffer; VkDescriptorSet descriptor_set_for_pipeline_0; VkDescriptorSet descriptor_set_for_pipeline_1; + + /* You see, there are two places when user can write to transfer_command_buffer: When Alice is initialized, but + * the very first frame was not sent in flight, and when we are in a gap between two frames in flight. + * transfer_command_buffer is immediately opened for writing on input, and won't be re-began on the first frame. + * But on the subsequent frames it will be reste and bagan-for-writing after we done waiting for in-flight fence + */ + bool transfer_command_buf_already_reset; }; ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const GenericMeshTopology* topology, @@ -824,36 +794,43 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic VecU8_drop(t_paths.normal_texture_path); VecU8_drop(t_paths.specular_texture_path); - mm->vbo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers, + GenericMeshVertex* staging_vbo; + mm->vbo = Abigail_register_new_buffer(&alice->abigail, topology->vertices.len * sizeof(GenericMeshVertex), - &alice->staging_buffers, &alice->dev_local_buffers); - mm->ebo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers, - topology->indexes.len * sizeof(U32), - &alice->staging_buffers, &alice->dev_local_buffers); + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers, + (void**)&staging_vbo /* We return values here */); - mm->diffuse_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures, + U32* staging_ebo; + mm->ebo = Abigail_register_new_buffer(&alice->abigail, + topology->indexes.len * sizeof(U32), + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers, + (void**)&staging_ebo /* We return values here */); + + void* diffuse_tex_staging; + mm->diffuse_texture = Abigail_register_new_texture(&alice->abigail, mm->pixels_diffuse.width, mm->pixels_diffuse.height, sizeof(cvec4), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - &alice->staging_buffers, &alice->dev_local_images); - mm->normal_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures, + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images, + &diffuse_tex_staging); + void *normal_tex_staging; + mm->normal_texture = Abigail_register_new_texture(&alice->abigail, mm->pixels_normal.width, mm->pixels_normal.height, sizeof(cvec4), VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - &alice->staging_buffers, &alice->dev_local_images); - mm->specular_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures, + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images, + &normal_tex_staging); + void* specular_tex_staging; + mm->specular_texture = Abigail_register_new_texture(&alice->abigail, mm->pixels_specular.width, mm->pixels_specular.height, sizeof(U8), VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - &alice->staging_buffers, &alice->dev_local_images); - - mm->scheduled_for_deletion = false; + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images, + &specular_tex_staging); + assert(mm->vbo.len >= topology->vertices.len * sizeof(GenericMeshVertex)); /* We allocated enough memory, but now it's time to actually fill staging buffers */ /* Filling staging VBO */ - assert(mm->vbo->staging.len >= topology->vertices.len * sizeof(GenericMeshVertex)); - assert(mm->vbo->device_buf.len >= topology->vertices.len * sizeof(GenericMeshVertex)); - GenericMeshVertex* staging_vbo = (GenericMeshVertex*)AliceBufferUplOnce_get_mapped_staging(mm->vbo); for (U64 i = 0; i < topology->vertices.len; i++) { staging_vbo[i].base = topology->vertices.buf[i]; } @@ -883,16 +860,14 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic /* Filling EBO is easy */ assert(topology->indexes.len == mm->indexes); size_t ebo_len = topology->indexes.len * sizeof(U32); - assert(mm->ebo->staging.len >= ebo_len); - U32* staging_ebo = (U32*)AliceBufferUplOnce_get_mapped_staging(mm->ebo); memcpy(staging_ebo, topology->indexes.buf, ebo_len); /* Filling staging textures from memory pixel data */ /* todo: do it immediately ON THE READ */ - memcpy(AliceTextureUplOnce_get_mapped_staging(mm->diffuse_texture), mm->pixels_diffuse.pixels.buf, - TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_diffuse)); - memcpy(AliceTextureUplOnce_get_mapped_staging(mm->normal_texture), mm->pixels_normal.pixels.buf, + memcpy(diffuse_tex_staging, mm->pixels_diffuse.pixels.buf, + TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_diffuse)); + memcpy(normal_tex_staging, mm->pixels_normal.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_normal)); - memcpy(AliceTextureUplOnce_get_mapped_staging(mm->specular_texture), mm->pixels_specular.pixels.buf, + memcpy(specular_tex_staging, mm->pixels_specular.pixels.buf, TextureDataR8_get_size_in_bytes(&mm->pixels_specular)); // todo: that is about time when we can delete mm->pixels_* buffers. They are still wasting space out there // todo: BUt I won't do it, because I chose inplace texture reading (from png) @@ -913,7 +888,7 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(VkDescriptorImageInfo){ - .sampler = alice->linear_sampler, .imageView = mm->diffuse_texture->view, + .sampler = alice->linear_sampler, .imageView = mm->diffuse_texture.view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }, }, @@ -925,7 +900,7 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(VkDescriptorImageInfo){ - .sampler = alice->nearest_sampler, .imageView = mm->normal_texture->view, + .sampler = alice->nearest_sampler, .imageView = mm->normal_texture.view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }, }, @@ -937,14 +912,14 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(VkDescriptorImageInfo){ - .sampler = alice->nearest_sampler, .imageView = mm->specular_texture->view, + .sampler = alice->nearest_sampler, .imageView = mm->specular_texture.view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }, }, }; vkUpdateDescriptorSets(alice->device, ARRAY_SIZE(writes_in_descriptor_set), writes_in_descriptor_set, 0, NULL); - ListAliceGenericMeshHand_insert_node(&alice->generic_models.hands, mm_node); + ListAliceGenericMeshHand_insert_node(&alice->generic_models, mm_node); return mm_node; } @@ -958,18 +933,21 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo mm->instance_attr.staging = MargaretBufAllocator_alloc(&alice->staging_buffers, 128); mm->instance_attr.device_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, 128); - mm->vbo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers, + ShinyMeshVertex* staging_vbo; + mm->vbo = Abigail_register_new_buffer(&alice->abigail, topology->vertices.len * sizeof(ShinyMeshVertex), - &alice->staging_buffers, &alice->dev_local_buffers); - mm->ebo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers, - topology->indexes.len * sizeof(U32), - &alice->staging_buffers, &alice->dev_local_buffers); + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers, + (void**)&staging_vbo); + U32* staging_ebo; + mm->ebo = Abigail_register_new_buffer(&alice->abigail, + topology->indexes.len * sizeof(U32), + alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers, + (void**)&staging_ebo); + + assert(mm->vbo.len >= topology->vertices.len * sizeof(ShinyMeshVertex)); /* We allocated enough memory, now it's time to actually fill staging buffers */ /* And we start by filling staging VBO */ - assert(mm->vbo->staging.len >= topology->vertices.len * sizeof(ShinyMeshVertex)); - assert(mm->vbo->device_buf.len >= topology->vertices.len * sizeof(ShinyMeshVertex)); - ShinyMeshVertex* staging_vbo = (ShinyMeshVertex*)AliceBufferUplOnce_get_mapped_staging(mm->vbo); for (U64 i = 0; i < topology->vertices.len; i++) { staging_vbo[i].base = topology->vertices.buf[i]; } @@ -988,31 +966,38 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo /* Filling staging EBO is super-duper easy */ assert(topology->indexes.len == mm->indexes); size_t ebo_len = topology->indexes.len * sizeof(U32); - assert(mm->ebo->staging.len >= ebo_len); - U32* staging_ebo = (U32*)AliceBufferUplOnce_get_mapped_staging(mm->ebo); memcpy(staging_ebo, topology->indexes.buf, ebo_len); - ListAliceShinyMeshHand_insert_node(&alice->shiny_models.hands, mm_node); + ListAliceShinyMeshHand_insert_node(&alice->shiny_models, mm_node); return mm_node; } - +// todo: write deletion after I separate textures from Meshes void Alice_delete_generic_mesh(Alice* alice, ListNodeAliceGenericMeshHand* hand) { - AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.vbo); - AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.ebo); - AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.diffuse_texture); - AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.normal_texture); - AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.specular_texture); - hand->el.normal_texture = hand->el.normal_texture = hand->el.specular_texture = NULL; - hand->el.vbo = hand->el.ebo = NULL; - VecRefListNodeAliceGenericMeshHand_append(&alice->generic_models.to_be_deleted, hand); + AliceGenericMeshHand* mm = &hand->el; + MargaretBufAllocator_free(&alice->dev_local_buffers, mm->vbo); + MargaretBufAllocator_free(&alice->dev_local_buffers, mm->ebo); + MargaretImgAllocator_free(&alice->dev_local_images, mm->diffuse_texture.img.a); + MargaretImgAllocator_free(&alice->dev_local_images, mm->normal_texture.img.a); + MargaretImgAllocator_free(&alice->dev_local_images, mm->specular_texture.img.a); + + MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging); + MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local); + // todo: the problem is, here we don't free some memory stored in AliceGenericMeshHand to store texture. + // todo: but the truth is: I am gonna get rid of pixels_{,,} fields very soon, so AliceGenericMeshHand would + // todo: be primitive again, without stupid crap + ListAliceGenericMeshHand_erase_by_it(&alice->generic_models, hand); } +/* Be careful to only delete meshes when you actually allowed to do so */ void Alice_delete_shiny_mesh(Alice* alice, ListNodeAliceShinyMeshHand* hand) { - AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.vbo); - AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.ebo); - hand->el.vbo = hand->el.ebo = NULL; - VecRefListNodeAliceShinyMeshHand_append(&alice->shiny_models.to_be_deleted, hand); + AliceShinyMeshHand* mm = &hand->el; + MargaretBufAllocator_free(&alice->dev_local_buffers, hand->el.vbo); + MargaretBufAllocator_free(&alice->dev_local_buffers, hand->el.ebo); + + MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging); + MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local); + ListAliceShinyMeshHand_erase_by_it(&alice->shiny_models, hand); } @@ -1058,37 +1043,6 @@ void AliceShinyMeshHand_set_inst(AliceShinyMeshHand* self, size_t instance, Shin tr_inv.x.z, tr_inv.y.z, tr_inv.z.z ); } -void AliceAllMeshesGeneric__resolve_on_another_frame(Alice* alice, AliceAllMeshesGeneric* self){ - for (size_t i = 0; i < self->to_be_deleted.len; i++) { - ListNodeAliceGenericMeshHand* mm_node = self->to_be_deleted.buf[i]; - AliceGenericMeshHand* mm = &mm_node->el; - assert(mm->scheduled_for_deletion); - assert(mm->vbo == NULL); - assert(mm->ebo == NULL); - MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging); - MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local); - // todo: the problem is, here we don't free some memory stored in AliceGenericMeshHand to store texture. - // todo: but the truth is: I am gonna get rid of pixels_{,,} fields very soon, so AliceGenericMeshHand would - // todo: be primitive again, without stupid crap - ListAliceGenericMeshHand_erase_by_it(&self->hands, mm_node); - } - self->to_be_deleted.len = 0; -} - -void AliceAllMeshesShiny__resolve_on_another_frame(Alice* alice, AliceAllMeshesShiny* self){ - for (size_t i = 0; i < self->to_be_deleted.len; i++) { - ListNodeAliceShinyMeshHand* mm_node = self->to_be_deleted.buf[i]; - AliceShinyMeshHand* mm = &mm_node->el; - assert(mm->scheduled_for_deletion); - assert(mm->vbo == NULL); - assert(mm->ebo == NULL); - MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging); - MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local); - ListAliceShinyMeshHand_erase_by_it(&self->hands, mm_node); - } - self->to_be_deleted.len = 0; -} - /* No buffer rerecording, no buffer beginning, no buffer ending, * 1) It copies initial generic model and shiny model topology. Textures of generic models included * 2) For all models and for all light sources it copies EVERYTHING. @@ -1096,10 +1050,8 @@ void AliceAllMeshesShiny__resolve_on_another_frame(Alice* alice, AliceAllMeshesS * 3) As mentioned before, Pipeline0UBO also gets copied */ void AliceScene__another_frame(Alice* alice) { - AliceAllMeshesGeneric__resolve_on_another_frame(alice, &alice->generic_models); - AliceAllMeshesShiny__resolve_on_another_frame(alice, &alice->shiny_models); - for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.hands.first; mm_node; mm_node = mm_node->next) { + for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.first; mm_node; mm_node = mm_node->next) { AliceGenericMeshHand* mm = &mm_node->el; assert(mm->instance_attr.count * sizeof(GenericMeshInstance) <= mm->instance_attr.staging.len); if (mm->instance_attr.count * sizeof(GenericMeshInstance) > mm->instance_attr.device_local.len) { @@ -1113,7 +1065,7 @@ void AliceScene__another_frame(Alice* alice) { mm->instance_attr.count * sizeof(GenericMeshInstance)); } } - for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.hands.first; mm_node; mm_node = mm_node->next) { + for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.first; mm_node; mm_node = mm_node->next) { AliceShinyMeshHand* mm = &mm_node->el; assert(mm->instance_attr.count * sizeof(ShinyMeshInstance) <= mm->instance_attr.staging.len); if (mm->instance_attr.count * sizeof(ShinyMeshInstance) > mm->instance_attr.device_local.len) { @@ -1187,21 +1139,19 @@ void alice_reset_and_record_command_buffer_0(Alice* alice, mat4 proj_cam_t) { alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0a.pipeline_layout, 0, 1, &alice->descriptor_set_for_pipeline_0, 0, NULL); - for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.hands.first; mm_node; mm_node = mm_node->next) { + for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.first; mm_node; mm_node = mm_node->next) { AliceGenericMeshHand* model = &mm_node->el; VkDescriptorSet descriptor_set1_for_textures = model->mem_dependant_vk_obj.p_0a_set_1; - const MargaretSubbuf* dev_local_vbo = &model->vbo->device_buf; const MargaretSubbuf* dev_local_inst_attr = &model->instance_attr.device_local; - const MargaretSubbuf* dev_local_ebo = &model->ebo->device_buf; - // const + vkCmdBindVertexBuffers(alice->rendering_command_buf_0, 0, 2, (VkBuffer[]){ - MargaretSubbuf_get_buffer(dev_local_vbo), + MargaretSubbuf_get_buffer(&model->vbo), MargaretSubbuf_get_buffer(dev_local_inst_attr), - }, (VkDeviceSize[]){ dev_local_vbo->start, dev_local_inst_attr->start }); - vkCmdBindIndexBuffer(alice->rendering_command_buf_0, MargaretSubbuf_get_buffer(dev_local_ebo), dev_local_ebo->start, - VK_INDEX_TYPE_UINT32); + }, (VkDeviceSize[]){ model->vbo.start, dev_local_inst_attr->start }); + vkCmdBindIndexBuffer(alice->rendering_command_buf_0, + MargaretSubbuf_get_buffer(&model->ebo), model->ebo.start, VK_INDEX_TYPE_UINT32); vkCmdBindDescriptorSets( alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0a.pipeline_layout, 1, 1, &descriptor_set1_for_textures, 0, NULL); @@ -1218,16 +1168,14 @@ void alice_reset_and_record_command_buffer_0(Alice* alice, mat4 proj_cam_t) { alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0b.pipeline_layout, 0, 1, &alice->descriptor_set_for_pipeline_0, 0, NULL); - for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.hands.first; mm_node; mm_node = mm_node->next) { + for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.first; mm_node; mm_node = mm_node->next) { const AliceShinyMeshHand* model = &mm_node->el; - const MargaretSubbuf* dev_local_vbo = &model->vbo->device_buf; const MargaretSubbuf* dev_local_inst_attr = &model->instance_attr.device_local; - const MargaretSubbuf* dev_local_ebo = &model->ebo->device_buf; vkCmdBindVertexBuffers(alice->rendering_command_buf_0, 0, 2, (VkBuffer[]){ - MargaretSubbuf_get_buffer(dev_local_vbo), MargaretSubbuf_get_buffer(dev_local_inst_attr) - }, (VkDeviceSize[]){ dev_local_vbo->start, dev_local_inst_attr->start }); - vkCmdBindIndexBuffer(alice->rendering_command_buf_0, MargaretSubbuf_get_buffer(dev_local_ebo), dev_local_ebo->start, - VK_INDEX_TYPE_UINT32); + MargaretSubbuf_get_buffer(&model->vbo), MargaretSubbuf_get_buffer(dev_local_inst_attr) + }, (VkDeviceSize[]){ model->vbo.start, dev_local_inst_attr->start }); + vkCmdBindIndexBuffer(alice->rendering_command_buf_0, + MargaretSubbuf_get_buffer(&model->ebo), model->ebo.start, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(alice->rendering_command_buf_0, model->indexes, model->instance_attr.count, 0, 0, 0); } @@ -1398,20 +1346,19 @@ void alice_frame_drawing(Alice* alice) { mat4 camera_translation_matrix = marie_translation_mat4(vec3_minus(alice->cam_info.cam.pos)); mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix)); + if (!alice->transfer_command_buf_already_reset) { + Abigail_wipe_old_staging(&alice->abigail, alice->device, &alice->staging_buffers); + margaret_reset_and_begin_command_buffer(alice->transfer_command_buf); + } else { + alice->transfer_command_buf_already_reset = false; + } + alice->callbacks.on_another_frame(alice->guest, (float)(alice->wl.cur_frame_time - alice->wl.last_frame_time) / 1000); - - margaret_reset_and_begin_command_buffer(alice->transfer_command_buf); - - /* Literally everything, including lucy cache, depends on these two steps */ - AliceAllSingleUploadBuffers__resolve_on_another_frame(&alice->single_upload_buffers, - &alice->staging_buffers, &alice->dev_local_buffers, alice->transfer_command_buf); - AliceAllSingleUploadTextures__resolve_on_another_frame(&alice->single_upload_textures, - &alice->staging_buffers, &alice->dev_local_images, alice->transfer_command_buf); - AliceScene__another_frame(alice); - LucyGlyphCache_another_frame(&alice->lucy_cache); + // LucyGlyphCache_another_frame(&alice->lucy_cache); lucy cache has no business here LucyRenderer_another_frame(&alice->lucy_renderer); margaret_end_command_buffer(alice->transfer_command_buf); + alice_reset_and_record_command_buffer_0(alice, t_mat); alice_reset_and_record_command_buffer_1(alice, *VecVkFramebuffer_at(&alice->swfb.framebuffers, ij)); @@ -1906,11 +1853,10 @@ Alice* Alice_new(){ alice->device, alice->queue_fam, swapchain_details_res.ok, alice->surface, alice->render_pass_1, NULL); - alice->single_upload_buffers = AliceAllSingleUploadBuffers_new(); - alice->single_upload_textures = AliceAllSingleUploadTextures_new(); + alice->abigail = (Abigail){ .to_del = VecMargaretSubbuf_new() }; - alice->generic_models = AliceAllMeshesGeneric_new(); - alice->shiny_models = AliceAllMeshesShiny_new(); + alice->generic_models = ListAliceGenericMeshHand_new(); + alice->shiny_models = ListAliceShinyMeshHand_new(); alice->pipeline0_light_conf.num_ubo_staging = MargaretBufAllocator_alloc(&alice->staging_buffers, sizeof(Pipeline0UBO)); alice->pipeline0_light_conf.num_ubo_dev_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, sizeof(Pipeline0UBO)); @@ -1939,7 +1885,7 @@ Alice* Alice_new(){ if (ft_init_err) abortf("Can't init free type library\n"); - alice->lucy_cache = LucyGlyphCache_new(engine_reference, &alice->single_upload_textures); + alice->lucy_cache = LucyGlyphCache_new(engine_reference, &alice->abigail); alice->lucy_renderer = LucyRenderer_new(engine_reference, &alice->lucy_cache, root_dir, alice->render_pass_1, 0); @@ -1947,6 +1893,9 @@ Alice* Alice_new(){ // Creating descriptor set for pipeline 0b and for pipeline 1 (containing IT1 sampler) alice_create_mem_dependant_vk_obj(alice); + alice->transfer_command_buf_already_reset = true; + margaret_reset_and_begin_command_buffer(alice->transfer_command_buf); + alice->wl.prev_key_frame_time = margaret_clock_gettime_monotonic_raw(); alice->wl.frame_count_since_key = 0; /* Alice initialization complete */ diff --git a/src/l2/alice/transfer_in_mainloop.h b/src/l2/alice/transfer_in_mainloop.h index 80fbc29..1b6dc14 100644 --- a/src/l2/alice/transfer_in_mainloop.h +++ b/src/l2/alice/transfer_in_mainloop.h @@ -2,208 +2,72 @@ /* I sometimes call this sub-namespace of Alice namespace Abigail. Though I hadn't renamed it to Abigail yet. * Abigail does not depend on Alice Engine. It only depends on margaret. So systems like Lucy can use it - * without creating any sus circular dependepncies. + * without creating any sus circular dependencies. */ #include "../margaret/vulkan_utils.h" +#include "../../../gen/l1/margaret/VecMargaretSubbuf.h" -/* Handler of a read-only buffer that can be uploaded and deleted at any time with it's staging buffer automatically - * deleted (Similar to what AliceTextureUploadedOnce does to textures) */ typedef struct { + U64 count; MargaretSubbuf staging; - MargaretSubbuf device_buf; - bool scheduled_for_deletion; -} AliceBufferUplOnce; - -typedef AliceBufferUplOnce* RefAliceBufferUplOnce; - -#include "../../../gen/l1/eve/alice/VecRefAliceBufferUplOnce.h" - -/* Handler of a texture that can be uploaded and deleted at any time with it's staging buffer automatically deleted. - * Stores VkImageView as a bonus */ -typedef struct { - MargaretSubbuf staging; - MargaretImg img; - VkImageView view; - bool scheduled_for_deletion; -} AliceTextureUplOnce; - -typedef AliceTextureUplOnce* RefAliceTextureUplOnce; - -#include "../../../gen/l1/eve/alice/VecRefAliceTextureUplOnce.h" + MargaretSubbuf device_local; +} PatriciaBuf; typedef struct { - VecRefAliceBufferUplOnce to_be_freed_of_old_staging_next_cycle; - VecRefAliceBufferUplOnce to_be_copied_to_device_next_cycle; - VecRefAliceBufferUplOnce to_be_deleted; -} AliceAllSingleUploadBuffers; + VecMargaretSubbuf to_del; +} Abigail; -AliceAllSingleUploadBuffers AliceAllSingleUploadBuffers_new() { - return (AliceAllSingleUploadBuffers){ - .to_be_freed_of_old_staging_next_cycle = VecRefAliceBufferUplOnce_new(), - .to_be_copied_to_device_next_cycle = VecRefAliceBufferUplOnce_new(), - .to_be_deleted = VecRefAliceBufferUplOnce_new(), - }; -} - -typedef struct { - VecRefAliceTextureUplOnce to_be_freed_of_old_staging_next_cycle; - VecRefAliceTextureUplOnce to_be_copied_to_device_next_cycle; - VecRefAliceTextureUplOnce to_be_deleted; -} AliceAllSingleUploadTextures; - -AliceAllSingleUploadTextures AliceAllSingleUploadTextures_new(){ - return (AliceAllSingleUploadTextures){ - .to_be_freed_of_old_staging_next_cycle = VecRefAliceTextureUplOnce_new(), - .to_be_copied_to_device_next_cycle = VecRefAliceTextureUplOnce_new(), - .to_be_deleted = VecRefAliceTextureUplOnce_new(), - }; -} - -void AliceAllSingleUploadBuffers__resolve_on_another_frame(AliceAllSingleUploadBuffers* self, - MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers, VkCommandBuffer transfer_cmd_buffer +/* You know the deal, the buffer, returned in ret_dev_local_buf, cannot be deleted in the same `_another_frame` + * callback as this function was called. And it should be obvious that this function can only be called when the + * frame is not in flight. And ret_mapped_staging region is guaranteed to be len bytes long, also, it cannot be + * used when current init/another_frame phase is over + */ +MargaretSubbuf /* ret_dev_local_buf */ Abigail_register_new_buffer(Abigail* self, U64 len, + VkCommandBuffer transfer_cmd_buffer, MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers, + void** ret_mapped_staging ) { - for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) { - AliceBufferUplOnce* mm = self->to_be_freed_of_old_staging_next_cycle.buf[i]; - assert(mm->staging.len != 0); - MargaretBufAllocator_free(staging_buffers, mm->staging); - mm->staging.len = 0; - } - - for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) { - AliceBufferUplOnce* mm = self->to_be_copied_to_device_next_cycle.buf[i]; - assert(mm->staging.len != 0); - if (mm->scheduled_for_deletion) - continue; - margaret_rec_cmd_copy_buffer_one_to_one(transfer_cmd_buffer, &mm->staging, &mm->device_buf); - VecRefAliceBufferUplOnce_append(&self->to_be_freed_of_old_staging_next_cycle, mm); - } - for (size_t i = 0; i < self->to_be_deleted.len; i++) { - AliceBufferUplOnce* mm = self->to_be_deleted.buf[i]; - assert(mm->scheduled_for_deletion); - if (mm->staging.len != 0) - MargaretBufAllocator_free(staging_buffers, mm->staging); - MargaretBufAllocator_free(dev_local_buffers, mm->device_buf); - free(mm); - } - - self->to_be_freed_of_old_staging_next_cycle.len = 0; - self->to_be_copied_to_device_next_cycle.len = 0; - self->to_be_deleted.len = 0; + MargaretSubbuf staging = MargaretBufAllocator_alloc(staging_buffers, len); + MargaretSubbuf dev_local = MargaretBufAllocator_alloc(dev_local_buffers, len); + margaret_rec_cmd_copy_buffer_one_to_one(transfer_cmd_buffer, &staging, &dev_local); + *ret_mapped_staging = MargaretSubbuf_get_mapped(&staging); + VecMargaretSubbuf_append(&self->to_del, staging); + return dev_local; } -void AliceAllSingleUploadTextures__resolve_on_another_frame(AliceAllSingleUploadTextures* self, - MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images, VkCommandBuffer transfer_cmd_buffer +/* Same deal as Abigail_register_new_buffer, but for textures. I say textures, because returned object also includes + * VkImageView, created for this image. + * Returned device localimage cannot be deleted in the same 'no-frame-in-flight' stage. We have to wait for it + * to undergo copying, only then, on another frame, can you delete it. ret_mapped_staging points to staging buffer, + * it is a memory region of width * height * pixed_sz bytes long. Here pixel_sz is a size of pixel in image of format + * `foramt`. This memory can only be edited in the same `on-another-frame` phrase where it was given. But not later + */ +MargaretTexture /* ret_dev_local_texture */ Abigail_register_new_texture(Abigail* self, U64 width, U64 height, U64 pixel_sz, + VkFormat format, VkImageUsageFlags usage, + VkCommandBuffer transfer_cmd_buffer, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images, + void** ret_mapped_staging ) { - for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) { - AliceTextureUplOnce* mm = self->to_be_freed_of_old_staging_next_cycle.buf[i]; - assert(mm->staging.len != 0); - MargaretBufAllocator_free(staging_buffers, mm->staging); - mm->staging.len = 0; - } - - for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) { - AliceTextureUplOnce* mm = self->to_be_copied_to_device_next_cycle.buf[i]; - assert(mm->staging.len != 0); - if (mm->scheduled_for_deletion) - continue; - margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(transfer_cmd_buffer, - &mm->staging, &mm->img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + MargaretSubbuf staging = MargaretBufAllocator_alloc(staging_buffers, width * height * pixel_sz); + MargaretImg dev_local = MargaretImgAllocator_alloc(dev_local_images, width, height, format, usage); + margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(transfer_cmd_buffer, + &staging, &dev_local, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT); - VecRefAliceTextureUplOnce_append(&self->to_be_freed_of_old_staging_next_cycle, mm); + *ret_mapped_staging = MargaretSubbuf_get_mapped(&staging); + VecMargaretSubbuf_append(&self->to_del, staging); + return (MargaretTexture){.img = dev_local, .view = margaret_create_view_for_image( + dev_local_images->device, dev_local.a.image, format, VK_IMAGE_ASPECT_COLOR_BIT)}; +} + +void Abigail_wipe_old_staging(Abigail* self, VkDevice device, MargaretBufAllocator* staging_buffers) { + for (U64 i = 0; i < self->to_del.len; i++) { + MargaretSubbuf staging = self->to_del.buf[i]; + MargaretBufAllocator_free(staging_buffers, staging); } - for (size_t i = 0; i < self->to_be_deleted.len; i++) { - AliceTextureUplOnce* mm = self->to_be_deleted.buf[i]; - assert(mm->scheduled_for_deletion); - if (mm->staging.len != 0) - MargaretBufAllocator_free(staging_buffers, mm->staging); - - MargaretImgAllocator_free(dev_local_images, mm->img.a); - vkDestroyImageView(dev_local_images->device, mm->view, NULL); - free(mm); - } - - self->to_be_freed_of_old_staging_next_cycle.len = 0; - self->to_be_copied_to_device_next_cycle.len = 0; - self->to_be_deleted.len = 0; + self->to_del.len = 0; } - - -/* Doesn't get automatically added to `to_be_copied_to_device_next_cycle` */ -AliceBufferUplOnce* AliceBufferUplOnce_new(size_t len, - MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers - ) { - AliceBufferUplOnce* res = (AliceBufferUplOnce*)safe_malloc(sizeof(AliceBufferUplOnce)); - res->staging = MargaretBufAllocator_alloc(staging_buffers, len); - res->device_buf = MargaretBufAllocator_alloc(dev_local_buffers, len); - res->scheduled_for_deletion = false; - return res; +void Abigail_drop(Abigail self) { + assert(self.to_del.len == 0); + VecMargaretSubbuf_drop(self.to_del); } -void* AliceBufferUplOnce_get_mapped_staging(AliceBufferUplOnce* self) { - return MargaretSubbuf_get_mapped(&self->staging); -} - -void AliceAllSingleUploadBuffers_register(AliceAllSingleUploadBuffers* self, AliceBufferUplOnce* obj) { - assert(obj->staging.len > 0); - assert(!obj->scheduled_for_deletion); - VecRefAliceBufferUplOnce_append(&self->to_be_copied_to_device_next_cycle, obj); -} - -AliceBufferUplOnce* AliceAllSingleUploadBuffers_register_new(AliceAllSingleUploadBuffers* self, size_t len, - MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers - ) { - AliceBufferUplOnce* res = AliceBufferUplOnce_new(len, staging_buffers, dev_local_buffers); - AliceAllSingleUploadBuffers_register(self, res); - return res; -} - -void AliceAllSingleUploadBuffers_delete(AliceAllSingleUploadBuffers* self, AliceBufferUplOnce* obj) { - assert(obj); - obj->scheduled_for_deletion = true; - VecRefAliceBufferUplOnce_append(&self->to_be_deleted, obj); -} - - - -/* Doesn't get automatically added to `to_be_copied_to_device_next_cycle` - * Only works for VK_IMAGE_ASPECT_COLOR_BIT images */ -AliceTextureUplOnce* AliceTextureUplOnce_new(U64 width, U64 height, U64 pixel_sz, VkFormat format, - VkImageUsageFlags usage, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images - ) { - assert(pixel_sz == margaret_singleplane_format_to_sizeof_type(format)); - AliceTextureUplOnce* res = (AliceTextureUplOnce*)safe_malloc(sizeof(AliceTextureUplOnce)); - res->staging = MargaretBufAllocator_alloc(staging_buffers, width * height * pixel_sz); - res->img = MargaretImgAllocator_alloc(dev_local_images, width, height, format, usage); - res->view = margaret_create_view_for_image(dev_local_images->device, res->img.a.image, - format, VK_IMAGE_ASPECT_COLOR_BIT); - res->scheduled_for_deletion = false; - return res; -} - -void* AliceTextureUplOnce_get_mapped_staging(AliceTextureUplOnce* self) { - return MargaretSubbuf_get_mapped(&self->staging); -} - -void AliceAllSingleUploadTextures_register(AliceAllSingleUploadTextures* self, AliceTextureUplOnce* obj) { - assert(obj->staging.len > 0); - assert(!obj->scheduled_for_deletion); - VecRefAliceTextureUplOnce_append(&self->to_be_copied_to_device_next_cycle, obj); -} - -AliceTextureUplOnce* AliceAllSingleUploadTextures_register_new(AliceAllSingleUploadTextures* self, - U64 width, U64 height, U64 pixel_sz, VkFormat format, - VkImageUsageFlags usage, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images - ) { - AliceTextureUplOnce* res = AliceTextureUplOnce_new(width, height, pixel_sz, format, usage, - staging_buffers, dev_local_images); - AliceAllSingleUploadTextures_register(self, res); - return res; -} - -void AliceAllSingleUploadTextures_delete(AliceAllSingleUploadTextures* self, AliceTextureUplOnce* obj) { - assert(obj); - obj->scheduled_for_deletion = true; - VecRefAliceTextureUplOnce_append(&self->to_be_deleted, obj); -} diff --git a/src/l2/lucy/glyph_cache.h b/src/l2/lucy/glyph_cache.h index 9eb1683..135bb96 100644 --- a/src/l2/lucy/glyph_cache.h +++ b/src/l2/lucy/glyph_cache.h @@ -14,10 +14,10 @@ #define LUCY_MAX_DESCRIPTOR_COUNT 100 typedef struct { - AliceTextureUplOnce* tex; + MargaretTexture tex; U64 usage; - /* Is this image scheduled for deletion on th next cycle. */ - bool scheduled_for_deletion; + /* I just could not avoid storing this here. But yeah, after the copying is done, this field stops being used */ + void* staging; } LucyImage; #include "../../../gen/l1/eve/lucy/OptionLucyImage.h" @@ -64,7 +64,7 @@ struct LucyFace { struct LucyGlyphCache { MargaretEngineReference ve; - AliceAllSingleUploadTextures* single_upload_textures; + Abigail* abigail; VecOptionLucyImage image_slots; VkDescriptorSetLayout descriptor_set_layout; @@ -76,7 +76,7 @@ struct LucyGlyphCache { }; -LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, AliceAllSingleUploadTextures* single_upload_textures){ +LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, Abigail* abigail){ VkDescriptorSetLayout my_desc_set_layout; VkDescriptorSetLayoutBindingFlagsCreateInfo set_layout_crinfo_flags = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, @@ -101,7 +101,7 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, AliceAllSingleUplo image_slots.buf[i].variant = Option_None; } return (LucyGlyphCache){ - .ve = ve, .single_upload_textures = single_upload_textures, .image_slots = image_slots, + .ve = ve, .abigail = abigail, .image_slots = image_slots, .descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set, .to_be_written_to_descriptor_set = VecU32_new(), .to_be_deleted = VecU32_new()}; @@ -117,11 +117,8 @@ void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){ LucyImage* img = &img_slot->some; assert(img->usage > 0); if (--img->usage) { - assert(!img->scheduled_for_deletion); - img->scheduled_for_deletion = true; - AliceAllSingleUploadTextures_delete(cache->single_upload_textures, img->tex); - img->tex = NULL; - VecU32_append(&cache->to_be_deleted, slot_id); + /* Nothing is written to descriptor set. And luckily, we don't have to */ + img_slot->variant = Option_None; } } BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs); @@ -166,7 +163,6 @@ U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){ 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; } @@ -183,15 +179,27 @@ void LucyGlyphCache_add_glyphs__close_img( 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); - img->tex = AliceAllSingleUploadTextures_register_new(cache->single_upload_textures, + img->tex = Abigail_register_new_texture(cache->abigail, img_width, img_height, sizeof(U8), VK_FORMAT_R8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - cache->ve.staging_buffers, cache->ve.dev_local_images); - VecU32_append(&cache->to_be_written_to_descriptor_set, img_slot_id); + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, cache->ve.transfer_cmd_buffer, + cache->ve.staging_buffers, cache->ve.dev_local_images, &(img->staging)); + assert(img->staging); + /* We are writing to descriptor set RIGHT NOW. That is why this function, and as such + * LucyGlyphCache_add_glyphs too, must be called when no frame is in flight */ + + vkUpdateDescriptorSets(cache->ve.device, 1, &(VkWriteDescriptorSet){ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = cache->descriptor_set, .dstBinding = 0, .dstArrayElement = img_slot_id, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &(VkDescriptorImageInfo){ + .sampler = cache->ve.nearest_sampler, .imageView = img->tex.view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + } + }, 0, NULL); } void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ @@ -312,8 +320,8 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){ for (size_t j = 0; j < ready.len; j++) { LucyPositionedStagingGlyph* p_glyph = &ready.buf[j]; LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some; - U64 staging_width = image->tex->img.width; - U8* staging = (U8*)AliceTextureUplOnce_get_mapped_staging(image->tex); + U64 staging_width = image->tex.img.width; + U8* staging = (U8*)image->staging; 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++) { @@ -336,42 +344,6 @@ void LucyGlyphCache_drop(LucyGlyphCache self){ VecU32_drop(self.to_be_deleted); } -void LucyGlyphCache_another_frame(LucyGlyphCache* self){ - for (size_t i = 0; i < self->to_be_written_to_descriptor_set.len; i++) { - U32 slot_id = self->to_be_written_to_descriptor_set.buf[i]; - OptionLucyImage* img_slot = &self->image_slots.buf[slot_id]; - assert(img_slot->variant == Option_Some); - LucyImage* img = &img_slot->some; - if (img->scheduled_for_deletion) - continue; - - 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->tex->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++) { - U32 slot_id = self->to_be_deleted.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); - assert(img->tex == NULL); - img_slot->variant = Option_None; - } - self->to_be_written_to_descriptor_set.len = 0; - self->to_be_deleted.len = 0; -} - /* This function does not check font file for correctness, use only with trusted fonts */ LucyFace* LucyFace_new(FT_Library lib, LucyGlyphCache* cache, VecU8 path){ VecU8_append(&path, 0); // Making it null-terminated diff --git a/src/l2/lucy/glyph_render.h b/src/l2/lucy/glyph_render.h index 9911d9d..a54f0f4 100644 --- a/src/l2/lucy/glyph_render.h +++ b/src/l2/lucy/glyph_render.h @@ -97,8 +97,8 @@ void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, Luc 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->tex->img.width; - float atlas_h = (float)img->tex->img.height; + float atlas_w = (float)img->tex.img.width; + float atlas_h = (float)img->tex.img.height; ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing); U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance); diff --git a/src/l2/margaret/vulkan_buffer_claire.h b/src/l2/margaret/vulkan_buffer_claire.h index 4287a98..1e7da56 100644 --- a/src/l2/margaret/vulkan_buffer_claire.h +++ b/src/l2/margaret/vulkan_buffer_claire.h @@ -361,4 +361,4 @@ void MargaretBufAllocator_expand_or_free_old( MargaretBufAllocator_free(self, *allocation); *allocation = maybe_bigger; } -} \ No newline at end of file +} diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index cb1d02e..508ceac 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -1287,3 +1287,8 @@ U64 margaret_singleplane_format_to_sizeof_type(VkFormat type){ abortf("Jokes on you\n"); } } + +typedef struct { + MargaretImg img; + VkImageView view; +} MargaretTexture;