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

This commit is contained in:
Андреев Григорий 2025-11-28 03:46:06 +03:00
parent d5854dd5a3
commit 8ec7bff490
2 changed files with 272 additions and 190 deletions

View File

@ -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;
}
return (char*)bl->mapped_memory + occ_it->key;
}

View File

@ -361,4 +361,8 @@ void vkCmdCopyImage(
const VkImageCopy* pRegions);
#include "../../margaret/vulkan_memory_claire.h"
#include "../../margaret/vulkan_memory_claire.h"
int main(){
return 0;
}