From 74c2b8007e902923cc89cb1d75b78c4aeb706626 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Sat, 25 Apr 2026 19:23:33 +0300 Subject: [PATCH] Changed API for margaret buf/img allocators. _free() now belongs to individal allocation class. No need to pass allocator pointer to _free, it is retrieved from the allocation block. Added image deletion queue to Abigail. Wrote a little bit of LucyGlyphCache. Mowing towards dynamic glyph loading --- CMakeLists.txt | 24 +++---- src/l1/anne/lucy.h | 13 ++-- src/l1/anne/margaret/margaret_misc.h | 3 + src/l1/anne/util_temp_vulkan.h | 1 + src/l2/alice/abigail.h | 77 +++++++++++++++++++++++ src/l2/alice/engine.h | 59 ++++++++--------- src/l2/alice/transfer_in_mainloop.h | 64 ------------------- src/l2/drawer_2d.h | 5 +- src/l2/lucy/glyph_cache.h | 85 ++++++++++++++++++++----- src/l2/lucy/glyph_render.h | 5 +- src/l2/margaret/vulkan_buffer_claire.h | 78 +++++++++++------------ src/l2/margaret/vulkan_images_claire.h | 34 +++++----- src/l2/margaret/vulkan_utils.h | 87 +++++++++++++++++++------- 13 files changed, 321 insertions(+), 214 deletions(-) create mode 100644 src/l2/alice/abigail.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c6fe60..ed6d525 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,27 +28,27 @@ add_compile_definitions(_POSIX_C_SOURCE=200112L) add_compile_definitions(_GNU_SOURCE) add_compile_options(-fno-trapping-math) -add_executable(codegen_l1 src/l1/anne/codegen.c) -target_compile_definitions(codegen_l1 - PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) +#add_executable(codegen_l1 src/l1/anne/codegen.c) +#target_compile_definitions(codegen_l1 +# PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) #add_executable(0_test src/l1_4/tests/t0.c) #add_executable(1_test src/l1_4/tests/t1.c) -add_executable(3_test src/l1_4/tests/t3.c) -target_link_libraries(3_test -lm) +#add_executable(3_test src/l1_4/tests/t3.c) +#target_link_libraries(3_test -lm) # #add_executable(l1_4_t2 src/l1_4/tests/t2.c) -add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) +#add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) #add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) #target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) # -add_executable(r2a src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c) -target_link_libraries(r2a ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon) +#add_executable(r2a src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c) +#target_link_libraries(r2a ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon) -add_executable(r2c src/l2/tests/r2/r2c.c) -target_link_libraries(r2c -lm) +#add_executable(r2c src/l2/tests/r2/r2c.c) +#target_link_libraries(r2c -lm) # #add_executable(3_render_test src/l2/tests/r3/r3.c gen/l_wl_protocols/xdg-shell-private.c) @@ -62,12 +62,12 @@ target_link_libraries(r2c -lm) #add_executable(l2t0 src/l2/tests/data_structures/t0.c) #add_executable(l2t1 src/l2/tests/data_structures/t1.c) -add_executable(l2_t_parsing src/l2/tests/t_parsing.c) +#add_executable(l2_t_parsing src/l2/tests/t_parsing.c) add_executable(l2_tex_gen src/l2/anne/codegen.c) target_link_libraries(l2_tex_gen -lm -lpng) -add_executable(l3_r4 src/l3/r4/r4.c gen/l_wl_protocols/xdg-shell-private.c) +add_executable(l3_r4 src/l3/r4/r4b.c gen/l_wl_protocols/xdg-shell-private.c) target_link_libraries(l3_r4 -lvulkan -lwayland-client -lm -lxkbcommon -lpng -lfreetype) add_executable(codegen_l1_allie_cpp src/l1/allie_cpp/anne/codegen.cpp) diff --git a/src/l1/anne/lucy.h b/src/l1/anne/lucy.h index 740ae02..55c5a9a 100644 --- a/src/l1/anne/lucy.h +++ b/src/l1/anne/lucy.h @@ -9,13 +9,16 @@ void generate_l1_lucy_headers(){ 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_non_primitive_non_clonable(l, ns, cstr("LucyPrepMassTransferImage"), 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); generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){ .T = cstr("LucyPositionedStagingGlyph"), .vec = true, .sort = true, }, false); + generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyPrepMassTransferImage"), true, false); + + generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyAccumDynTransferImage"), 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); } diff --git a/src/l1/anne/margaret/margaret_misc.h b/src/l1/anne/margaret/margaret_misc.h index 55c0514..05b48ed 100644 --- a/src/l1/anne/margaret/margaret_misc.h +++ b/src/l1/anne/margaret/margaret_misc.h @@ -30,4 +30,7 @@ void generate_margaret_eve_for_vulkan_utils() { /* Used in utilities such as Abigail */ generate_guarded_span_company_for_primitive(l, ns, cstr("MargaretSubbuf"), cstr("#include \"../../../src/l2/margaret/vulkan_utils.h\"\n"), true, false); + /* Used in deletion queues */ + generate_guarded_span_company_for_primitive(l, ns, cstr("MargaretTexture"), + cstr("#include \"../../../src/l2/margaret/vulkan_utils.h\"\n"), true, false); } diff --git a/src/l1/anne/util_temp_vulkan.h b/src/l1/anne/util_temp_vulkan.h index 2a24a4f..260636c 100644 --- a/src/l1/anne/util_temp_vulkan.h +++ b/src/l1/anne/util_temp_vulkan.h @@ -41,4 +41,5 @@ void generate_util_templ_inst_for_vulkan_headers() { generate_guarded_span_company_for_primitive(l, ns, cstr("VkBufferCopy"), vulkan_dep, true, false); generate_guarded_span_company_for_primitive(l, ns, cstr("VkImageMemoryBarrier"), vulkan_dep, true, false); generate_guarded_span_company_for_primitive(l, ns, cstr("VkDescriptorImageInfo"), vulkan_dep, true, false); + generate_guarded_span_company_for_primitive(l, ns, cstr("VkBufferImageCopy"), vulkan_dep, true, true); } diff --git a/src/l2/alice/abigail.h b/src/l2/alice/abigail.h new file mode 100644 index 0000000..6b46bd7 --- /dev/null +++ b/src/l2/alice/abigail.h @@ -0,0 +1,77 @@ +#pragma once + +/* Abigail does not depend on Alice Engine. It only depends on margaret. So systems like Lucy can use it + * without creating any sus circular dependencies. + */ + +#include "../margaret/vulkan_utils.h" +#include "../../../gen/l1/margaret/VecMargaretSubbuf.h" +#include "../../../gen/l1/margaret/VecMargaretTexture.h" + + +typedef struct { + VecMargaretSubbuf to_del_buffers; + VecMargaretTexture to_del_images; +} Abigail; + +Abigail Abigail_new() { + return (Abigail){.to_del_buffers = VecMargaretSubbuf_new(), .to_del_images = VecMargaretTexture_new(), }; +} + +/* 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 isn't 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 + ) { + 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_buffers, staging); + return dev_local; +} + +/* 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 local image 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 + * `format`. 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 + ) { + 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); + *ret_mapped_staging = MargaretSubbuf_get_mapped(&staging); + VecMargaretSubbuf_append(&self->to_del_buffers, 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(Abigail* self) { + for (U64 i = 0; i < self->to_del_buffers.len; i++) { + MargaretSubbuf_free(self->to_del_buffers.buf[i]); + } + self->to_del_buffers.len = 0; + for (U64 i = 0; i < self->to_del_images.len; i++) { + MargaretTexture_free(self->to_del_images.buf[i]); + } + self->to_del_images.len = 0; +} + +void Abigail_drop(Abigail self) { + assert(self.to_del_buffers.len == 0); + VecMargaretSubbuf_drop(self.to_del_buffers); + assert(self.to_del_images.len == 0); + VecMargaretTexture_drop(self.to_del_images); +} diff --git a/src/l2/alice/engine.h b/src/l2/alice/engine.h index b160aa9..f3278d2 100644 --- a/src/l2/alice/engine.h +++ b/src/l2/alice/engine.h @@ -766,7 +766,7 @@ void AliceScene__another_frame(Alice* alice) { 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) { - MargaretBufAllocator_expand_or_free_old(alice->dev_local_buffers, &mm->instance_attr.device_local, + MargaretSubbuf_expand_or_free_old(&mm->instance_attr.device_local, mm->instance_attr.count * sizeof(GenericMeshInstance)); } assert(mm->instance_attr.count * sizeof(GenericMeshInstance) <= mm->instance_attr.device_local.len); @@ -780,7 +780,7 @@ void AliceScene__another_frame(Alice* alice) { 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) { - MargaretBufAllocator_expand_or_free_old(alice->dev_local_buffers, &mm->instance_attr.device_local, + MargaretSubbuf_expand_or_free_old(&mm->instance_attr.device_local, mm->instance_attr.count * sizeof(ShinyMeshInstance)); } assert(mm->instance_attr.count * sizeof(ShinyMeshInstance) <= mm->instance_attr.device_local.len); @@ -806,7 +806,7 @@ void AliceScene__another_frame(Alice* alice) { margaret_rec_cmd_copy_buffer_one_to_one(alice->transfer_command_buf, ubo_staging, ubo); if (point_lights_count * sizeof(Pipeline0PointLight) > point_lights->len) { - MargaretBufAllocator_expand_or_free_old(alice->storage_buffer, point_lights, point_lights_count * sizeof(Pipeline0PointLight)); + MargaretSubbuf_expand_or_free_old(point_lights, point_lights_count * sizeof(Pipeline0PointLight)); } assert(point_lights_count * sizeof(Pipeline0PointLight) <= point_lights->len); if (point_lights_count) { @@ -1062,7 +1062,7 @@ void alice_frame_drawing(Alice* alice) { // todo: WARNING. THIS IS VERY BAD. Please, consider fixing this shitcode if (!alice->transfer_command_buf_already_reset) { - Abigail_wipe_old_staging(&alice->abigail, alice->device, alice->staging_buffers); + Abigail_wipe(&alice->abigail); margaret_reset_and_begin_command_buffer(alice->transfer_command_buf); } else { alice->transfer_command_buf_already_reset = false; @@ -1581,7 +1581,7 @@ Alice* Alice_new(){ alice->device, alice->queue_fam, swapchain_details_res.ok, alice->surface, alice->render_pass_1, NULL); - alice->abigail = (Abigail){ .to_del = VecMargaretSubbuf_new() }; + alice->abigail = Abigail_new(); alice->generic_models = ListAliceGenericMeshHand_new(); alice->shiny_models = ListAliceShinyMeshHand_new(); @@ -1823,30 +1823,27 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo return mm_node; } -// todo: write deletion after I separate textures from Meshes -void Alice_delete_generic_mesh(Alice* alice, ListNodeAliceGenericMeshHand* hand) { - AliceGenericMeshHand* mm = &hand->el; - MargaretBufAllocator_free(alice->dev_local_buffers, mm->vbo); - MargaretBufAllocator_free(alice->dev_local_buffers, mm->ebo); - - 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); -} +// todo: rewrite fucking everything +// void Alice_delete_generic_mesh(Alice* alice, ListNodeAliceGenericMeshHand* hand) { +// AliceGenericMeshHand* mm = &hand->el; +// MargaretBufAllocator_free(alice->dev_local_buffers, mm->vbo); +// MargaretBufAllocator_free(alice->dev_local_buffers, mm->ebo); +// +// MargaretBufAllocator_free(alice->staging_buffers, mm->instance_attr.staging); +// MargaretBufAllocator_free(alice->dev_local_buffers, mm->instance_attr.device_local); +// 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) { - 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); -} +// void Alice_delete_shiny_mesh(Alice* alice, ListNodeAliceShinyMeshHand* 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); +// } void AliceAcknGenericMesh_resize_instance_arr(AliceAcknGenericMesh self, U64 new_count){ @@ -1854,8 +1851,7 @@ void AliceAcknGenericMesh_resize_instance_arr(AliceAcknGenericMesh self, U64 new if (self->el.instance_attr.staging.len < needed_length) { printf("Alice generic model instance staging Buffer: Gotta replace %lu with %lu\n", self->el.instance_attr.staging.len, needed_length); - MargaretBufAllocator_expand_or_move_old_host_visible( - self->el.p->staging_buffers, &self->el.instance_attr.staging, needed_length); + MargaretSubbuf_expand_or_move_old_host_visible(&self->el.instance_attr.staging, needed_length); } self->el.instance_attr.count = new_count; } @@ -1863,8 +1859,7 @@ void AliceAcknGenericMesh_resize_instance_arr(AliceAcknGenericMesh self, U64 new void AliceAcknShinyMesh_resize_instance_arr(AliceAcknShinyMesh self, U64 new_count){ U64 needed_length = new_count * sizeof(ShinyMeshInstance); if (self->el.instance_attr.staging.len < needed_length) { - MargaretBufAllocator_expand_or_move_old_host_visible( - self->el.p->staging_buffers, &self->el.instance_attr.staging, needed_length); + MargaretSubbuf_expand_or_move_old_host_visible(&self->el.instance_attr.staging, needed_length); } self->el.instance_attr.count = new_count; } @@ -1898,7 +1893,7 @@ void Alice_resize_point_light_arr(Alice* alice, U32 new_count){ U64 needed_length = new_count * sizeof(Pipeline0PointLight); MargaretSubbuf* point_lights_staging = &alice->pipeline0_light_conf.point_lights.staging; if (needed_length > alice->pipeline0_light_conf.point_lights.staging.len) { - MargaretBufAllocator_expand_or_move_old_host_visible(alice->staging_buffers, point_lights_staging, needed_length); + MargaretSubbuf_expand_or_move_old_host_visible(point_lights_staging, needed_length); alice_update_pipe0_set0_descr1(alice); } alice->pipeline0_light_conf.point_lights.count = new_count; diff --git a/src/l2/alice/transfer_in_mainloop.h b/src/l2/alice/transfer_in_mainloop.h index ccbb231..24063af 100644 --- a/src/l2/alice/transfer_in_mainloop.h +++ b/src/l2/alice/transfer_in_mainloop.h @@ -1,73 +1,9 @@ #pragma once -/* 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 dependencies. - */ - #include "../margaret/vulkan_utils.h" -#include "../../../gen/l1/margaret/VecMargaretSubbuf.h" typedef struct { U64 count; MargaretSubbuf staging; MargaretSubbuf device_local; } PatriciaBuf; - -typedef struct { - VecMargaretSubbuf to_del; -} Abigail; - -/* 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 isn't 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 - ) { - 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; -} - -/* 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 local image 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 - * `format`. 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 - ) { - 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); - *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); - } - self->to_del.len = 0; -} - -void Abigail_drop(Abigail self) { - assert(self.to_del.len == 0); - VecMargaretSubbuf_drop(self.to_del); -} - diff --git a/src/l2/drawer_2d.h b/src/l2/drawer_2d.h index 9c24ba3..781d844 100644 --- a/src/l2/drawer_2d.h +++ b/src/l2/drawer_2d.h @@ -66,8 +66,7 @@ void Plain2dShapeRenderer_clear(Plain2dShapeRenderer* self) { void Plain2dShapeRenderer_add_triangle(Plain2dShapeRenderer* self, vec4 color, vec2 A, vec2 B, vec2 C) { U64 needed_vbo_length = (self->vertex_count + 3) * sizeof(Plain2dShapeVertex); if (needed_vbo_length > self->staging_vbo.len) { - MargaretBufAllocator_expand_or_move_old_host_visible( - self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length); + MargaretSubbuf_expand_or_move_old_host_visible(&self->staging_vbo, needed_vbo_length); } Plain2dShapeVertex* vbo_data = (Plain2dShapeVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo); vbo_data[self->vertex_count++] = (Plain2dShapeVertex){.pos = A, .color = color}; @@ -79,7 +78,7 @@ void Plain2dShapeRenderer_add_triangle(Plain2dShapeRenderer* self, vec4 color, v void Plain2dShapeRenderer_another_frame(Plain2dShapeRenderer* self){ U64 needed_vbo_length = self->vertex_count * sizeof(Plain2dShapeVertex); if (self->vbo.len < needed_vbo_length) { - MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length); + MargaretSubbuf_expand_or_free_old(&self->vbo, needed_vbo_length); } if ((self->need_to_transfer) && self->vertex_count > 0) { self->need_to_transfer = false; diff --git a/src/l2/lucy/glyph_cache.h b/src/l2/lucy/glyph_cache.h index 95b3829..df75dc9 100644 --- a/src/l2/lucy/glyph_cache.h +++ b/src/l2/lucy/glyph_cache.h @@ -1,7 +1,5 @@ #pragma once -#define DARIA_ROOT "" -#define _DARIA "asdasd" #include "../margaret/vulkan_utils.h" #include "../../../gen/l1/VecAndSpan_U32Segment.h" @@ -10,7 +8,7 @@ #include "../../../gen/l1/VecAndSpan_U32.h" #include "../../l1_5/core/buff_rb_tree_node.h" #include "../../l1_5/core/rb_tree_node.h" -#include "../alice/transfer_in_mainloop.h" +#include "../alice/abigail.h" #include #include FT_FREETYPE_H @@ -65,12 +63,16 @@ struct LucyFace { RBTree_MapU32ToLucyFaceFixedSize sizes; }; -struct { - U64 pos_in_staging; +typedef struct { U32 img_slot_id; - uvec2 pos_in_atlas; - /* The rest is determined on the fly */ -} LucyPositionedDynGlyph; + VecVkBufferImageCopy glyphs; +} LucyAccumDynTransferImage; + +void LucyAccumDynTransferImage_drop(LucyAccumDynTransferImage self) { + VecVkBufferImageCopy_drop(self.glyphs); +} + +#include "../../../gen/l1/eve/lucy/VecLucyAccumDynTransferImage.h" struct LucyGlyphCache { MargaretEngineReference ve; @@ -82,9 +84,14 @@ struct LucyGlyphCache { VkDescriptorSet descriptor_set; MargaretSubbuf dyn_staging; + U32 dyn_stating_usage; U32 dynamic_image_slot; VecU32 dynamic_image_landscape; U32 dynamic_landscape_progress_x; + /* At least one will always be here. + * After being flushed current dynamic image will be added here again and again. + * When we switch active dynamic image slot, we get 2+ elements in `accumulated_dyn_images`. */ + VecLucyAccumDynTransferImage accumulated_dyn_images; }; @@ -112,7 +119,7 @@ void LucyGlyphCache__create_dyn_texture(LucyGlyphCache* cache, U32 new_atlas_dim VkImageView view = margaret_create_view_for_image( cache->ve.device, dev_local.a.image, VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, image_slot_id); - assert(img_slot->variant == Option_None); + assert(img_slot->variant == Option_Some); img_slot->some.usage = 1; img_slot->some.tex = (MargaretTexture){}; @@ -128,10 +135,7 @@ void LucyGlyphCache__create_dyn_texture(LucyGlyphCache* cache, U32 new_atlas_dim } }, 0, NULL); - // for (size_t i = 0; i < cache->dynamic_image_landscape.len; i++) { - // cache->dynamic_image_landscape.buf[i] = 0; - // } - // VecU32_expand(&cache->dynamic_image_landscape, new_atlas_dim, 0); + cache->dynamic_image_slot = image_slot_id; } @@ -172,12 +176,18 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, Abigail* abigail){ .ve = ve, .abigail = abigail, .max_dim = max_dim, .image_slots = image_slots, .descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set, - .dyn_staging = dyn_staging, .dynamic_image_slot = -1, - /* .dynamic_image_landscape = VecU32_new(), */ + .dyn_staging = dyn_staging, .dyn_stating_usage = 0, + .dynamic_image_slot = 67, + /* .dynamic_image_landscape will be initialized later */ .dynamic_landscape_progress_x = 0 }; LucyGlyphCache__create_dyn_texture(&cache, LUCY_INITIAL_DYN_IMAGE_DIM); + cache.accumulated_dyn_images = VecLucyAccumDynTransferImage_new_reserved(1); + VecLucyAccumDynTransferImage_append(&cache.accumulated_dyn_images, (LucyAccumDynTransferImage){ + /* `img_slot_id` is filled previously be LucyGlyphCache__create_dyn_texture */ + .img_slot_id = cache.dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(), + }); cache.dynamic_image_landscape = VecU32_new_zeroinit(LUCY_INITIAL_DYN_IMAGE_DIM); return cache; @@ -218,6 +228,10 @@ void LucyGlyphCache__add_glyph_to_glyph_set(BufRBTree_MapU32ToLucyStoredGlyph* g }); } +U32 LucyGlyphCache__pick_size_next_dyn_img(U32 max_dim, U32 cur_dyn_img_dim) { + return cur_dyn_img_dim * 2 <= max_dim ? cur_dyn_img_dim * 2 : max_dim; +} + /* Returned pointer will be invalidated after you modify the set of codepoints for this size of this face */ LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs_node, U32 codepoint) { LucyFaceFixedSize* ffs = &ffs_node->value; @@ -255,13 +269,50 @@ LucyStoredGlyph* LucyCache_add_glyph_on_the_fly(RBTreeNodeLucyFaceFixedSize* ffs } U32 ceiling = start_y + my_bitmap.height; if (ceiling > cur_dyn_img_dim) { - /* This is serious. We need to swap */ + /* This is serious. We need to issue a new image */ + // todo: decrease usage on the previous dyn_image. If we see that usage is zero, we want to pop the last img + // todo: from accumulated_syn_images and send it to deleter (for images) + // todo: it is the second place where we need a deleter for images. I REALLY REALLY NEED A DELETER, other than Abigail + + U32 new_dyn_img_dim = LucyGlyphCache__pick_size_next_dyn_img(max_dim, cur_dyn_img_dim); + LucyGlyphCache__create_dyn_texture(cache, new_dyn_img_dim); + /* cache->dynamic_img_slot was updated */ + VecLucyAccumDynTransferImage_append(&cache->accumulated_dyn_images, (LucyAccumDynTransferImage){ + .img_slot_id = cache->dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(), + }); + + for (size_t x = 0; x < cur_dyn_img_dim; x++) { + cache->dynamic_image_landscape.buf[x] = 0; + } + VecU32_expand(&cache->dynamic_image_landscape, new_dyn_img_dim, 0); + + cache->dynamic_landscape_progress_x = 0; + goto another_attempt; } // todo: but we forgot to even write LucyAccumDynTransferImage, that would contain LucyPositionedDynGlyph // todo: write swap, that would change the LucyAccumDynTransferImage we are writing to. return NULL; // todo: fix } +/* This function must be called at the end of another_frame callback, after every single operation with glyph cache + * has been done. It will record copy commands for transferring dynamic images. All the accumulated dyn-glyph + * records will be cleared */ +void LucyGlyphCache__flush_dyn_images_transfer(LucyGlyphCache* cache) { + for (size_t ii = 0; ii < cache->accumulated_dyn_images.len; ii++) { + LucyAccumDynTransferImage* img_regions = &cache->accumulated_dyn_images.buf[ii]; + margaret_rec_cmd_copy_buffer_to_image(cache->ve.transfer_cmd_buffer, + &cache->dyn_staging, &cache->image_slots.buf[img_regions->img_slot_id].some.tex.img, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, + VecVkBufferImageCopy_to_span(&img_regions->glyphs)); + } + VecLucyAccumDynTransferImage_sink(&cache->accumulated_dyn_images, 0); + VecLucyAccumDynTransferImage_append(&cache->accumulated_dyn_images, (LucyAccumDynTransferImage){ + .img_slot_id = cache->dynamic_image_slot, .glyphs = VecVkBufferImageCopy_new(), + }); + cache->dyn_stating_usage = 0; +} + void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){ LucyGlyphCache* cache = self->p->p; BufRBTree_MapU32ToLucyStoredGlyph* glyphs = &self->glyphs; @@ -274,7 +325,7 @@ void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){ if (--img->usage == 0) { /* Nothing is written to descriptor set. And luckily, we don't have to */ img_slot->variant = Option_None; - // todo: add image to deletion queue + // todo: add image to deletion queue. I NEED IMAGE DELETER SO SO BADLY. } } BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs); diff --git a/src/l2/lucy/glyph_render.h b/src/l2/lucy/glyph_render.h index b4b11e2..eedb1f8 100644 --- a/src/l2/lucy/glyph_render.h +++ b/src/l2/lucy/glyph_render.h @@ -103,8 +103,7 @@ void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, Luc U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance); if (self->staging_vbo.len < needed_vbo_length) { - MargaretBufAllocator_expand_or_move_old_host_visible( - self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length); + MargaretSubbuf_expand_or_move_old_host_visible(&self->staging_vbo, needed_vbo_length); } LucyRenderInstance* vbo_data = (LucyRenderInstance*)MargaretSubbuf_get_mapped(&self->staging_vbo); @@ -159,7 +158,7 @@ void LucyRenderer_add_simple_label( void LucyRenderer_another_frame(LucyRenderer* self){ U64 needed_vbo_length = self->glyphs_count * sizeof(LucyRenderInstance); if (self->vbo.len < needed_vbo_length) { - MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length); + MargaretSubbuf_expand_or_free_old(&self->vbo, needed_vbo_length); } if ((self->need_to_transfer) && self->glyphs_count > 0) { self->need_to_transfer = false; diff --git a/src/l2/margaret/vulkan_buffer_claire.h b/src/l2/margaret/vulkan_buffer_claire.h index 155b6ad..3147873 100644 --- a/src/l2/margaret/vulkan_buffer_claire.h +++ b/src/l2/margaret/vulkan_buffer_claire.h @@ -190,14 +190,16 @@ U64Segment MargaretBufAllocator__get_right_free_space( return (U64Segment){.start = occ_start + occ_taken_size, .len = allocation->block->capacity - (occ_start + occ_taken_size)}; } - -void MargaretBufAllocator_drop(MargaretBufAllocator self){ - for (ListNodeMargaretBufAllocatorOneBlock* bi = self.blocks.first; bi; bi = bi->next) { - vkDestroyBuffer(self.device, bi->el.buf_hand, NULL); - vkFreeMemory(self.device, bi->el.mem_hand, NULL); +/* MargaretBufAllocator is stored on heap as a pinned structure */ +void MargaretBufAllocator_drop(MargaretBufAllocator* self){ + for (ListNodeMargaretBufAllocatorOneBlock* bi = self->blocks.first; bi; bi = bi->next) { + assert(bi->el.occupants.el.len == 0); + vkDestroyBuffer(self->device, bi->el.buf_hand, NULL); + vkFreeMemory(self->device, bi->el.mem_hand, NULL); } - ListMargaretBufAllocatorOneBlock_drop(self.blocks); - BufRBTreeByLen_SetMargaretBAFreeSegment_drop(self.mem_free_space); + ListMargaretBufAllocatorOneBlock_drop(self->blocks); + BufRBTreeByLen_SetMargaretBAFreeSegment_drop(self->mem_free_space); + free(self); } /* Idk how to hide this monster */ @@ -237,20 +239,20 @@ void MargaretBufAllocator_debug(const MargaretBufAllocator* self){ } /* Free one subbuffer, not a whole MBA :) */ -void MargaretBufAllocator_free(MargaretBufAllocator* self, MargaretSubbuf allocation){ - assert(allocation.block->p == self); // Vibe check - U64Segment left_free_space = MargaretBufAllocator__get_left_free_space(self, &allocation); - U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, &allocation); +void MargaretSubbuf_free(MargaretSubbuf allocation){ + MargaretBufAllocator* allocator = allocation.block->p; + assert(allocation.block->p == allocator); // Vibe check + U64Segment left_free_space = MargaretBufAllocator__get_left_free_space(allocator, &allocation); + U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(allocator, &allocation); - MargaretBufAllocator__erase_gap(self, allocation.block, left_free_space.start, left_free_space.len); - MargaretBufAllocator__erase_gap(self, allocation.block, right_free_space.start, right_free_space.len); - MargaretBufAllocator__insert_gap(self, allocation.block, + MargaretBufAllocator__erase_gap(allocator, allocation.block, left_free_space.start, left_free_space.len); + MargaretBufAllocator__erase_gap(allocator, allocation.block, right_free_space.start, right_free_space.len); + MargaretBufAllocator__insert_gap(allocator, allocation.block, left_free_space.start, right_free_space.start + right_free_space.len - left_free_space.start); bool eret = BufRBTree_MapU64ToU64_erase(&allocation.block->occupants, allocation.start); assert(eret); - // MargaretBufAllocator_debug(self); } NODISCARD MargaretSubbuf MargaretBufAllocator_alloc(MargaretBufAllocator* self, U64 req_size){ @@ -287,14 +289,15 @@ NODISCARD MargaretSubbuf MargaretBufAllocator_alloc(MargaretBufAllocator* self, return (MargaretSubbuf){.block = free_gap.some.block, .start = free_gap.some.start, req_size}; } -void MargaretBufAllocator_shrink(MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 smaller_size){ - smaller_size = margaret_bump_buffer_size_to_alignment(smaller_size, self->alignment_exp); +void MargaretSubbuf_shrink(MargaretSubbuf* allocation, U64 smaller_size){ + MargaretBufAllocator* allocator = allocation->block->p; + smaller_size = margaret_bump_buffer_size_to_alignment(smaller_size, allocator->alignment_exp); assert(smaller_size > 0); assert(smaller_size <= allocation->len); - U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, allocation); - MargaretBufAllocator__erase_gap(self, allocation->block, right_free_space.start, right_free_space.len); - MargaretBufAllocator__insert_gap(self, allocation->block, + U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(allocator, allocation); + MargaretBufAllocator__erase_gap(allocator, allocation->block, right_free_space.start, right_free_space.len); + MargaretBufAllocator__insert_gap(allocator, allocation->block, allocation->start + smaller_size, right_free_space.len + (allocation->len - smaller_size)); @@ -306,18 +309,16 @@ void MargaretBufAllocator_shrink(MargaretBufAllocator* self, MargaretSubbuf* all * But if ret value .len field is non-zero it means a valid MargaretSubbuf object was returned and the * `allocation` argument was untouched. It remains a valid object, you need to deallocate it yourself */ -NODISCARD MargaretSubbuf MargaretBufAllocator_expand( - MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size - ){ - assert(allocation->block->p == self); // Vibe check - bigger_size = margaret_bump_buffer_size_to_alignment(bigger_size, self->alignment_exp); +NODISCARD MargaretSubbuf MargaretSubbuf_expand(MargaretSubbuf* allocation, U64 bigger_size){ + MargaretBufAllocator* allocator = allocation->block->p; + bigger_size = margaret_bump_buffer_size_to_alignment(bigger_size, allocator->alignment_exp); - U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, allocation); + U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(allocator, allocation); if (allocation->start + bigger_size > right_free_space.start + right_free_space.len){ - return MargaretBufAllocator_alloc(self, bigger_size); + return MargaretBufAllocator_alloc(allocator, bigger_size); } - MargaretBufAllocator__erase_gap(self, allocation->block, right_free_space.start, right_free_space.len); - MargaretBufAllocator__insert_gap(self, allocation->block, + MargaretBufAllocator__erase_gap(allocator, allocation->block, right_free_space.start, right_free_space.len); + MargaretBufAllocator__insert_gap(allocator, allocation->block, allocation->start + bigger_size, right_free_space.len + (allocation->len - bigger_size)); @@ -325,7 +326,6 @@ NODISCARD MargaretSubbuf MargaretBufAllocator_expand( U64 my_it = BufRBTree_MapU64ToU64_find(&allocation->block->occupants, allocation->start); assert(my_it > 0 && my_it <= allocation->block->occupants.el.len); allocation->block->occupants.el.buf[my_it - 1].value = bigger_size; - // MargaretBufAllocator_debug(self); return (MargaretSubbuf){0}; } @@ -344,28 +344,24 @@ VkBuffer MargaretSubbuf_get_buffer(const MargaretSubbuf* allocation){ * the data from old buffer to new one and frees the old buffer, while replacing * info in `allocation` variable with info about new allocation. */ -void MargaretBufAllocator_expand_or_move_old_host_visible( - MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size){ - assert(self->host_visible); - MargaretSubbuf maybe_bigger = MargaretBufAllocator_expand(self, allocation, bigger_size); +void MargaretSubbuf_expand_or_move_old_host_visible(MargaretSubbuf* allocation, U64 bigger_size){ + assert(allocation->block->p->host_visible); + MargaretSubbuf maybe_bigger = MargaretSubbuf_expand(allocation, bigger_size); if (maybe_bigger.len > 0) { memcpy(MargaretSubbuf_get_mapped(&maybe_bigger), MargaretSubbuf_get_mapped(allocation), allocation->len); - MargaretBufAllocator_free(self, *allocation); + MargaretSubbuf_free(*allocation); *allocation = maybe_bigger; - // MargaretBufAllocator_debug(self); } - // MargaretBufAllocator_debug(self); } /* It tries to expand buffer, but if it fails, it creates a freshly-new buffer. It * frees the old buffer, while replacing * info in `allocation` variable with info about new allocation. Old data gets lost */ -void MargaretBufAllocator_expand_or_free_old( - MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size){ - MargaretSubbuf maybe_bigger = MargaretBufAllocator_expand(self, allocation, bigger_size); +void MargaretSubbuf_expand_or_free_old(MargaretSubbuf* allocation, U64 bigger_size){ + MargaretSubbuf maybe_bigger = MargaretSubbuf_expand(allocation, bigger_size); if (maybe_bigger.len > 0) { - MargaretBufAllocator_free(self, *allocation); + MargaretSubbuf_free(*allocation); *allocation = maybe_bigger; } } diff --git a/src/l2/margaret/vulkan_images_claire.h b/src/l2/margaret/vulkan_images_claire.h index 875c8d3..5d58455 100644 --- a/src/l2/margaret/vulkan_images_claire.h +++ b/src/l2/margaret/vulkan_images_claire.h @@ -464,25 +464,27 @@ U64Segment MargaretImgAllocator__get_right_free_space( } /* Also frees blocks */ -void MargaretImgAllocator_drop(MargaretImgAllocator self){ - for (ListNodeMargaretImgAllocatorOneBlock* bi = self.blocks.first; bi; bi = bi->next) { - vkFreeMemory(self.device, bi->el.mem_hand, NULL); +void MargaretImgAllocator_drop(MargaretImgAllocator* self){ + for (ListNodeMargaretImgAllocatorOneBlock* bi = self->blocks.first; bi; bi = bi->next) { + assert(bi->el.images.el.len == 0); + vkFreeMemory(self->device, bi->el.mem_hand, NULL); } - ListMargaretImgAllocatorOneBlock_drop(self.blocks); - MargaretMemFreeSpaceManager_drop(self.mem_free_space); + ListMargaretImgAllocatorOneBlock_drop(self->blocks); + MargaretMemFreeSpaceManager_drop(self->mem_free_space); + free(self); } -void MargaretImgAllocator_free(MargaretImgAllocator* self, MargaretImgAllocation allocation){ - assert(allocation.block->p == self); // Vibe check - U64Segment left_free_space = MargaretImgAllocator__get_left_free_space(self, allocation); - U64Segment right_free_space = MargaretImgAllocator__get_right_free_space(self, allocation); +void MargaretImgAllocation__free(MargaretImgAllocation allocation){ + MargaretImgAllocator* allocator = allocation.block->p; + U64Segment left_free_space = MargaretImgAllocator__get_left_free_space(allocator, allocation); + U64Segment right_free_space = MargaretImgAllocator__get_right_free_space(allocator, allocation); - vkDestroyImage(self->device, allocation.image, NULL); + vkDestroyImage(allocator->device, allocation.image, NULL); MargaretImgAllocatorOneBlock* block = allocation.block; - MargaretImgAllocator__erase_gap(self, block, left_free_space.start, left_free_space.len); - MargaretImgAllocator__erase_gap(self, block, right_free_space.start, right_free_space.len); - MargaretImgAllocator__insert_gap(self, block, + MargaretImgAllocator__erase_gap(allocator, block, left_free_space.start, left_free_space.len); + MargaretImgAllocator__erase_gap(allocator, block, right_free_space.start, right_free_space.len); + MargaretImgAllocator__insert_gap(allocator, block, left_free_space.start, right_free_space.start + right_free_space.len - left_free_space.start); @@ -564,6 +566,10 @@ NODISCARD MargaretImg MargaretImgAllocator_alloc( VkImageUsageFlags usage_flags ){ return (MargaretImg){.a = MargaretImgAllocator__alloc(self, width, height, format, usage_flags), - .width = width, .height = height, .format = format, .usage_flags = usage_flags, + .width = width, .height = height, .format = format, .usage_flags = usage_flags, .current_layout = VK_IMAGE_LAYOUT_UNDEFINED}; } + +void MargaretImg_free(MargaretImg img) { + MargaretImgAllocation__free(img.a); +} diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index 7f78428..e27ffb4 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -27,6 +27,7 @@ #include "../../../gen/l1/vulkan/OptionVkSurfaceFormatKHR.h" #include #include "../../../gen/l1/vulkan/VecVkImageMemoryBarrier.h" +#include "../../../gen/l1/vulkan/VecAndSpan_VkBufferImageCopy.h" void margaret_create_debug_utils_messenger_EXT( VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, @@ -1252,13 +1253,9 @@ void margaret_rec_cmd_copy_buffer_one_to_one( .srcOffset = src_allocation->start, .dstOffset = dst_allocation->start, .size = copying_len}); } -/* (destination_stage_mask, destination_access_mask) are probably - * (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT) */ -void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect( - VkCommandBuffer cmd_buf, const MargaretSubbuf* src, MargaretImg* dst, - VkImageLayout dst_new_layout, - VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask){ - +/* helper function, used in procedures that copy something into image */ +void margaret_rec_pipeline_barrier__begin_copy_to_image(VkCommandBuffer cmd_buf, MargaretImg* dst, + VkImageAspectFlags aspect_mask) { vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0 /* Flags */, 0, NULL, 0, NULL, 1, &(VkImageMemoryBarrier){ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, @@ -1270,10 +1267,43 @@ void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect( .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = dst->a.image, .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, + .aspectMask = aspect_mask, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, }, }); +} + +/* helper function, used in procedures that copy something into image */ +void margaret_rec_pipeline_barrier__finish_copy_to_image(VkCommandBuffer cmd_buf, MargaretImg* dst, + VkImageLayout dst_new_layout, + VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask, + VkImageAspectFlags aspect_mask + ) { + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TRANSFER_BIT, destination_stage_mask, + 0 /* Flags */, 0, NULL, 0, NULL, 1, &(VkImageMemoryBarrier){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = destination_access_mask, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = dst_new_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst->a.image, + .subresourceRange = (VkImageSubresourceRange){ + .aspectMask = aspect_mask, .baseMipLevel = 0, + .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, + }, + }); +} + +/* (destination_stage_mask, destination_access_mask) are probably + * (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT) */ +void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect( + VkCommandBuffer cmd_buf, const MargaretSubbuf* src, MargaretImg* dst, + VkImageLayout dst_new_layout, + VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask + ){ + margaret_rec_pipeline_barrier__begin_copy_to_image(cmd_buf, dst, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdCopyBufferToImage(cmd_buf, MargaretSubbuf_get_buffer(src), dst->a.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &(VkBufferImageCopy){ @@ -1287,21 +1317,27 @@ void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect( .imageExtent = { .width = dst->width, .height = dst->height, .depth = 1 }, }); - vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TRANSFER_BIT, destination_stage_mask, - 0 /* Flags */, 0, NULL, 0, NULL, 1, &(VkImageMemoryBarrier){ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = destination_access_mask, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = dst_new_layout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dst->a.image, - .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, - .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, - }, - }); + margaret_rec_pipeline_barrier__finish_copy_to_image(cmd_buf, dst, + dst_new_layout, destination_stage_mask, destination_access_mask, VK_IMAGE_ASPECT_COLOR_BIT); + dst->current_layout = dst_new_layout; +} + +/* (destination_stage_mask, destination_access_mask) are probably + * (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT) + * + * aspect_mask is probably VK_IMAGE_ASPECT_COLOR_BIT. Don't forget that each region also specifies aspect mask */ +void margaret_rec_cmd_copy_buffer_to_image(VkCommandBuffer cmd_buf, const MargaretSubbuf* src, MargaretImg* dst, + VkImageLayout dst_new_layout, + VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask, + VkImageAspectFlags aspect_mask, SpanVkBufferImageCopy regions + ) { + margaret_rec_pipeline_barrier__begin_copy_to_image(cmd_buf, dst, aspect_mask); + + vkCmdCopyBufferToImage(cmd_buf, MargaretSubbuf_get_buffer(src), dst->a.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + regions.len, regions.data); + + margaret_rec_pipeline_barrier__finish_copy_to_image(cmd_buf, dst, + dst_new_layout, destination_stage_mask, destination_access_mask, aspect_mask); dst->current_layout = dst_new_layout; } @@ -1341,3 +1377,8 @@ typedef struct { MargaretImg img; VkImageView view; } MargaretTexture; + +void MargaretTexture_free(MargaretTexture self) { + vkDestroyImageView(self.img.a.block->p->device, self.view, NULL); + MargaretImg_free(self.img); +}