More implementation and first tests.

Crashing for now - need more refactoring.
This commit is contained in:
Adam Sawicki 2021-10-28 14:32:34 +02:00
parent 7acc6c0ca8
commit 54b7eccc35
2 changed files with 219 additions and 46 deletions

View File

@ -2194,6 +2194,30 @@ struct VmaVirtualBlockCreateInfo
const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks;
}; };
/// TODO
typedef enum VmaVirtualAllocationCreateFlagBits {
/** Allocation will be created from upper stack in a double stack pool.
This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag.
*/
VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT,
/** Allocation strategy that tries to minimize memory usage.
*/
VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT,
/** Allocation strategy that tries to minimize allocation time.
*/
VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT,
/** Allocation strategy that tries to minimize memory fragmentation.
*/
VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT,
/** A bit mask to extract only `STRATEGY` bits from entire set of flags.
*/
VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK,
VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VmaVirtualAllocationCreateFlagBits;
typedef VkFlags VmaVirtualAllocationCreateFlags;
/// Parameters of created virtual allocation to be passed to vma TODO. /// Parameters of created virtual allocation to be passed to vma TODO.
struct VmaVirtualAllocationCreateInfo struct VmaVirtualAllocationCreateInfo
{ {
@ -2207,6 +2231,10 @@ struct VmaVirtualAllocationCreateInfo
Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset.
*/ */
VkDeviceSize alignment; VkDeviceSize alignment;
/** \brief TODO
*/
VmaVirtualAllocationCreateFlags flags;
/** \brief Custom pointer to be associated with the allocation. /** \brief Custom pointer to be associated with the allocation.
It can be fetched or changed later. It can be fetched or changed later.
@ -6831,22 +6859,43 @@ public:
const VkAllocationCallbacks m_AllocationCallbacks; const VkAllocationCallbacks m_AllocationCallbacks;
VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo); VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo);
~VmaVirtualBlock_T(); ~VmaVirtualBlock_T()
VkResult Init(); {
vma_delete(GetAllocationCallbacks(), m_Metadata);
}
VkResult Init()
{
return VK_SUCCESS;
}
const VkAllocationCallbacks* GetAllocationCallbacks() const const VkAllocationCallbacks* GetAllocationCallbacks() const
{ {
return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL; return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL;
} }
bool IsEmpty() const; bool IsEmpty() const
void GetAllocationInfo(VkDeviceSize offset, VmaVirtualAllocationInfo& outInfo) const; {
return m_Metadata->IsEmpty();
}
void GetAllocationInfo(VkDeviceSize offset, VmaVirtualAllocationInfo& outInfo) const
{
m_Metadata->GetAllocationInfo(offset, outInfo);
}
VkResult Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VkDeviceSize& outOffset); VkResult Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VkDeviceSize& outOffset);
void Free(VkDeviceSize offset); void Free(VkDeviceSize offset)
void Clear(); {
void SetAllocationUserData(VkDeviceSize offset, void* userData); m_Metadata->FreeAtOffset(offset);
}
void Clear()
{
m_Metadata->Clear();
}
void SetAllocationUserData(VkDeviceSize offset, void* userData)
{
m_Metadata->SetAllocationUserData(offset, userData);
}
private: private:
VmaBlockMetadata* m_Metadata;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -16596,48 +16645,49 @@ VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo
m_AllocationCallbacksSpecified(createInfo.pAllocationCallbacks != VMA_NULL), m_AllocationCallbacksSpecified(createInfo.pAllocationCallbacks != VMA_NULL),
m_AllocationCallbacks(createInfo.pAllocationCallbacks != VMA_NULL ? *createInfo.pAllocationCallbacks : VmaEmptyAllocationCallbacks) m_AllocationCallbacks(createInfo.pAllocationCallbacks != VMA_NULL ? *createInfo.pAllocationCallbacks : VmaEmptyAllocationCallbacks)
{ {
//TODO const uint32_t algorithm = createInfo.flags & VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK;
} switch(algorithm)
{
case 0:
m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Generic)(VK_NULL_HANDLE, true);
break;
case VMA_VIRTUAL_BLOCK_CREATE_BUDDY_ALGORITHM_BIT:
m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Buddy)(VK_NULL_HANDLE, true);
break;
case VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT:
m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Linear)(VK_NULL_HANDLE, true);
break;
default:
VMA_ASSERT(0);
}
VmaVirtualBlock_T::~VmaVirtualBlock_T() m_Metadata->Init(createInfo.size);
{
//TODO
}
VkResult VmaVirtualBlock_T::Init()
{
//TODO
return VK_SUCCESS;
}
bool VmaVirtualBlock_T::IsEmpty() const
{
return true;//TODO
}
void VmaVirtualBlock_T::GetAllocationInfo(VkDeviceSize offset, VmaVirtualAllocationInfo& outInfo) const
{
//TODO
} }
VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VkDeviceSize& outOffset) VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VkDeviceSize& outOffset)
{ {
return VK_ERROR_DEVICE_LOST;//TODO outOffset = VK_WHOLE_SIZE;
} VmaAllocationRequest request = {};
if(m_Metadata->CreateAllocationRequest(
void VmaVirtualBlock_T::Free(VkDeviceSize offset) 0, // currentFrameIndex - unimportant
{ 0, // frameInUseCount - unimportant
//TODO 1, // bufferImageGranularity
} createInfo.size, // allocSize
VMA_MAX(createInfo.alignment, 1llu), // allocAlignment
void VmaVirtualBlock_T::Clear() (createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0, // upperAddress
{ VMA_SUBALLOCATION_TYPE_UNKNOWN, // allocType - unimportant
//TODO false, // canMakeOthersLost
} createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK, // strategy
&request))
void VmaVirtualBlock_T::SetAllocationUserData(VkDeviceSize offset, void* userData) {
{ m_Metadata->Alloc(request,
//TODO VMA_SUBALLOCATION_TYPE_UNKNOWN, // type - unimportant
createInfo.size, // allocSize
createInfo.pUserData);
outOffset = request.offset;
return VK_SUCCESS;
}
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -31,6 +31,7 @@
#ifdef _WIN32 #ifdef _WIN32
static const char* CODE_DESCRIPTION = "Foo"; static const char* CODE_DESCRIPTION = "Foo";
static constexpr VkDeviceSize MEGABYTE = 1024 * 1024;
extern VkCommandBuffer g_hTemporaryCommandBuffer; extern VkCommandBuffer g_hTemporaryCommandBuffer;
extern const VkAllocationCallbacks* g_Allocs; extern const VkAllocationCallbacks* g_Allocs;
@ -2686,6 +2687,126 @@ static void TestBasics()
TestInvalidAllocations(); TestInvalidAllocations();
} }
static void TestVirtualBlocks()
{
wprintf(L"Test virtual blocks\n");
const VkDeviceSize blockSize = 16 * MEGABYTE;
const VkDeviceSize alignment = 256;
// # Create block 16 MB
VmaVirtualBlockCreateInfo blockCreateInfo = {};
blockCreateInfo.pAllocationCallbacks = g_Allocs;
blockCreateInfo.size = blockSize;
VmaVirtualBlock block;
TEST(vmaCreateVirtualBlock(&blockCreateInfo, &block) == VK_SUCCESS && block);
// # Allocate 8 MB
VmaVirtualAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.alignment = alignment;
allocCreateInfo.pUserData = (void*)(uintptr_t)1;
allocCreateInfo.size = 8 * MEGABYTE;
VkDeviceSize alloc0Offset;
TEST(vmaVirtualAllocate(block, &allocCreateInfo, &alloc0Offset) == VK_SUCCESS && alloc0Offset < blockSize);
#if 0
// # Validate the allocation
VIRTUAL_ALLOCATION_INFO allocInfo = {};
block->GetAllocationInfo(alloc0Offset, &allocInfo);
CHECK_BOOL( allocInfo.size == allocDesc.Size );
CHECK_BOOL( allocInfo.pUserData == allocDesc.pUserData );
// # Check SetUserData
block->SetAllocationUserData(alloc0Offset, (void*)(uintptr_t)2);
block->GetAllocationInfo(alloc0Offset, &allocInfo);
CHECK_BOOL( allocInfo.pUserData == (void*)(uintptr_t)2 );
// # Allocate 4 MB
allocDesc.Size = 4 * MEGABYTE;
allocDesc.Alignment = alignment;
UINT64 alloc1Offset;
CHECK_HR( block->Allocate(&allocDesc, &alloc1Offset) );
CHECK_BOOL( alloc1Offset < blockSize );
CHECK_BOOL( alloc1Offset + 4 * MEGABYTE <= alloc0Offset || alloc0Offset + 8 * MEGABYTE <= alloc1Offset ); // Check if they don't overlap.
// # Allocate another 8 MB - it should fail
allocDesc.Size = 8 * MEGABYTE;
allocDesc.Alignment = alignment;
UINT64 alloc2Offset;
CHECK_BOOL( FAILED(block->Allocate(&allocDesc, &alloc2Offset)) );
CHECK_BOOL( alloc2Offset == UINT64_MAX );
// # Free the 4 MB block. Now allocation of 8 MB should succeed.
block->FreeAllocation(alloc1Offset);
CHECK_HR( block->Allocate(&allocDesc, &alloc2Offset) );
CHECK_BOOL( alloc2Offset < blockSize );
CHECK_BOOL( alloc2Offset + 4 * MEGABYTE <= alloc0Offset || alloc0Offset + 8 * MEGABYTE <= alloc2Offset ); // Check if they don't overlap.
// # Calculate statistics
StatInfo statInfo = {};
block->CalculateStats(&statInfo);
CHECK_BOOL(statInfo.AllocationCount == 2);
CHECK_BOOL(statInfo.BlockCount == 1);
CHECK_BOOL(statInfo.UsedBytes == blockSize);
CHECK_BOOL(statInfo.UnusedBytes + statInfo.UsedBytes == blockSize);
// # Generate JSON dump
WCHAR* json = nullptr;
block->BuildStatsString(&json);
{
std::wstring str(json);
CHECK_BOOL( str.find(L"\"UserData\": 1") != std::wstring::npos );
CHECK_BOOL( str.find(L"\"UserData\": 2") != std::wstring::npos );
}
block->FreeStatsString(json);
#endif
// # Free alloc0, leave alloc2 unfreed.
vmaVirtualFree(block, alloc0Offset);
#if 0
// # Test alignment
{
constexpr size_t allocCount = 10;
UINT64 allocOffset[allocCount] = {};
for(size_t i = 0; i < allocCount; ++i)
{
const bool alignment0 = i == allocCount - 1;
allocDesc.Size = i * 3 + 15;
allocDesc.Alignment = alignment0 ? 0 : 8;
CHECK_HR(block->Allocate(&allocDesc, &allocOffset[i]));
if(!alignment0)
{
CHECK_BOOL(allocOffset[i] % allocDesc.Alignment == 0);
}
}
for(size_t i = allocCount; i--; )
{
block->FreeAllocation(allocOffset[i]);
}
}
// # Final cleanup
block->FreeAllocation(alloc2Offset);
#endif
//vmaClearVirtualBlock(block);
vmaDestroyVirtualBlock(block);
}
static void TestAllocationVersusResourceSize() static void TestAllocationVersusResourceSize()
{ {
wprintf(L"Test allocation versus resource size\n"); wprintf(L"Test allocation versus resource size\n");
@ -6561,16 +6682,18 @@ void Test()
{ {
wprintf(L"TESTING:\n"); wprintf(L"TESTING:\n");
if(false) if(true)
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Temporarily insert custom tests here: // Temporarily insert custom tests here:
TestVirtualBlocks();
return; return;
} }
// # Simple tests // # Simple tests
TestBasics(); TestBasics();
TestVirtualBlocks();
TestAllocationVersusResourceSize(); TestAllocationVersusResourceSize();
//TestGpuData(); // Not calling this because it's just testing the testing environment. //TestGpuData(); // Not calling this because it's just testing the testing environment.
#if VMA_DEBUG_MARGIN #if VMA_DEBUG_MARGIN