Skip to content

Commit 6e4dd3d

Browse files
committed
Fixed a bug in buffer-image granularity handling
Hopefully fixes GPUOpen-LibrariesAndSDKs#517
1 parent 5d0efb5 commit 6e4dd3d

2 files changed

Lines changed: 85 additions & 53 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Added `VMA_VERSION` macro with library version number (#507).
1212
- Improvements in the algorithm choosing memory type when `VMA_MEMORY_USAGE_AUTO*` is used (#520).
1313
- Fixed compatibility with C++20 modules on Clang 21 and GCC15 (#513, #514).
14+
- Fixed a bug in buffer-image granularity handling (#517).
1415
- Fixed race condition in defragmentation (#529, #313).
1516
- Other fixes and improvements, including compatibility with various platforms and compilers, improvements in documentation, sample application, and tests.
1617

include/vk_mem_alloc.h

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,7 +3137,7 @@ remove them if not needed.
31373137
*/
31383138
#if !defined(VMA_CONFIGURATION_USER_INCLUDES_H)
31393139
#include <cassert> // for assert
3140-
#include <algorithm> // for min, max, swap
3140+
#include <algorithm> // for min, max, swap, sort
31413141
#include <mutex>
31423142
#else
31433143
#include VMA_CONFIGURATION_USER_INCLUDES_H
@@ -7178,6 +7178,14 @@ void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json)
71787178

71797179
#ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY
71807180
// Before deleting object of this class remember to call 'Destroy()'
7181+
/*
7182+
Tracks block occupancy at VkPhysicalDeviceLimits::bufferImageGranularity page boundaries.
7183+
For each granularity-sized page in a memory block, m_RegionInfo stores:
7184+
- allocCount: how many allocations touch this page as their first or last page.
7185+
- allocType: the remembered VmaSuballocationType for that page while allocCount > 0.
7186+
Only boundary pages are tracked because buffer-image granularity conflicts matter when
7187+
adjacent allocations share the same granularity page at the start or end of an allocation.
7188+
*/
71817189
class VmaBlockBufferImageGranularity final
71827190
{
71837191
public:
@@ -7200,6 +7208,21 @@ class VmaBlockBufferImageGranularity final
72007208
VkDeviceSize& inOutAllocSize,
72017209
VkDeviceSize& inOutAllocAlignment) const;
72027210

7211+
/*
7212+
Checks whether an allocation placed in a free block would conflict with existing
7213+
allocations due to buffer-image granularity requirements and, if needed, aligns the
7214+
allocation start to the next granularity page.
7215+
7216+
Parameters:
7217+
- inOutAllocOffset: candidate allocation offset inside the block; may be increased.
7218+
- allocSize: size of the allocation being placed.
7219+
- blockOffset: start offset of the free block being considered.
7220+
- blockSize: size of the free block being considered.
7221+
- allocType: VmaSuballocationType of the allocation being placed.
7222+
7223+
Returns true when the placement conflicts or no longer fits in the free block after alignment.
7224+
Returns false when the placement is valid, possibly after updating inOutAllocOffset.
7225+
*/
72037226
bool CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset,
72047227
VkDeviceSize allocSize,
72057228
VkDeviceSize blockOffset,
@@ -7288,56 +7311,62 @@ bool VmaBlockBufferImageGranularity::CheckConflictAndAlignUp(VkDeviceSize& inOut
72887311
VkDeviceSize blockSize,
72897312
VmaSuballocationType allocType) const
72907313
{
7291-
if (IsEnabled())
7314+
if (!IsEnabled())
7315+
return false;
7316+
7317+
uint32_t startPage = GetStartPage(inOutAllocOffset);
7318+
if (m_RegionInfo[startPage].allocCount > 0 &&
7319+
VmaIsBufferImageGranularityConflict(static_cast<VmaSuballocationType>(m_RegionInfo[startPage].allocType), allocType))
72927320
{
7293-
uint32_t startPage = GetStartPage(inOutAllocOffset);
7321+
inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity);
7322+
if (blockSize < allocSize + inOutAllocOffset - blockOffset)
7323+
return true;
7324+
startPage = GetStartPage(inOutAllocOffset);
72947325
if (m_RegionInfo[startPage].allocCount > 0 &&
72957326
VmaIsBufferImageGranularityConflict(static_cast<VmaSuballocationType>(m_RegionInfo[startPage].allocType), allocType))
7296-
{
7297-
inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity);
7298-
if (blockSize < allocSize + inOutAllocOffset - blockOffset)
7299-
return true;
7300-
++startPage;
7301-
}
7302-
uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize);
7303-
if (endPage != startPage &&
7304-
m_RegionInfo[endPage].allocCount > 0 &&
7305-
VmaIsBufferImageGranularityConflict(static_cast<VmaSuballocationType>(m_RegionInfo[endPage].allocType), allocType))
73067327
{
73077328
return true;
73087329
}
73097330
}
7331+
uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize);
7332+
if (endPage != startPage &&
7333+
m_RegionInfo[endPage].allocCount > 0 &&
7334+
VmaIsBufferImageGranularityConflict(static_cast<VmaSuballocationType>(m_RegionInfo[endPage].allocType), allocType))
7335+
{
7336+
return true;
7337+
}
7338+
73107339
return false;
73117340
}
73127341

