11#include " memory_pool.h"
22#include < iostream>
33#include < algorithm>
4+ #include < vulkan/vulkan.hpp>
45
56MemoryPool::MemoryPool (const vk::raii::Device& device, const vk::raii::PhysicalDevice& physicalDevice)
67 : device(device), physicalDevice(physicalDevice) {
78}
89
10+
911MemoryPool::~MemoryPool () {
1012 // RAII will handle cleanup automatically
1113 std::lock_guard lock (poolMutex);
@@ -153,6 +155,48 @@ std::unique_ptr<MemoryPool::MemoryBlock> MemoryPool::createMemoryBlock(PoolType
153155 return block;
154156}
155157
158+ std::unique_ptr<MemoryPool::MemoryBlock> MemoryPool::createMemoryBlockWithType (PoolType poolType, vk::DeviceSize size, uint32_t memoryTypeIndex) {
159+ auto configIt = poolConfigs.find (poolType);
160+ if (configIt == poolConfigs.end ()) {
161+ throw std::runtime_error (" Pool type not configured" );
162+ }
163+ const PoolConfig& config = configIt->second ;
164+
165+ // Allocate the memory block with the exact requested size
166+ vk::MemoryAllocateInfo allocInfo{
167+ .allocationSize = size,
168+ .memoryTypeIndex = memoryTypeIndex
169+ };
170+
171+ // Determine properties from the chosen memory type
172+ const auto memProps = physicalDevice.getMemoryProperties ();
173+ if (memoryTypeIndex >= memProps.memoryTypeCount ) {
174+ throw std::runtime_error (" Invalid memoryTypeIndex for createMemoryBlockWithType" );
175+ }
176+ const vk::MemoryPropertyFlags typeProps = memProps.memoryTypes [memoryTypeIndex].propertyFlags ;
177+
178+ auto block = std::unique_ptr<MemoryBlock>(new MemoryBlock{
179+ .memory = vk::raii::DeviceMemory (device, allocInfo),
180+ .size = size,
181+ .used = 0 ,
182+ .memoryTypeIndex = memoryTypeIndex,
183+ .isMapped = false ,
184+ .mappedPtr = nullptr ,
185+ .freeList = {},
186+ .allocationUnit = config.allocationUnit
187+ });
188+
189+ block->isMapped = (typeProps & vk::MemoryPropertyFlagBits::eHostVisible) != vk::MemoryPropertyFlags{};
190+ if (block->isMapped ) {
191+ block->mappedPtr = block->memory .mapMemory (0 , size);
192+ }
193+
194+ const size_t numUnits = static_cast <size_t >(block->size / config.allocationUnit );
195+ block->freeList .resize (numUnits, true );
196+
197+ return block;
198+ }
199+
156200std::pair<MemoryPool::MemoryBlock*, size_t > MemoryPool::findSuitableBlock (PoolType poolType, vk::DeviceSize size, vk::DeviceSize alignment) {
157201 auto poolIt = pools.find (poolType);
158202 if (poolIt == pools.end ()) {
@@ -162,27 +206,42 @@ std::pair<MemoryPool::MemoryBlock*, size_t> MemoryPool::findSuitableBlock(PoolTy
162206 auto & poolBlocks = poolIt->second ;
163207 const PoolConfig& config = poolConfigs[poolType];
164208
165- // Calculate required units (accounting for alignment)
209+ // Calculate required units (accounting for size alignment)
166210 const vk::DeviceSize alignedSize = ((size + alignment - 1 ) / alignment) * alignment;
167- const size_t requiredUnits = ( alignedSize + config.allocationUnit - 1 ) / config.allocationUnit ;
211+ const size_t requiredUnits = static_cast < size_t >(( alignedSize + config.allocationUnit - 1 ) / config.allocationUnit ) ;
168212
169- // Search existing blocks for sufficient free space
213+ // Search existing blocks for sufficient free space with proper offset alignment
170214 for (const auto & block : poolBlocks) {
171- // Find consecutive free units
172- size_t consecutiveFree = 0 ;
173- size_t startUnitCandidate = 0 ;
174- for ( size_t i = 0 ; i < block-> freeList . size (); ++i) {
175- if (block-> freeList [i] ) {
176- if (consecutiveFree == 0 ) {
177- startUnitCandidate = i ;
178- }
179- consecutiveFree++;
180- if (consecutiveFree >= requiredUnits) {
181- return {block. get (), startUnitCandidate} ;
182- }
183- } else {
184- consecutiveFree = 0 ;
215+ const vk::DeviceSize unit = config. allocationUnit ;
216+ const size_t totalUnits = block-> freeList . size () ;
217+
218+ size_t i = 0 ;
219+ while (i < totalUnits ) {
220+ // Ensure starting unit produces an offset aligned to 'alignment'
221+ vk::DeviceSize startOffset = static_cast <vk::DeviceSize>(i) * unit ;
222+ if ((alignment > 0 ) && (startOffset % alignment != 0 )) {
223+ // Advance i to the next unit that aligns with 'alignment'
224+ const vk::DeviceSize remainder = startOffset % alignment;
225+ const vk::DeviceSize advanceBytes = alignment - remainder ;
226+ const size_t advanceUnits = static_cast < size_t >((advanceBytes + unit - 1 ) / unit);
227+ i += std::max< size_t >(advanceUnits, 1 );
228+ continue ;
185229 }
230+
231+ // From aligned i, check for consecutive free units
232+ size_t consecutiveFree = 0 ;
233+ size_t j = i;
234+ while (j < totalUnits && block->freeList [j] && consecutiveFree < requiredUnits) {
235+ ++consecutiveFree;
236+ ++j;
237+ }
238+
239+ if (consecutiveFree >= requiredUnits) {
240+ return {block.get (), i};
241+ }
242+
243+ // Move past the checked range
244+ i = (j > i) ? j : (i + 1 );
186245 }
187246 }
188247
@@ -333,13 +392,41 @@ std::pair<vk::raii::Image, std::unique_ptr<MemoryPool::Allocation>> MemoryPool::
333392
334393 vk::raii::Image image (device, imageInfo);
335394
336- // Get memory requirements
395+ // Get memory requirements for this image
337396 vk::MemoryRequirements memRequirements = image.getMemoryRequirements ();
338397
339- // Allocate from texture pool
340- auto allocation = allocate (PoolType::TEXTURE_IMAGE, memRequirements.size , memRequirements.alignment );
341- if (!allocation) {
342- throw std::runtime_error (" Failed to allocate memory from texture pool" );
398+ // Pick a memory type compatible with this image
399+ uint32_t memoryTypeIndex = findMemoryType (memRequirements.memoryTypeBits , properties);
400+
401+ // Create a dedicated memory block for this image with the exact type and size
402+ std::unique_ptr<Allocation> allocation;
403+ {
404+ std::lock_guard<std::mutex> lock (poolMutex);
405+ auto poolIt = pools.find (PoolType::TEXTURE_IMAGE);
406+ if (poolIt == pools.end ()) {
407+ poolIt = pools.try_emplace (PoolType::TEXTURE_IMAGE).first ;
408+ }
409+ auto & poolBlocks = poolIt->second ;
410+ auto block = createMemoryBlockWithType (PoolType::TEXTURE_IMAGE, memRequirements.size , memoryTypeIndex);
411+
412+ // Prepare allocation that uses the new block from offset 0
413+ allocation = std::make_unique<Allocation>();
414+ allocation->memory = *block->memory ;
415+ allocation->offset = 0 ;
416+ allocation->size = memRequirements.size ;
417+ allocation->memoryTypeIndex = memoryTypeIndex;
418+ allocation->isMapped = block->isMapped ;
419+ allocation->mappedPtr = block->mappedPtr ;
420+
421+ // Mark the entire block as used
422+ block->used = memRequirements.size ;
423+ const size_t units = block->freeList .size ();
424+ for (size_t i = 0 ; i < units; ++i) {
425+ block->freeList [i] = false ;
426+ }
427+
428+ // Keep the block owned by the pool for lifetime management and deallocation support
429+ poolBlocks.push_back (std::move (block));
343430 }
344431
345432 // Bind memory to image
0 commit comments