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
This commit is contained in:
parent
5e3aa054d3
commit
74c2b8007e
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
77
src/l2/alice/abigail.h
Normal file
77
src/l2/alice/abigail.h
Normal file
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 <ft2build.h>
|
||||
#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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "../../../gen/l1/vulkan/OptionVkSurfaceFormatKHR.h"
|
||||
#include <vulkan/vulkan_wayland.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user