73137342
void VmaBlockBufferImageGranularity::AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size)
73147343
{
7315-
if (IsEnabled())
7316-
{
7317-
uint32_t startPage = GetStartPage(offset);
7318-
AllocPage(m_RegionInfo[startPage], allocType);
7344+
if (!IsEnabled())
7345+
return;
73197346

7320-
uint32_t endPage = GetEndPage(offset, size);
7321-
if (startPage != endPage)
7322-
AllocPage(m_RegionInfo[endPage], allocType);
7323-
}
7347+
uint32_t startPage = GetStartPage(offset);
7348+
AllocPage(m_RegionInfo[startPage], allocType);
7349+
7350+
uint32_t endPage = GetEndPage(offset, size);
7351+
if (startPage != endPage)
7352+
AllocPage(m_RegionInfo[endPage], allocType);
73247353
}
73257354

73267355
void VmaBlockBufferImageGranularity::FreePages(VkDeviceSize offset, VkDeviceSize size)
73277356
{
7328-
if (IsEnabled())
7357+
if (!IsEnabled())
7358+
return;
7359+
7360+
uint32_t startPage = GetStartPage(offset);
7361+
--m_RegionInfo[startPage].allocCount;
7362+
if (m_RegionInfo[startPage].allocCount == 0)
7363+
m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE;
7364+
uint32_t endPage = GetEndPage(offset, size);
7365+
if (startPage != endPage)
73297366
{
7330-
uint32_t startPage = GetStartPage(offset);
7331-
--m_RegionInfo[startPage].allocCount;
7332-
if (m_RegionInfo[startPage].allocCount == 0)
7333-
m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE;
7334-
uint32_t endPage = GetEndPage(offset, size);
7335-
if (startPage != endPage)
7336-
{
7337-
--m_RegionInfo[endPage].allocCount;
7338-
if (m_RegionInfo[endPage].allocCount == 0)
7339-
m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE;
7340-
}
7367+
--m_RegionInfo[endPage].allocCount;
7368+
if (m_RegionInfo[endPage].allocCount == 0)
7369+
m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE;
73417370
}
73427371
}
73437372

@@ -7362,36 +7391,38 @@ VmaBlockBufferImageGranularity::ValidationContext VmaBlockBufferImageGranularity
73627391
bool VmaBlockBufferImageGranularity::Validate(ValidationContext& ctx,
73637392
VkDeviceSize offset, VkDeviceSize size) const
73647393
{
7365-
if (IsEnabled())
7366-
{
7367-
uint32_t start = GetStartPage(offset);
7368-
++ctx.pageAllocs[start];
7369-
VMA_VALIDATE(m_RegionInfo[start].allocCount > 0);
7394+
if (!IsEnabled())
7395+
return true;
73707396

7371-
uint32_t end = GetEndPage(offset, size);
7372-
if (start != end)
7373-
{
7374-
++ctx.pageAllocs[end];
7375-
VMA_VALIDATE(m_RegionInfo[end].allocCount > 0);
7376-
}
7397+
uint32_t start = GetStartPage(offset);
7398+
++ctx.pageAllocs[start];
7399+
VMA_VALIDATE(m_RegionInfo[start].allocCount > 0);
7400+
7401+
uint32_t end = GetEndPage(offset, size);
7402+
if (start != end)
7403+
{
7404+
++ctx.pageAllocs[end];
7405+
VMA_VALIDATE(m_RegionInfo[end].allocCount > 0);
73777406
}
7407+
73787408
return true;
73797409
}
73807410

73817411
bool VmaBlockBufferImageGranularity::FinishValidation(ValidationContext& ctx) const
73827412
{
7413+
if (!IsEnabled())
7414+
return true;
7415+
73837416
// Check proper page structure
7384-
if (IsEnabled())
7385-
{
7386-
VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!");
7417+
VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!");
73877418

7388-
for (uint32_t page = 0; page < m_RegionCount; ++page)
7389-
{
7390-
VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount);
7391-
}
7392-
vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount);
7393-
ctx.pageAllocs = VMA_NULL;
7419+
for (uint32_t page = 0; page < m_RegionCount; ++page)
7420+
{
7421+
VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount);
73947422
}
7423+
vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount);
7424+
ctx.pageAllocs = VMA_NULL;
7425+
73957426
return true;
73967427
}
73977428

0 commit comments

Comments
 (0)