MargaretImgAllocation now stores a direct pointer to MargaretImgAllocatorOneBlock. And both margaretImgAllocator and margaretBufAllocator blocks store pointers to allocators that created them. Memory allocators (buffer, images) are now stored on heap. Now I can do a simplification of allocations management: I don't need to pass allocator to allocation method. Though I hadn't refactored that yet...

This commit is contained in:
Андреев Григорий 2026-02-14 03:00:03 +03:00
parent 248b81f2ec
commit 2367ce1e9d
4 changed files with 123 additions and 102 deletions

View File

@ -24,9 +24,10 @@ void generate_margaret_eve_for_vulkan_utils() {
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
.T = cstr("BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment")});
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("MargaretImgAllocatorOneBlock"), true, false);
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){.T = cstr("MargaretBufAllocatorOneBlock")}, true);
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){.T = cstr("MargaretImgAllocatorOneBlock")}, true);
/* 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);
}

View File

@ -736,10 +736,10 @@ struct Alice {
VkCommandBuffer device_local_mem_mv_command_buf;
VkDescriptorPool descriptor_pool; // todo: write dynamic allocator wrapper for descriptor pools
MargaretImgAllocator dev_local_images;
MargaretBufAllocator dev_local_buffers;
MargaretBufAllocator storage_buffer;
MargaretBufAllocator staging_buffers;
MargaretImgAllocator* dev_local_images;
MargaretBufAllocator* dev_local_buffers;
MargaretBufAllocator* storage_buffer;
MargaretBufAllocator* staging_buffers;
Jane_alice jane; // todo: figure out my own design
MargaretSwapchainBundle swfb;
@ -783,8 +783,8 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
AliceGenericMeshHand* mm = &mm_node->el;
mm->indexes = topology->indexes.len;
mm->instance_attr.count = 0;
mm->instance_attr.staging = MargaretBufAllocator_alloc(&alice->staging_buffers, 200);
mm->instance_attr.device_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, 200);
mm->instance_attr.staging = MargaretBufAllocator_alloc(alice->staging_buffers, 200);
mm->instance_attr.device_local = MargaretBufAllocator_alloc(alice->dev_local_buffers, 200);
// todo: change this, I don't like this at all :(
mm->pixels_diffuse = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&t_paths.diffuse_texture_path));
@ -797,13 +797,13 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
GenericMeshVertex* staging_vbo;
mm->vbo = Abigail_register_new_buffer(&alice->abigail,
topology->vertices.len * sizeof(GenericMeshVertex),
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_buffers,
(void**)&staging_vbo /* We return values here */);
U32* staging_ebo;
mm->ebo = Abigail_register_new_buffer(&alice->abigail,
topology->indexes.len * sizeof(U32),
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_buffers,
(void**)&staging_ebo /* We return values here */);
void* diffuse_tex_staging;
@ -811,21 +811,21 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
mm->pixels_diffuse.width, mm->pixels_diffuse.height,
sizeof(cvec4), VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_images,
&diffuse_tex_staging);
void *normal_tex_staging;
mm->normal_texture = Abigail_register_new_texture(&alice->abigail,
mm->pixels_normal.width, mm->pixels_normal.height,
sizeof(cvec4), VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_images,
&normal_tex_staging);
void* specular_tex_staging;
mm->specular_texture = Abigail_register_new_texture(&alice->abigail,
mm->pixels_specular.width, mm->pixels_specular.height,
sizeof(U8), VK_FORMAT_R8_UNORM,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_images,
&specular_tex_staging);
assert(mm->vbo.len >= topology->vertices.len * sizeof(GenericMeshVertex));
@ -930,19 +930,19 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo
mm->indexes = topology->indexes.len;
mm->instance_attr.count = 0;
mm->instance_attr.staging = MargaretBufAllocator_alloc(&alice->staging_buffers, 128);
mm->instance_attr.device_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, 128);
mm->instance_attr.staging = MargaretBufAllocator_alloc(alice->staging_buffers, 128);
mm->instance_attr.device_local = MargaretBufAllocator_alloc(alice->dev_local_buffers, 128);
ShinyMeshVertex* staging_vbo;
mm->vbo = Abigail_register_new_buffer(&alice->abigail,
topology->vertices.len * sizeof(ShinyMeshVertex),
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_buffers,
(void**)&staging_vbo);
U32* staging_ebo;
mm->ebo = Abigail_register_new_buffer(&alice->abigail,
topology->indexes.len * sizeof(U32),
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
alice->transfer_command_buf, alice->staging_buffers, alice->dev_local_buffers,
(void**)&staging_ebo);
assert(mm->vbo.len >= topology->vertices.len * sizeof(ShinyMeshVertex));
@ -975,14 +975,14 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo
// 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);
MargaretImgAllocator_free(&alice->dev_local_images, mm->diffuse_texture.img.a);
MargaretImgAllocator_free(&alice->dev_local_images, mm->normal_texture.img.a);
MargaretImgAllocator_free(&alice->dev_local_images, mm->specular_texture.img.a);
MargaretBufAllocator_free(alice->dev_local_buffers, mm->vbo);
MargaretBufAllocator_free(alice->dev_local_buffers, mm->ebo);
MargaretImgAllocator_free(alice->dev_local_images, mm->diffuse_texture.img.a);
MargaretImgAllocator_free(alice->dev_local_images, mm->normal_texture.img.a);
MargaretImgAllocator_free(alice->dev_local_images, mm->specular_texture.img.a);
MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging);
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local);
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
@ -992,11 +992,11 @@ void Alice_delete_generic_mesh(Alice* alice, ListNodeAliceGenericMeshHand* 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->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);
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);
}
@ -1007,7 +1007,7 @@ void AliceGenericMeshHand_resize_instance_arr(Alice* alice, AliceGenericMeshHand
printf("Alice generic model instance staging Buffer: Gotta replace %lu with %lu\n",
self->instance_attr.staging.len, needed_length);
MargaretBufAllocator_expand_or_move_old_host_visible(
&alice->staging_buffers, &self->instance_attr.staging, needed_length);
alice->staging_buffers, &self->instance_attr.staging, needed_length);
}
self->instance_attr.count = new_count;
}
@ -1016,7 +1016,7 @@ void AliceShinyMeshHand_resize_instance_arr(Alice* alice, AliceShinyMeshHand* se
U64 needed_length = new_count * sizeof(ShinyMeshInstance);
if (self->instance_attr.staging.len < needed_length) {
MargaretBufAllocator_expand_or_move_old_host_visible(
&alice->staging_buffers, &self->instance_attr.staging, needed_length);
alice->staging_buffers, &self->instance_attr.staging, needed_length);
}
self->instance_attr.count = new_count;
}
@ -1055,7 +1055,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,
MargaretBufAllocator_expand_or_free_old(alice->dev_local_buffers, &mm->instance_attr.device_local,
mm->instance_attr.count * sizeof(GenericMeshInstance));
}
assert(mm->instance_attr.count * sizeof(GenericMeshInstance) <= mm->instance_attr.device_local.len);
@ -1069,7 +1069,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,
MargaretBufAllocator_expand_or_free_old(alice->dev_local_buffers, &mm->instance_attr.device_local,
mm->instance_attr.count * sizeof(ShinyMeshInstance));
}
assert(mm->instance_attr.count * sizeof(ShinyMeshInstance) <= mm->instance_attr.device_local.len);
@ -1095,7 +1095,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));
MargaretBufAllocator_expand_or_free_old(alice->storage_buffer, point_lights, point_lights_count * sizeof(Pipeline0PointLight));
}
assert(point_lights_count * sizeof(Pipeline0PointLight) <= point_lights->len);
if (point_lights_count) {
@ -1347,7 +1347,7 @@ void alice_frame_drawing(Alice* alice) {
mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix));
if (!alice->transfer_command_buf_already_reset) {
Abigail_wipe_old_staging(&alice->abigail, alice->device, &alice->staging_buffers);
Abigail_wipe_old_staging(&alice->abigail, alice->device, alice->staging_buffers);
margaret_reset_and_begin_command_buffer(alice->transfer_command_buf);
} else {
alice->transfer_command_buf_already_reset = false;
@ -1858,26 +1858,26 @@ Alice* Alice_new(){
alice->generic_models = ListAliceGenericMeshHand_new();
alice->shiny_models = ListAliceShinyMeshHand_new();
alice->pipeline0_light_conf.num_ubo_staging = MargaretBufAllocator_alloc(&alice->staging_buffers, sizeof(Pipeline0UBO));
alice->pipeline0_light_conf.num_ubo_dev_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, sizeof(Pipeline0UBO));
alice->pipeline0_light_conf.num_ubo_staging = MargaretBufAllocator_alloc(alice->staging_buffers, sizeof(Pipeline0UBO));
alice->pipeline0_light_conf.num_ubo_dev_local = MargaretBufAllocator_alloc(alice->dev_local_buffers, sizeof(Pipeline0UBO));
Pipeline0UBO* ubo0 = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&alice->pipeline0_light_conf.num_ubo_staging);
ubo0->point_light_count = ubo0->spotlight_count = 0;
alice->pipeline0_light_conf.point_lights.count = 0;
alice->pipeline0_light_conf.point_lights.staging = MargaretBufAllocator_alloc(&alice->staging_buffers, 1000);
alice->pipeline0_light_conf.point_lights.device_local = MargaretBufAllocator_alloc(&alice->storage_buffer, 1000);
alice->pipeline0_light_conf.point_lights.staging = MargaretBufAllocator_alloc(alice->staging_buffers, 1000);
alice->pipeline0_light_conf.point_lights.device_local = MargaretBufAllocator_alloc(alice->storage_buffer, 1000);
alice->cam_info = AliceCamVerticalControl_new();
alice->rendering_config = AliceRenderConfig_new();
alice->IT1_image = MargaretImgAllocator_alloc(&alice->dev_local_images,
alice->IT1_image = MargaretImgAllocator_alloc(alice->dev_local_images,
MAX_WIN_WIDTH, MAX_WIN_HEIGHT, alice->IT1_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
alice->zbuffer_image = MargaretImgAllocator_alloc(&alice->dev_local_images,
alice->zbuffer_image = MargaretImgAllocator_alloc(alice->dev_local_images,
MAX_WIN_WIDTH, MAX_WIN_HEIGHT, alice->zbuffer_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
MargaretEngineReference engine_reference = {
.device = alice->device, .physical_device = alice->physical_device, .transfer_cmd_buffer = alice->transfer_command_buf,
.dev_local_images = &alice->dev_local_images, .dev_local_buffers = &alice->dev_local_buffers,
.staging_buffers = &alice->staging_buffers, .descriptor_pool = alice->descriptor_pool,
.dev_local_images = alice->dev_local_images, .dev_local_buffers = alice->dev_local_buffers,
.staging_buffers = alice->staging_buffers, .descriptor_pool = alice->descriptor_pool,
.linear_sampler = alice->linear_sampler, .nearest_sampler = alice->nearest_sampler
};
@ -1909,7 +1909,7 @@ void Alice_set_point_light_count(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);
MargaretBufAllocator_expand_or_move_old_host_visible(alice->staging_buffers, point_lights_staging, needed_length);
alice_update_pipe0_set0_descr1(alice);
}
alice->pipeline0_light_conf.point_lights.count = new_count;

View File

@ -34,13 +34,16 @@ typedef struct {
U64 len;
} MargaretSubbuf;
struct MargaretBufAllocatorOneBlock{
typedef struct MargaretBufAllocator MargaretBufAllocator;
struct MargaretBufAllocatorOneBlock {
BufRBTree_MapU64ToU64 occupants;
U64 capacity;
U64 occupation_counter;
VkDeviceMemory mem_hand;
VkBuffer buf_hand;
void* mapped_memory;
MargaretBufAllocator* p;
};
void MargaretBufAllocatorOneBlock_drop(MargaretBufAllocatorOneBlock self){
@ -52,7 +55,7 @@ void MargaretBufAllocatorOneBlock_drop(MargaretBufAllocatorOneBlock self){
#include "../../../gen/l1/eve/margaret/VecMargaretBAFreeSegment.h"
#include "../../../gen/l1_5/eve/margaret/BufRBTreeByLen_SetMargaretBAFreeSegment.h"
typedef struct {
struct MargaretBufAllocator {
ListMargaretBufAllocatorOneBlock blocks;
BufRBTreeByLen_SetMargaretBAFreeSegment mem_free_space;
VkDevice device;
@ -62,7 +65,7 @@ typedef struct {
U8 alignment_exp;
bool host_visible;
bool ban_non_envisaged_blocks;
} MargaretBufAllocator;
};
void MargaretBufAllocator__erase_gap(
@ -121,25 +124,26 @@ void MargaretBufAllocator__add_block(MargaretBufAllocator* self, U64 capacity){
.occupants = BufRBTree_MapU64ToU64_new_reserved(1),
.capacity = capacity,
.occupation_counter = capacity,
.mem_hand = memory, .buf_hand = buffer, .mapped_memory = mapped_memory
});
.mem_hand = memory, .buf_hand = buffer, .mapped_memory = mapped_memory,
.p = self });
}
MargaretBufAllocator MargaretBufAllocator_new(
MargaretBufAllocator* MargaretBufAllocator_new(
VkDevice device, VkPhysicalDevice physical_device,
VkBufferUsageFlags usage,
U8 memory_type_id, U8 alignment_exp, bool host_visible,
U64 initial_block_size, bool ban_non_envisaged_blocks
){
MargaretBufAllocator self = {
MargaretBufAllocator* self = (MargaretBufAllocator*)safe_malloc(sizeof(MargaretBufAllocator));
*self = (MargaretBufAllocator){
.blocks = ListMargaretBufAllocatorOneBlock_new(),
.mem_free_space = BufRBTreeByLen_SetMargaretBAFreeSegment_new_reserved(1),
.device = device, .physical_device = physical_device, .usage = usage, .memory_type_id = memory_type_id,
.alignment_exp = alignment_exp, .host_visible = host_visible,
.ban_non_envisaged_blocks = ban_non_envisaged_blocks,
};
MargaretBufAllocator__add_block(&self, initial_block_size);
MargaretBufAllocator__insert_gap(&self, &self.blocks.first->el, 0, initial_block_size);
MargaretBufAllocator__add_block(self, initial_block_size);
MargaretBufAllocator__insert_gap(self, &self->blocks.first->el, 0, initial_block_size);
return self;
}
@ -234,6 +238,7 @@ 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);
@ -302,7 +307,9 @@ void MargaretBufAllocator_shrink(MargaretBufAllocator* self, MargaretSubbuf* all
* `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){
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);
U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, allocation);

View File

@ -176,8 +176,10 @@
#include "../../l1_5/core/buff_rb_tree_node.h"
#include "../../../gen/l1_5/BufRBTree_MapU64ToU64.h"
typedef struct{
U64 block;
typedef struct MargaretImgAllocatorOneBlock MargaretImgAllocatorOneBlock;
typedef struct {
MargaretImgAllocatorOneBlock* block;
U64 start;
U64 len;
} MargaretIAFreeSegment;
@ -199,7 +201,7 @@ bool MargaretIAFreeSegment_less_resp_align(const MargaretIAFreeSegment* A, const
if (A->block == B->block) {
return A->start < B->start;
}
return A->block < B->block;
return (uintptr_t)A->block < (uintptr_t)B->block;
}
return A_len < B_len;
}
@ -208,25 +210,28 @@ bool MargaretIAFreeSegment_less_resp_align(const MargaretIAFreeSegment* A, const
/* Does not include all parameters needed for relocation. Because relocation is needed only
* during controlled defragmentation */
typedef struct {
U64 block;
MargaretImgAllocatorOneBlock* block;
VkImage image;
U64 start;
} MargaretImgAllocation;
typedef struct MargaretImgAllocator MargaretImgAllocator;
/* Not primitive */
typedef struct {
struct MargaretImgAllocatorOneBlock {
BufRBTree_MapU64ToU64 images;
U64 capacity;
U64 occupation_counter;
VkDeviceMemory mem_hand;
void* mapped_memory;
} MargaretImgAllocatorOneBlock;
MargaretImgAllocator* p;
};
void MargaretImgAllocatorOneBlock_drop(MargaretImgAllocatorOneBlock self){
BufRBTree_MapU64ToU64_drop(self.images);
}
#include "../../../gen/l1/eve/margaret/VecMargaretImgAllocatorOneBlock.h"
#include "../../../gen/l1/eve/margaret/ListMargaretImgAllocatorOneBlock.h"
#include "../../../gen/l1/VecAndSpan_U8.h"
#include "../../../gen/l1/eve/margaret/VecMargaretIAFreeSegment.h"
@ -258,7 +263,9 @@ void MargaretMemFreeSpaceManager_drop(MargaretMemFreeSpaceManager self){
VecU8_drop(self.set_present);
}
void MargaretMemFreeSpaceManager_erase(MargaretMemFreeSpaceManager* man, U64 block, U64 start, U64 len){
void MargaretMemFreeSpaceManager_erase(MargaretMemFreeSpaceManager* man,
MargaretImgAllocatorOneBlock* block, U64 start, U64 len
){
if (len == 0)
return;
assert(man->set_present.len > 0);
@ -273,7 +280,9 @@ void MargaretMemFreeSpaceManager_erase(MargaretMemFreeSpaceManager* man, U64 blo
}
}
void MargaretMemFreeSpaceManager_insert(MargaretMemFreeSpaceManager* man, U64 block, U64 start, U64 len){
void MargaretMemFreeSpaceManager_insert(MargaretMemFreeSpaceManager* man,
MargaretImgAllocatorOneBlock* block, U64 start, U64 len
){
if (len == 0)
return;
assert(man->set_present.len > 0); /* MargaretMemFreeSpaceManager will do that for us with 2^3 */
@ -313,26 +322,28 @@ OptionMargaretIAFreeSegment MargaretMemFreeSpaceManager_search(
}
/* VkDevice and VkPhysicalDevice stay remembered here. Don't forget that, please */
typedef struct {
VecMargaretImgAllocatorOneBlock blocks;
struct MargaretImgAllocator {
ListMargaretImgAllocatorOneBlock blocks;
MargaretMemFreeSpaceManager mem_free_space;
VkDevice device;
VkPhysicalDevice physical_device;
U8 memory_type_id;
} MargaretImgAllocator;
};
void MargaretImgAllocator__erase_gap(MargaretImgAllocator* self, U64 block_id, U64 start, U64 len){
MargaretMemFreeSpaceManager_erase(&self->mem_free_space, block_id, start, len);
MargaretImgAllocatorOneBlock* BLOCK = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, block_id);
BLOCK->occupation_counter += len;
assert(BLOCK->occupation_counter <= BLOCK->capacity);
void MargaretImgAllocator__erase_gap(MargaretImgAllocator* self,
MargaretImgAllocatorOneBlock* block, U64 start, U64 len
){
MargaretMemFreeSpaceManager_erase(&self->mem_free_space, block, start, len);
block->occupation_counter += len;
assert(block->occupation_counter <= block->capacity);
}
void MargaretImgAllocator__insert_gap(MargaretImgAllocator* self, U64 block_id, U64 start, U64 len){
MargaretMemFreeSpaceManager_insert(&self->mem_free_space, block_id, start, len);
MargaretImgAllocatorOneBlock* BLOCK = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, block_id);
assert(len <= BLOCK->occupation_counter);
BLOCK->occupation_counter -= len;
void MargaretImgAllocator__insert_gap(MargaretImgAllocator* self,
MargaretImgAllocatorOneBlock* block, U64 start, U64 len
){
MargaretMemFreeSpaceManager_insert(&self->mem_free_space, block, start, len);
assert(len <= block->occupation_counter);
block->occupation_counter -= len;
}
void MargaretImgAllocator__add_block(MargaretImgAllocator* self, U64 capacity){
@ -342,20 +353,20 @@ void MargaretImgAllocator__add_block(MargaretImgAllocator* self, U64 capacity){
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = capacity, .memoryTypeIndex = self->memory_type_id
}, NULL, &memory) == VK_SUCCESS);
VecMargaretImgAllocatorOneBlock_append(&self->blocks, (MargaretImgAllocatorOneBlock){
ListMargaretImgAllocatorOneBlock_insert(&self->blocks, (MargaretImgAllocatorOneBlock){
.images = BufRBTree_MapU64ToU64_new_reserved(1),
.capacity = capacity,
.occupation_counter = capacity, // sounds sus
.mem_hand = memory,
.mapped_memory = NULL /* not supported */});
.mapped_memory = NULL /* not supported */, .p = self });
}
/* Idk where to put it */
void MargaretImgAllocator__debug(const MargaretImgAllocator* self){
printf("=============================== MargaretImgAllocator ============\n"
"All blocks: { ");
for (size_t i = 0; i < self->blocks.len; i++) {
printf(" %lu/%lu ", self->blocks.buf[i].occupation_counter, self->blocks.buf[i].capacity);
for (ListNodeMargaretImgAllocatorOneBlock* i = 0; i; i = i->next) {
printf(" %lu/%lu ", i->el.occupation_counter, i->el.capacity);
}
printf("}\n");
for (size_t ai = 0; ai < self->mem_free_space.set_present.len; ai++) {
@ -367,24 +378,25 @@ void MargaretImgAllocator__debug(const MargaretImgAllocator* self){
assert(set->guest == alignment_exp);
for (size_t i = 0; i < set->el.len; i++) {
const MargaretIAFreeSegment *free_seg = &set->el.buf[i];
printf(" Block %lu, start %lu, len %lu\n", free_seg->block, free_seg->start, free_seg->len);
printf(" Block %p, start %lu, len %lu\n", (void*)free_seg->block, free_seg->start, free_seg->len);
}
}
}
MargaretImgAllocator MargaretImgAllocator_new(
MargaretImgAllocator* MargaretImgAllocator_new(
VkDevice device, VkPhysicalDevice physical_device, U8 memory_type_id, U64 initial_block_size
){
MargaretImgAllocator self = {
.blocks = VecMargaretImgAllocatorOneBlock_new(),
MargaretImgAllocator* self = (MargaretImgAllocator*)safe_malloc(sizeof(MargaretImgAllocator));
*self = (MargaretImgAllocator){
.blocks = ListMargaretImgAllocatorOneBlock_new(),
.mem_free_space = MargaretMemFreeSpaceManager_new(),
.device = device,
.physical_device = physical_device,
.memory_type_id = memory_type_id,
};
MargaretImgAllocator__add_block(&self, initial_block_size);
MargaretImgAllocator__insert_gap(&self, 0, 0, initial_block_size);
// MargaretImgAllocator__debug(&self);
MargaretImgAllocator__add_block(self, initial_block_size);
assert(self->blocks.first != NULL);
MargaretImgAllocator__insert_gap(self, &self->blocks.first->el, 0, initial_block_size);
return self;
}
@ -407,7 +419,7 @@ U64 MargaretImgAllocator__add_img_given_gap(
MargaretImgAllocator__insert_gap(self, segment.block, aligned_start + required_size,
gap_start + gap_len - (aligned_start + required_size));
BufRBTree_MapU64ToU64* images = &VecMargaretImgAllocatorOneBlock_mat(&self->blocks, segment.block)->images;
BufRBTree_MapU64ToU64* images = &segment.block->images;
bool iret = BufRBTree_MapU64ToU64_insert(images, aligned_start, required_size);
assert(iret);
return aligned_start;
@ -415,7 +427,7 @@ U64 MargaretImgAllocator__add_img_given_gap(
U64Segment MargaretImgAllocator__get_left_free_space(
const MargaretImgAllocator* self, MargaretImgAllocation allocation){
const MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_at(&self->blocks, allocation.block);
const MargaretImgAllocatorOneBlock* block = allocation.block;
U64 occ_start = allocation.start;
U64 prev_occ_it = BufRBTree_MapU64ToU64_find_max_less(&block->images, allocation.start);
@ -434,7 +446,7 @@ U64Segment MargaretImgAllocator__get_left_free_space(
U64Segment MargaretImgAllocator__get_right_free_space(
const MargaretImgAllocator* self, MargaretImgAllocation allocation){
const MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_at(&self->blocks, allocation.block);
const MargaretImgAllocatorOneBlock* block = allocation.block;
U64 occ_start = allocation.start;
VkMemoryRequirements occ_memory_requirements;
vkGetImageMemoryRequirements(self->device, allocation.image, &occ_memory_requirements);
@ -451,27 +463,29 @@ U64Segment MargaretImgAllocator__get_right_free_space(
return (U64Segment){.start = occ_start + occ_taken_size, .len = block->capacity - (occ_start + occ_taken_size)};
}
/* Also frees blocks */
void MargaretImgAllocator_drop(MargaretImgAllocator self){
for (size_t bi = 0; bi < self.blocks.len; bi++) {
vkFreeMemory(self.device, self.blocks.buf[bi].mem_hand, NULL);
for (ListNodeMargaretImgAllocatorOneBlock* bi = self.blocks.first; bi; bi = bi->next) {
vkFreeMemory(self.device, bi->el.mem_hand, NULL);
}
VecMargaretImgAllocatorOneBlock_drop(self.blocks);
ListMargaretImgAllocatorOneBlock_drop(self.blocks);
MargaretMemFreeSpaceManager_drop(self.mem_free_space);
}
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);
vkDestroyImage(self->device, allocation.image, NULL);
MargaretImgAllocator__erase_gap(self, allocation.block, left_free_space.start, left_free_space.len);
MargaretImgAllocator__erase_gap(self, allocation.block, right_free_space.start, right_free_space.len);
MargaretImgAllocator__insert_gap(self, allocation.block,
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,
left_free_space.start,
right_free_space.start + right_free_space.len - left_free_space.start);
MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, allocation.block);
bool eret = BufRBTree_MapU64ToU64_erase(&block->images, allocation.start);
assert(eret);
}
@ -514,24 +528,23 @@ NODISCARD MargaretImgAllocation MargaretImgAllocator__alloc(
MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, mem_requirements.size);
if (free_gap.variant == Option_None) {
assert(self->blocks.len > 0);
U64 pitch = self->blocks.buf[self->blocks.len - 1].capacity;
assert(self->blocks.first != NULL);
U64 pitch = self->blocks.first->el.capacity;
// Old blocks remain intact
U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(2 * pitch, maintenance3_properties.maxMemoryAllocationSize));
// U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(pitch, maintenance3_properties.maxMemoryAllocationSize));
MargaretImgAllocator__add_block(self, new_capacity);
U64 bid = self->blocks.len - 1;
MargaretImgAllocator__insert_gap(self, bid, mem_requirements.size, new_capacity - mem_requirements.size);
MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, bid);
MargaretImgAllocatorOneBlock* block = &self->blocks.first->el;
MargaretImgAllocator__insert_gap(self, block, mem_requirements.size, new_capacity - mem_requirements.size);
block->occupation_counter = mem_requirements.size;
bool iret = BufRBTree_MapU64ToU64_insert(&block->images, 0, mem_requirements.size);
assert(iret);
check(vkBindImageMemory(self->device, fresh_img, block->mem_hand, 0) == VK_SUCCESS);
// MargaretImgAllocator__debug(self);
return (MargaretImgAllocation){.block = bid, fresh_img, 0};
return (MargaretImgAllocation){.block = block, fresh_img, 0};
}
U64 aligned_pos = MargaretImgAllocator__add_img_given_gap(self, free_gap.some, mem_requirements.size, alignment_exp);
VkDeviceMemory memory = VecMargaretImgAllocatorOneBlock_at(&self->blocks, free_gap.some.block)->mem_hand;
VkDeviceMemory memory = free_gap.some.block->mem_hand;
check(vkBindImageMemory(self->device, fresh_img, memory, aligned_pos) == VK_SUCCESS);
// MargaretImgAllocator__debug(self);
return (MargaretImgAllocation){.block = free_gap.some.block, .image = fresh_img, .start = aligned_pos};