From 8ec7bff4906ceac2138a611d4b55c10ba282249b Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Fri, 28 Nov 2025 03:46:06 +0300 Subject: [PATCH] I think I finally wrote MargaretMemAllocator. I hadn't even tested it. It is 3:44. Were you aware of 'Tractat about Reptiles'? Me neither. MargaretMemAllocator is the most multifunctional allocator possible, you will still need separate allocator for buffers --- src/l2/margaret/vulkan_memory_claire.h | 456 +++++++++++++++---------- src/l2/tests/data_structures/t2.c | 6 +- 2 files changed, 272 insertions(+), 190 deletions(-) diff --git a/src/l2/margaret/vulkan_memory_claire.h b/src/l2/margaret/vulkan_memory_claire.h index cd5845d..889e282 100644 --- a/src/l2/margaret/vulkan_memory_claire.h +++ b/src/l2/margaret/vulkan_memory_claire.h @@ -205,8 +205,12 @@ typedef struct { U64 width; U64 height; VkFormat format; - VkImageLayout current_layout; VkImageUsageFlags usage_flags; + + /* Layout after defragmentation + at which point in pipeline will the need this image (again, after defragmentation) */ + VkImageLayout current_layout; + VkPipelineStageFlags current_dest_stage_mask; + VkAccessFlags current_dest_access_mask; bool preserve_at_quiet; VkImage image; } MargaretMemoryOccupationImage; @@ -286,8 +290,10 @@ typedef struct { U64 width; U64 height; VkFormat format; - VkImageLayout current_layout; VkImageUsageFlags usage_flags; + VkImageLayout current_layout; + VkPipelineStageFlags current_dest_stage_mask; + VkAccessFlags current_dest_access_mask; bool preserve_at_quiet; RBTreeNode_KVPU64ToMargaretMAOccupation** ret_ans; } MargaretMemAllocatorRequestAllocImage; @@ -302,6 +308,24 @@ typedef struct { VecMargaretMemAllocatorRequestAllocImage alloc_image; } MargaretMemAllocatorRequests; +void MargaretMemAllocatorRequests_sink(MargaretMemAllocatorRequests* self){ + VecMargaretMemAllocatorRequestFreeOccupant_sink(&self->free_buf, 0); + VecMargaretMemAllocatorRequestFreeOccupant_sink(&self->free_image, 0); + VecMargaretMemAllocatorRequestResizeBuffer_sink(&self->shrink_buf, 0); + VecMargaretMemAllocatorRequestResizeBuffer_sink(&self->expand_buf, 0); + VecMargaretMemAllocatorRequestAllocBuffer_sink(&self->alloc_buf, 0); + VecMargaretMemAllocatorRequestAllocImage_sink(&self->alloc_image, 0); +} + +void MargaretMemAllocatorRequests_drop(MargaretMemAllocatorRequests self){ + VecMargaretMemAllocatorRequestFreeOccupant_drop(self.free_buf); + VecMargaretMemAllocatorRequestFreeOccupant_drop(self.free_image); + VecMargaretMemAllocatorRequestResizeBuffer_drop(self.shrink_buf); + VecMargaretMemAllocatorRequestResizeBuffer_drop(self.expand_buf); + VecMargaretMemAllocatorRequestAllocBuffer_drop(self.alloc_buf); + VecMargaretMemAllocatorRequestAllocImage_drop(self.alloc_image); +} + typedef struct { U64 start; U64 len; @@ -428,6 +452,7 @@ OptionMargaretFreeMemSegment MargaretMemFreeSpaceManager_search( /* VkDevice and VkPhysicalDevice stay remembered here. Don't forget that, please */ typedef struct { + U64 total_capacity; ListMargaretMemAllocatorOneBlock blocks; /* old_blocks is usually empty. BUT! When you generated a defragmentation command buffer with * MargaretMemAllocator_carry_out_request, this vector will be filled with old blocks, while @@ -478,98 +503,72 @@ void MargaretMemAllocator__insert_gap( block_it->el.occupation_counter -= len; } +/* didn't generate it, so I am doing it myself */ +void RBTree_MapU64ToMargaretMAOccupation_insert_node( + RBTree_MapU64ToMargaretMAOccupation* self, RBTreeNode_KVPU64ToMargaretMAOccupation* node){ + node->base.left = node->base.right = self->NIL; + node->base.color = RBTREE_RED; + if (self->root == self->NIL) { + self->root = &node->base; + node->base.parent = self->NIL; + node->base.color = RBTREE_BLACK; + } + RBTreeNode_KVPU64ToMargaretMAOccupation* cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)self->root; + while (true) { + if (node->key < cur->key) { + if (cur->base.left == self->NIL) { + node->base.parent = &cur->base; + cur->base.left = &node->base; + RBTree_fix_after_insert(&self->root, self->NIL, &node->base); + } else { + cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)cur->base.left; + } + } else if (cur->key < node->key) { + if (cur->base.right == self->NIL) { + node->base.parent = &cur->base; + cur->base.right = &node->base; + RBTree_fix_after_insert(&self->root, self->NIL, &node->base); + } else { + cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)cur->base.right; + } + } else + assert(false); + } +} + U64 margaret_get_alignment_left_padding(U64 unaligned_start, U8 alignment_exp){ U64 hit = unaligned_start & (1ull << alignment_exp) - 1; return (hit ? (1ull << alignment_exp) - hit : 0); } -/* This method only works for alloc_buffer and alloc_image requests. It does not work for - * expand_buffer request (path 2) */ -bool MargaretMemAllocator__add_freshly_new_occupant_any_type( - MargaretMemAllocator* self, MargaretMAOccupant occ, const VkMemoryRequirements* requirements, - RBTreeNode_KVPU64ToMargaretMAOccupation** ret_ans +/* This method works both for alloc_buffer/alloc_image requests and for expand_buf request (moving path). + * existing node carries information about occupant, but key (start pos), taken_size, block, are not filled, + * and this node is basically outside any tree */ +void MargaretMemAllocator__add_occupant_node_given_gap_any_type( + MargaretMemAllocator* self, RBTreeNode_KVPU64ToMargaretMAOccupation* existing_node, + MargaretFreeMemSegment segment, U64 required_size, U8 alignment_exp ){ - check(U64_is_2pow(requirements->alignment)); - U8 alignment_exp = U64_2pow_log(requirements->alignment); - OptionMargaretFreeMemSegment free_gap = - MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, requirements->size); - if (free_gap.variant == Option_None) - return false; - ListNodeMargaretMemAllocatorOneBlock* block_it = free_gap.some.dev_mem_block; + ListNodeMargaretMemAllocatorOneBlock* block_it = segment.dev_mem_block; RBTree_MapU64ToMargaretMAOccupation* block_occupied_memory = &block_it->el.occupied_memory; - U64 gap_start = free_gap.some.start; - U64 gap_len = free_gap.some.len; + U64 gap_start = segment.start; + U64 gap_len = segment.len; U64 af = margaret_get_alignment_left_padding(gap_start, alignment_exp); U64 aligned_start = gap_start + af; - assert(aligned_start + requirements->size <= gap_start + gap_len); + assert(aligned_start + required_size <= gap_start + gap_len); MargaretMemAllocator__erase_gap(self, block_it, gap_start, gap_len); MargaretMemAllocator__insert_gap(self, block_it, gap_start, af); - MargaretMemAllocator__insert_gap(self, block_it, aligned_start + requirements->size, - gap_start + gap_len - (aligned_start + requirements->size)); + MargaretMemAllocator__insert_gap(self, block_it, aligned_start + required_size, + gap_start + gap_len - (aligned_start + required_size)); - /* We are doing a dumb crutch here where we first insert key+value, then search for the iterator */ - check(RBTree_MapU64ToMargaretMAOccupation_insert(block_occupied_memory, aligned_start, - (MargaretMAOccupation){.taken_size = requirements->size, .block = block_it, .me = occ})); - /* Lord forgive me */ - *ret_ans = RBTree_MapU64ToMargaretMAOccupation_find(block_occupied_memory, aligned_start); - assert(*ret_ans); - return true; + existing_node->key = aligned_start; + existing_node->value.taken_size = required_size; + existing_node->value.block = block_it; + + RBTree_MapU64ToMargaretMAOccupation_insert_node(block_occupied_memory, existing_node); } -bool MargaretMemAllocator__add_freshly_new_buffer_occ( - MargaretMemAllocator* self, RBTreeNode_KVPU64ToMargaretMAOccupation** ret_ans, - U64 size, VkBufferUsageFlags usage_flags, bool preserve_at_quiet){ - VkBuffer buf; - check(vkCreateBuffer(self->device, &(VkBufferCreateInfo){ - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = size, - .usage = usage_flags, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - }, NULL, &buf) == VK_SUCCESS); - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(self->device, buf, &memory_requirements); - bool success = MargaretMemAllocator__add_freshly_new_occupant_any_type(self, (MargaretMAOccupant){ - .variant = MargaretMemoryOccupation_Buffer, - .buf = (MargaretMemoryOccupationBuffer){ - .buffer = buf, .capacity = size, .usage_flags = usage_flags, .preserve_at_quiet = preserve_at_quiet - }}, &memory_requirements, ret_ans); - if (!success) - vkDestroyBuffer(self->device, buf, NULL); - return success; -} -/* Helper function used in BD path */ -bool MargaretMemAllocator__add_new_image_occ( - MargaretMemAllocator* self, RBTreeNode_KVPU64ToMargaretMAOccupation** ret_ans, - U64 width, U64 height, VkFormat format, VkImageUsageFlags usage_flags, bool preserve_at_quiet){ - VkImage img; - check(vkCreateImage(self->device, &(VkImageCreateInfo){ - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = format, - .extent = (VkExtent3D){ - .width = width, - .height = height, - .depth = 1, - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = usage_flags, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }, NULL, &img) == VK_SUCCESS); - VkMemoryRequirements memory_requirements; - vkGetImageMemoryRequirements(self->device, img, &memory_requirements); - return MargaretMemAllocator__add_freshly_new_occupant_any_type(self, (MargaretMAOccupant){ - .variant = MargaretMemoryOccupation_Image, - .img = (MargaretMemoryOccupationImage){ - .image = img, .width = width, .height = height, .current_layout = VK_IMAGE_LAYOUT_UNDEFINED, - .usage_flags = usage_flags, .preserve_at_quiet = preserve_at_quiet, .format = format, - }}, &memory_requirements, ret_ans); -} U64Segment MargaretMemAllocatorOneBlock_get_left_free_space( const MargaretMemAllocatorOneBlock* self, RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it){ @@ -719,42 +718,10 @@ void MargaretMemAllocator__shrink_some_buffer( occ_me->buf.capacity = smaller_size; } -/* didn't generate it, so I am doing it myself */ -void RBTree_MapU64ToMargaretMAOccupation_insert_node( - RBTree_MapU64ToMargaretMAOccupation* self, RBTreeNode_KVPU64ToMargaretMAOccupation* node){ - node->base.left = node->base.right = self->NIL; - node->base.color = RBTREE_RED; - if (self->root == self->NIL) { - self->root = &node->base; - node->base.parent = self->NIL; - node->base.color = RBTREE_BLACK; - } - RBTreeNode_KVPU64ToMargaretMAOccupation* cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)self->root; - while (true) { - if (node->key < cur->key) { - if (cur->base.left == self->NIL) { - node->base.parent = &cur->base; - cur->base.left = &node->base; - RBTree_fix_after_insert(&self->root, self->NIL, &node->base); - } else { - cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)cur->base.left; - } - } else if (cur->key < node->key) { - if (cur->base.right == self->NIL) { - node->base.parent = &cur->base; - cur->base.right = &node->base; - RBTree_fix_after_insert(&self->root, self->NIL, &node->base); - } else { - cur = (RBTreeNode_KVPU64ToMargaretMAOccupation*)cur->base.right; - } - } else - assert(false); - } -} - /* Helper function for MargaretMemAllocator_request_needs_defragmentation */ void MargaretMemAllocator__keep_building_up_cur_block( MargaretMemAllocator* self, U64* cur_block_size_needed, ListNodeMargaretMemAllocatorOneBlock** cur_block, + U64* updated_total_capacity, VkMemoryRequirements mem_requirements, RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it, U64 maxMemoryAllocationSize ){ @@ -770,6 +737,7 @@ void MargaretMemAllocator__keep_building_up_cur_block( .memoryTypeIndex = self->memory_type_id, .allocationSize = maxMemoryAllocationSize}, NULL, &((*cur_block)->el.mem_hand)); (*cur_block)->el.capacity = maxMemoryAllocationSize; + *updated_total_capacity += maxMemoryAllocationSize; if (self->mem_properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { vkMapMemory(self->device, (*cur_block)->el.mem_hand, 0, VK_WHOLE_SIZE, 0, &(*cur_block)->el.mapped_memory); } @@ -813,7 +781,6 @@ void MargaretMemAllocator_request_needs_defragmentation( * request vector. Because we expanded buffer without moving it. Now we need to undo the expansions and * regenerate expand_buffer request back in vector */ for (size_t i = 0; i < buffer_expansion_record.len; i++) { - MargaretMABufferExpansionRecord ss; U64 old_capacity = buffer_expansion_record.buf[i].old_capacity; RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it = buffer_expansion_record.buf[i].occ_it; assert(occ_it); @@ -871,6 +838,8 @@ void MargaretMemAllocator_request_needs_defragmentation( assert(self->old_blocks.first == NULL); self->old_blocks.first = self->blocks.first; self->blocks.first = NULL; + // this variable will be updated later by `updated_total_capacity` + U64 old_total_capacity = self->total_capacity; /* Cleaning free space set from gaps of old blocks */ for (ListNodeMargaretMemAllocatorOneBlock* block_it = self->old_blocks.first; block_it; block_it = block_it->next){ @@ -885,6 +854,7 @@ void MargaretMemAllocator_request_needs_defragmentation( MargaretMemAllocator__erase_gap(self, block_it, prev_end, block_it->el.capacity - prev_end); } + U64 updated_total_capacity = 0; /* It's used as a counter before the actual VkDeviceMemory is allocated. * (To know how much memory needs to be allocated ) */ U64 cur_block_size_needed = 0; @@ -919,7 +889,8 @@ void MargaretMemAllocator_request_needs_defragmentation( occ_it->value.me.buf.buffer = fresh_buf; occ_it->value.me.buf.capacity = needed_buf_capacity; - MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, &cur_block, mem_requirements, + MargaretMemAllocator__keep_building_up_cur_block(self, + &cur_block_size_needed, &cur_block, &updated_total_capacity, mem_requirements, occ_it, maintenance3_properties.maxMemoryAllocationSize); if (occ_it->value.me.buf.preserve_at_quiet) { @@ -950,7 +921,8 @@ void MargaretMemAllocator_request_needs_defragmentation( occ_it->value.me.buf.usage_flags = req->usage; occ_it->value.me.buf.preserve_at_quiet = req->preserve_at_quiet; - MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, &cur_block, mem_requirements, + MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, + &cur_block, &updated_total_capacity, mem_requirements, occ_it, maintenance3_properties.maxMemoryAllocationSize); } @@ -962,11 +934,7 @@ void MargaretMemAllocator_request_needs_defragmentation( .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .imageType = VK_IMAGE_TYPE_2D, .format = req->format, - .extent = (VkExtent3D){ - .width = req->width, - .height = req->height, - .depth = 1, - }, + .extent = (VkExtent3D){ .width = req->width, .height = req->height, .depth = 1, }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -983,10 +951,13 @@ void MargaretMemAllocator_request_needs_defragmentation( occ_it->value.me.variant = MargaretMemoryOccupation_Image; occ_it->value.me.img = (MargaretMemoryOccupationImage){ .width = req->width, .height = req->height, .usage_flags = req->usage_flags, - .current_layout = req->current_layout, .format = req->format, .image = fresh_image, + .current_layout = req->current_layout, .current_dest_stage_mask = req->current_dest_stage_mask, + .current_dest_access_mask = req->current_dest_access_mask, + .format = req->format, .image = fresh_image, .preserve_at_quiet = req->preserve_at_quiet }; - MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, &cur_block, mem_requirements, + MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, + &cur_block, &updated_total_capacity, mem_requirements, occ_it, maintenance3_properties.maxMemoryAllocationSize); } @@ -1018,7 +989,8 @@ void MargaretMemAllocator_request_needs_defragmentation( occ_it->value.me.buf.buffer = fresh_buf; /* This function changes occ_it->taken_size and, of course, occ_it->block */ - MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, &cur_block, mem_requirements, + MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, + &cur_block, &updated_total_capacity, mem_requirements, occ_it, maintenance3_properties.maxMemoryAllocationSize); if (occ_it->value.me.buf.preserve_at_quiet) { @@ -1032,9 +1004,7 @@ void MargaretMemAllocator_request_needs_defragmentation( .imageType = VK_IMAGE_TYPE_2D, .format = replacer->value.me.img.format, .extent = (VkExtent3D){ - .width = replacer->value.me.img.width, - .height = replacer->value.me.img.height, - .depth = 1, + .width = replacer->value.me.img.width, .height = replacer->value.me.img.height, .depth = 1, }, .mipLevels = 1, .arrayLayers = 1, @@ -1048,11 +1018,27 @@ void MargaretMemAllocator_request_needs_defragmentation( vkGetImageMemoryRequirements(self->device, fresh_image, &mem_requirements); occ_it->value.me.img.image = fresh_image; + MargaretMemAllocator__keep_building_up_cur_block(self, &cur_block_size_needed, + &cur_block, &updated_total_capacity, mem_requirements, + occ_it, maintenance3_properties.maxMemoryAllocationSize); + if (occ_it->value.me.img.preserve_at_quiet) { - VkImageMemoryBarrier first_barriers[2]; // todo: continue from here - vkCmdPipelineBarrier(cmd_buff, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0 /* Flags */, 0, NULL /* not here */, 0, NULL /* not here */, - 1, &(VkImageMemoryBarrier){ + VkImageMemoryBarrier first_barriers[2] = { + (VkImageMemoryBarrier){ /* Source image */ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = replacer->value.me.img.image, + .subresourceRange = (VkImageSubresourceRange){ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, + .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, + }, + }, + (VkImageMemoryBarrier){ /* Destination image */ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = 0, .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, @@ -1062,36 +1048,48 @@ void MargaretMemAllocator_request_needs_defragmentation( .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = occ_it->value.me.img.image, .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, + .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, }, - }); + } + }; + vkCmdPipelineBarrier(cmd_buff, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0 /* Flags */, 0, NULL /* not here */, 0, NULL /* not here */, + 2, first_barriers); vkCmdCopyImage(cmd_buff, replacer->value.me.img.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, fresh_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &(VkImageCopy){ .srcSubresource = (VkImageSubresourceLayers){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, + .baseArrayLayer = 0, .layerCount = 1, }, .srcOffset = {0, 0, 0}, .dstSubresource = (VkImageSubresourceLayers){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, + .baseArrayLayer = 0, .layerCount = 1, }, .dstOffset = {0, 0, 0}, .extent = (VkExtent3D){ - .width = replacer->value.me.img.width, - .height = replacer->value.me.img.height, + .width = replacer->value.me.img.width, .height = replacer->value.me.img.height, .depth = 1 } }); - // vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, destination_stage_mask, + VkImageMemoryBarrier finishing_barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = occ_it->value.me.img.current_dest_access_mask, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = occ_it->value.me.img.current_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = occ_it->value.me.img.image, + .subresourceRange = (VkImageSubresourceRange){ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, + .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, + }, + }; + vkCmdPipelineBarrier(cmd_buff, + VK_PIPELINE_STAGE_TRANSFER_BIT, occ_it->value.me.img.current_dest_stage_mask, + 0 /* Flags*/, 0, NULL, 0, NULL, 1, &finishing_barrier); } } @@ -1099,7 +1097,23 @@ void MargaretMemAllocator_request_needs_defragmentation( } } - // todo: iterate over all remaining occupants, and do the "moving thing" + assert(cur_block_size_needed > 0 && cur_block_size_needed <= maintenance3_properties.maxMemoryAllocationSize); + /* Finalizing the very last MMA block */ + U64 desirable_gain = 2 * old_total_capacity; + U64 shizhlyazhki = desirable_gain > updated_total_capacity ? desirable_gain - updated_total_capacity : 0; + U64 fin_block_capacity = MIN_U64(maintenance3_properties.maxMemoryAllocationSize, + MAX_U64(cur_block_size_needed, shizhlyazhki)); + cur_block->el.capacity = fin_block_capacity; + updated_total_capacity += fin_block_capacity; + vkAllocateMemory(self->device, &(VkMemoryAllocateInfo){ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .memoryTypeIndex = self->memory_type_id, + .allocationSize = fin_block_capacity}, NULL, &cur_block->el.mem_hand); + if (self->mem_properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + vkMapMemory(self->device, cur_block->el.mem_hand, 0, VK_WHOLE_SIZE, 0, &cur_block->el.mapped_memory); + } + self->total_capacity = updated_total_capacity; + MargaretMemAllocatorRequests_sink(requests); } MargaretMemAllocatorDemands MargaretMemAllocator_carry_out_request( @@ -1127,14 +1141,15 @@ MargaretMemAllocatorDemands MargaretMemAllocator_carry_out_request( /* We first try to do all the expand_buf requests, that COULD be done using method 1 */ for (U64 rr = 0; rr < requests->expand_buf.len;) { U64 new_size = requests->expand_buf.buf[rr].new_size; - RBTreeNode_KVPU64ToMargaretMAOccupation* original_node = requests->expand_buf.buf[rr].occ_it; - // todo: fix according to new design - U64 occ_start = ans->occ_it->key; - assert(ans->occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); - MargaretMemoryOccupationBuffer* buf = &ans->occ_it->value.me.buf; + RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it = requests->expand_buf.buf[rr].occ_it; + + U64 occ_start = occ_it->key; + assert(occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); + MargaretMemoryOccupationBuffer* buf = &occ_it->value.me.buf; /* Method 1 */ - U64Segment right_free_space = MargaretMemAllocatorOneBlock_get_right_free_space(block, ans->occ_it); + U64Segment right_free_space = MargaretMemAllocatorOneBlock_get_right_free_space( + &occ_it->value.block->el, occ_it); VkBuffer temp_buf_extension; check (vkCreateBuffer(self->device, &(VkBufferCreateInfo){ @@ -1154,19 +1169,18 @@ MargaretMemAllocatorDemands MargaretMemAllocator_carry_out_request( rr++; continue; } - vkDestroyBuffer(self->device, temp_buf_extension, NULL); - MargaretMemAllocator__erase_gap(self, ans->device_mem_ind, right_free_space); - MargaretMemAllocator__insert_gap(self, ans->device_mem_ind, + MargaretMemAllocator__erase_gap(self, occ_it->value.block, right_free_space.start, right_free_space.len); + MargaretMemAllocator__insert_gap(self, occ_it->value.block, occ_start + temp_buf_extension_req.size, right_free_space.start + right_free_space.len - (occ_start + temp_buf_extension_req.size)); VecMargaretMABufferExpansionRecord_append(&buffer_expansion_record, (MargaretMABufferExpansionRecord){ - .mem_block_ind = ans->device_mem_ind, .old_capacity = buf->capacity, .occ_it = ans->occ_it + .old_capacity = buf->capacity, .occ_it = occ_it }); /* Success */ - buf->capacity = new_size; - ans->occ_it->value.taken_size = temp_buf_extension_req.size; vkDestroyBuffer(self->device, buf->buffer, NULL); + buf->capacity = new_size; buf->buffer = temp_buf_extension; + occ_it->value.taken_size = temp_buf_extension_req.size; VecMargaretMemAllocatorRequestResizeBuffer_unordered_pop(&requests->expand_buf, rr); } @@ -1177,25 +1191,49 @@ MargaretMemAllocatorDemands MargaretMemAllocator_carry_out_request( MargaretMemAllocatorDemands demands = 0; for (U64 ri = 0; ri < requests->expand_buf.len; ri++) { - U64 new_size = requests->expand_buf.buf[ri].new_size; - MargaretMemAllocatorOccupantPosition* ans = requests->expand_buf.buf[ri].ans; - MargaretMemAllocatorOccupantPosition old_ans = *ans; - assert(old_ans.occ_it->value.ans == ans); - assert(ans->occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); - assert(new_size >= old_ans.occ_it->value.me.buf.capacity); - MargaretMemoryOccupationBuffer* old_buf = &old_ans.occ_it->value.me.buf; - bool success = MargaretMemAllocator__add_new_buffer_occ(self, ans, ) - // todo: add addition of occ:: BUfffwe sbool success = __add_occ_niuffw(.... old-Pkjbiuf) - if (!success) { + U64 larger_size = requests->expand_buf.buf[ri].new_size; + RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it = requests->expand_buf.buf[ri].occ_it; + assert(occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); + assert(larger_size >= occ_it->value.me.buf.capacity); + + VkBuffer bigger_buffer; + check(vkCreateBuffer(self->device, &(VkBufferCreateInfo){ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = larger_size, + .usage = occ_it->value.me.buf.usage_flags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }, NULL, &bigger_buffer) == VK_SUCCESS); + VkMemoryRequirements mem_requirements; + vkGetBufferMemoryRequirements(self->device, bigger_buffer, &mem_requirements); + + check(U64_is_2pow(mem_requirements.alignment)); + U8 alignment_exp = U64_2pow_log(mem_requirements.alignment); + OptionMargaretFreeMemSegment free_gap = + MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, mem_requirements.size); + if (free_gap.variant == Option_None) { + vkDestroyBuffer(self->device, bigger_buffer, NULL); MargaretMemAllocator_request_needs_defragmentation(self, cmd_buff, requests, buffer_expansion_record, 0, 0); assert(self->old_moved_buffers.len == 0); return MARGARET_MA_DEMANDS_DEFRAGMENTATION; } + + RBTreeNode_KVPU64ToMargaretMAOccupation* replacer = safe_malloc(sizeof(RBTreeNode_KVPU64ToMargaretMAOccupation)); + RBTree_MapU64ToMargaretMAOccupation* OLD_TREE = &occ_it->value.block->el.occupied_memory; + RBTree_steal_neighbours(&OLD_TREE->root, OLD_TREE->NIL, &occ_it->base, &replacer->base); + replacer->key = occ_it->key; + replacer->value = occ_it->value; + assert(replacer->value.me.variant == MargaretMemoryOccupation_Buffer); + occ_it->value.me.buf.buffer = bigger_buffer; + occ_it->value.me.buf.capacity = larger_size; + + MargaretMemAllocator__add_occupant_node_given_gap_any_type(self, occ_it, free_gap.some, mem_requirements.size, alignment_exp); + VecMargaretMANewMovedBufRecord_append(&self->old_moved_buffers, - (MargaretMANewMovedBufRecord){.ans = ans, .old_pos = old_ans}); - if (old_buf->preserve_at_quiet) { + (MargaretMANewMovedBufRecord){.replacement = replacer, .my_occ_it = occ_it}); + if (replacer->value.me.buf.preserve_at_quiet) { demands = MARGARET_MA_DEMANDS_CMD_BUFFER_BIT; - vkCmdCopyBuffer(cmd_buff, old_buf->buffer, temp_buf, 1, &(VkBufferCopy){0, 0, old_buf->capacity}); + vkCmdCopyBuffer(cmd_buff, replacer->value.me.buf.buffer, bigger_buffer, + 1, &(VkBufferCopy){0, 0, replacer->value.me.buf.capacity}); } } @@ -1209,36 +1247,76 @@ MargaretMemAllocatorDemands MargaretMemAllocator_carry_out_request( .usage = req->usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, }, NULL, &fresh_buf) == VK_SUCCESS); - VkMemoryRequirements mem_requires; - vkGetBufferMemoryRequirements(self->device, fresh_buf, &mem_requires); - bool success = MargaretMemAllocator__add_new_occupant(self, (MargaretMemoryOccupation){ - .taken_size = mem_requires.size, .ans = req->ans, .variant = MargaretMemoryOccupation_Buffer, - .buf.capacity = req->allocation_size, .buf.buffer = fresh_buf, .buf.preserve_at_quiet = req->preserve_at_quiet, - .buf.usage_flags = req->usage - }, &mem_requires); - if (!success) { + VkMemoryRequirements mem_requirements; + vkGetBufferMemoryRequirements(self->device, fresh_buf, &mem_requirements); + check(U64_is_2pow(mem_requirements.alignment)); + U8 alignment_exp = U64_2pow_log(mem_requirements.alignment); + OptionMargaretFreeMemSegment free_gap = + MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, mem_requirements.size); + if (free_gap.variant == Option_None) { vkDestroyBuffer(self->device, fresh_buf, NULL); - MargaretMemAllocator_request_needs_defragmentation(self, cmd_buff, requests, buffer_expansion_record, ri, 0); + MargaretMemAllocator_request_needs_defragmentation(self, cmd_buff, requests, buffer_expansion_record, 0, 0); assert(self->old_moved_buffers.len == 0); return MARGARET_MA_DEMANDS_DEFRAGMENTATION; } + + RBTreeNode_KVPU64ToMargaretMAOccupation* new_node = safe_malloc(sizeof(RBTreeNode_KVPU64ToMargaretMAOccupation)); + new_node->value.me = (MargaretMAOccupant){.variant = MargaretMemoryOccupation_Buffer, .buf = { + .buffer = fresh_buf, .capacity = req->allocation_size, .preserve_at_quiet = req->allocation_size, + .usage_flags = req->usage + }}; + MargaretMemAllocator__add_occupant_node_given_gap_any_type(self, new_node, free_gap.some, mem_requirements.size, alignment_exp); } for (U64 ri = 0; ri < requests->alloc_image.len; ri++) { MargaretMemAllocatorRequestAllocImage* req = &requests->alloc_image.buf[ri]; - // todo: add shitafuck + VkImage fresh_img; + check(vkCreateImage(self->device, &(VkImageCreateInfo){ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = req->format, + .extent = (VkExtent3D){.width = req->width, .height = req->height,.depth = 1,}, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = req->usage_flags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .initialLayout = req->current_layout, + }, NULL, &fresh_img) == VK_SUCCESS); + VkMemoryRequirements mem_requirements; + vkGetImageMemoryRequirements(self->device, fresh_img, &mem_requirements); + + check(U64_is_2pow(mem_requirements.alignment)); + U8 alignment_exp = U64_2pow_log(mem_requirements.alignment); + OptionMargaretFreeMemSegment free_gap = + MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, mem_requirements.size); + if (free_gap.variant == Option_None) { + vkDestroyImage(self->device, fresh_img, NULL); + MargaretMemAllocator_request_needs_defragmentation(self, cmd_buff, requests, buffer_expansion_record, 0, 0); + assert(self->old_moved_buffers.len == 0); + return MARGARET_MA_DEMANDS_DEFRAGMENTATION; + } + + RBTreeNode_KVPU64ToMargaretMAOccupation* new_node = safe_malloc(sizeof(RBTreeNode_KVPU64ToMargaretMAOccupation)); + new_node->value.me = (MargaretMAOccupant){.variant = MargaretMemoryOccupation_Image, .img = { + .image = fresh_img, .width = req->width, .height = req->height, .format = req->format, + .usage_flags = req->usage_flags, .current_layout = req->current_layout, + .current_dest_stage_mask = req->current_dest_stage_mask, + .current_dest_access_mask = req->current_dest_access_mask, .preserve_at_quiet = req->preserve_at_quiet + }}; + MargaretMemAllocator__add_occupant_node_given_gap_any_type(self, new_node, free_gap.some, mem_requirements.size, alignment_exp); } + MargaretMemAllocatorRequests_sink(requests); return demands; - } char* MargaretMemAllocator_get_host_visible_buffer_ptr( - const MargaretMemAllocator* self, const MargaretMemAllocatorOccupantPosition* pos){ - const MargaretMemAllocatorOneBlock* bl = VecMargaretMemAllocatorOneBlock_at(&self->blocks, pos->device_mem_ind); - assert(pos->occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); - check((self->mem_properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RBTreeNode_KVPU64ToMargaretMAOccupation* occ_it){ + const MargaretMemAllocatorOneBlock* bl = &occ_it->value.block->el; + assert(occ_it->value.me.variant == MargaretMemoryOccupation_Buffer); assert(bl->mapped_memory); - return (char*)bl->mapped_memory + pos->occ_it->key; -} \ No newline at end of file + return (char*)bl->mapped_memory + occ_it->key; +} diff --git a/src/l2/tests/data_structures/t2.c b/src/l2/tests/data_structures/t2.c index a7ffaa8..5af0ab2 100644 --- a/src/l2/tests/data_structures/t2.c +++ b/src/l2/tests/data_structures/t2.c @@ -361,4 +361,8 @@ void vkCmdCopyImage( const VkImageCopy* pRegions); -#include "../../margaret/vulkan_memory_claire.h" \ No newline at end of file +#include "../../margaret/vulkan_memory_claire.h" + +int main(){ + return 0; +}