Converted Descriptor heap to memory arena. Used Gemini with antigravity.
Heap pool code is a mess right now (lot of useless comments) Will revisit later.
This commit is contained in:
@@ -58,6 +58,7 @@
|
||||
<CustomBuild Include="include\Core\Math\Vector.h" />
|
||||
<CustomBuild Include="include\Core\Memory\Allocator.h" />
|
||||
<CustomBuild Include="include\Core\Memory\MemoryArena.h" />
|
||||
<CustomBuild Include="include\Core\Memory\ScratchArena.h" />
|
||||
<CustomBuild Include="include\Core\Memory\Utils.h" />
|
||||
<CustomBuild Include="include\Core\Networking\IPAddress.h" />
|
||||
<CustomBuild Include="include\Core\Networking\NetworkPacket.h" />
|
||||
@@ -122,6 +123,7 @@
|
||||
<CustomBuild Include="src\Core\Memory\EngineArena.h" />
|
||||
<CustomBuild Include="src\Core\Memory\MemoryArena.cpp" />
|
||||
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp" />
|
||||
<CustomBuild Include="src\Core\Memory\ScratchArena.cpp" />
|
||||
<CustomBuild Include="src\Core\Networking\NetworkPacket.cpp" />
|
||||
<CustomBuild Include="src\Core\Networking\Socket.cpp" />
|
||||
<CustomBuild Include="src\Core\Networking\SocketPlatformImpl.h" />
|
||||
@@ -162,6 +164,8 @@
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12GraphicsPipeline.cpp" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12GraphicsPipeline.h" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12Includes.h" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12InternalTests.cpp" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12InternalTests.h" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12RenderPass.cpp" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12RenderPass.h" />
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12Shader.cpp" />
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
<CustomBuild Include="include\Core\Memory\MemoryArena.h">
|
||||
<Filter>include\Core\Memory</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="include\Core\Memory\ScratchArena.h">
|
||||
<Filter>include\Core\Memory</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="include\Core\Memory\Utils.h">
|
||||
<Filter>include\Core\Memory</Filter>
|
||||
</CustomBuild>
|
||||
@@ -285,6 +288,9 @@
|
||||
<CustomBuild Include="src\Core\Memory\MemoryArenaTests.cpp">
|
||||
<Filter>src\Core\Memory</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="src\Core\Memory\ScratchArena.cpp">
|
||||
<Filter>src\Core\Memory</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="src\Core\Networking\NetworkPacket.cpp">
|
||||
<Filter>src\Core\Networking</Filter>
|
||||
</CustomBuild>
|
||||
@@ -405,6 +411,12 @@
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12Includes.h">
|
||||
<Filter>src\Graphics\D3D12</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12InternalTests.cpp">
|
||||
<Filter>src\Graphics\D3D12</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12InternalTests.h">
|
||||
<Filter>src\Graphics\D3D12</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="src\Graphics\D3D12\D3D12RenderPass.cpp">
|
||||
<Filter>src\Graphics\D3D12</Filter>
|
||||
</CustomBuild>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Juliet
|
||||
|
||||
JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size);
|
||||
JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16);
|
||||
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16);
|
||||
JULIET_API void ArenaReset(MemoryArena* arena);
|
||||
JULIET_API size_t ArenaGetMarker(MemoryArena* arena);
|
||||
JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker);
|
||||
@@ -58,4 +59,10 @@ namespace Juliet
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* ArenaRealloc(MemoryArena* arena, T* oldPtr, size_t oldCount, size_t newCount)
|
||||
{
|
||||
return static_cast<T*>(Juliet::ArenaRealloc(arena, static_cast<void*>(oldPtr), sizeof(T) * oldCount, sizeof(T) * newCount, alignof(T)));
|
||||
}
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size)
|
||||
@@ -36,6 +38,66 @@ namespace Juliet
|
||||
return result;
|
||||
}
|
||||
|
||||
void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment)
|
||||
{
|
||||
Assert(arena);
|
||||
// Alignment must be power of 2
|
||||
Assert((alignment & (alignment - 1)) == 0);
|
||||
|
||||
if (oldPtr == nullptr)
|
||||
{
|
||||
return ArenaPush(arena, newSize, alignment);
|
||||
}
|
||||
|
||||
if (newSize == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if the old allocation is at the top of the stack
|
||||
// We need to verify if (oldPtr + oldSize) == (Data + Offset)
|
||||
// Note: usage of reinterpret_cast is to be careful with pointer arithmetic on void*
|
||||
|
||||
uint8* oldPtrBytes = static_cast<uint8*>(oldPtr);
|
||||
uint8* arenaEnd = arena->Data + arena->Offset;
|
||||
|
||||
if (oldPtrBytes + oldSize == arenaEnd)
|
||||
{
|
||||
// It is the last allocation! We can reuse the space.
|
||||
// We just need to check if we can expand it (if growing)
|
||||
|
||||
// Re-calculate the offset start for this block (to ensure nothing weird with padding)
|
||||
// Ideally oldPtr was aligned.
|
||||
|
||||
// Current Offset corresponds to oldPtrBytes + oldSize.
|
||||
// We want to move Offset to oldPtrBytes + newSize.
|
||||
|
||||
size_t oldPtrOffset = static_cast<size_t>(oldPtrBytes - arena->Data);
|
||||
size_t newOffset = oldPtrOffset + newSize;
|
||||
|
||||
if (newOffset > arena->Size)
|
||||
{
|
||||
// Cannot expand in place, not enough space.
|
||||
// Fallthrough to Alloc + Copy
|
||||
}
|
||||
else
|
||||
{
|
||||
// In-place Resize success
|
||||
arena->Offset = newOffset;
|
||||
return oldPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Alloc + Copy
|
||||
void* newPtr = ArenaPush(arena, newSize, alignment);
|
||||
if (newPtr)
|
||||
{
|
||||
size_t copySize = oldSize < newSize ? oldSize : newSize;
|
||||
std::memcpy(newPtr, oldPtr, copySize);
|
||||
}
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
void ArenaReset(MemoryArena* arena)
|
||||
{
|
||||
Assert(arena);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
@@ -91,7 +92,10 @@ namespace Juliet::D3D12::Internal
|
||||
|
||||
void ReleaseDescriptor(const D3D12Descriptor& descriptor)
|
||||
{
|
||||
if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr) return;
|
||||
if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12DescriptorHeap* heap = descriptor.Heap;
|
||||
|
||||
@@ -105,23 +109,64 @@ namespace Juliet::D3D12::Internal
|
||||
heap->FreeIndicesCount++;
|
||||
}
|
||||
|
||||
D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver)
|
||||
D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver, DescriptorHeapCreator creator)
|
||||
{
|
||||
D3D12DescriptorHeapPool* pool = &d3d12Driver->SamplerHeapPool;
|
||||
uint32 count = GPUDriver::kSampler_HeapDescriptorCount;
|
||||
|
||||
D3D12DescriptorHeap* result = nullptr;
|
||||
|
||||
if (pool->Count > 0)
|
||||
{
|
||||
result = pool->Heaps[pool->Count - 1];
|
||||
pool->Count -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, count, false);
|
||||
return pool->Heaps[pool->Count];
|
||||
}
|
||||
|
||||
return result;
|
||||
// Pool is exhausted (all heaps are in use). We need to create a new one.
|
||||
// The pool array might be full of "Used" heaps, or it might have empty slots (nullptr) if we expanded before.
|
||||
// We look for a free slot to store the new heap.
|
||||
size_t freeSlotIndex = SIZE_MAX;
|
||||
|
||||
// Scan for nullptr in the entire array.
|
||||
// Optimization: active heaps are likely at the beginning, but since Count=0, "Used" heaps are 0..Capacity?
|
||||
// Actually, if Count=0, ALL slots 0..Capacity-1 are effectively "Used" (unless some are nullptr).
|
||||
for (size_t i = 0; i < pool->Capacity; ++i)
|
||||
{
|
||||
if (pool->Heaps[i] == nullptr)
|
||||
{
|
||||
freeSlotIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeSlotIndex == SIZE_MAX)
|
||||
{
|
||||
// No free slot, expand
|
||||
size_t oldCapacity = pool->Capacity;
|
||||
pool->Capacity = pool->Capacity == 0 ? 1 : pool->Capacity * 2;
|
||||
|
||||
// Using ArenaRealloc (Template):
|
||||
pool->Heaps = ArenaRealloc<D3D12DescriptorHeap*>(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity);
|
||||
|
||||
// Initialize new slots to nullptr
|
||||
for (size_t i = oldCapacity; i < pool->Capacity; ++i)
|
||||
{
|
||||
pool->Heaps[i] = nullptr;
|
||||
}
|
||||
freeSlotIndex = oldCapacity;
|
||||
}
|
||||
|
||||
// Create the new heap at the free slot
|
||||
pool->Heaps[freeSlotIndex] = creator(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, count, false);
|
||||
|
||||
// Now we have a new heap at freeSlotIndex. Ideally we want to return it.
|
||||
// But to maintain the "Stack" invariant (Available are at 0..Count-1),
|
||||
// and "Used" are at "Count..Capacity-1".
|
||||
// Currently Count=0. So "Used" is 0..Capacity-1.
|
||||
// freeSlotIndex is inside "Used" range.
|
||||
// We can just return it. It is already in the "Used" partition.
|
||||
// However, we want to ensure it doesn't get lost or overwritten.
|
||||
// Since we didn't increment Count, it stays in "Used".
|
||||
|
||||
return pool->Heaps[freeSlotIndex];
|
||||
}
|
||||
|
||||
void ReturnSamplerHeapToPool(NonNullPtr<D3D12Driver> d3d12Driver, D3D12DescriptorHeap* heap)
|
||||
@@ -136,14 +181,35 @@ namespace Juliet::D3D12::Internal
|
||||
|
||||
heap->CurrentDescriptorIndex = 0;
|
||||
|
||||
if (pool->Count >= pool->Capacity)
|
||||
// The heap is currently in the "Used" partition (index >= Count).
|
||||
// We want to move it to the "Available" partition (index < Count).
|
||||
// Strategy: Swap heap with the element at pool->Heaps[pool->Count], then increment Count.
|
||||
|
||||
// First, find the heap index.
|
||||
size_t heapIndex = SIZE_MAX;
|
||||
for (size_t i = pool->Count; i < pool->Capacity; ++i)
|
||||
{
|
||||
pool->Capacity = pool->Capacity == 0 ? 1 : pool->Capacity * 2;
|
||||
pool->Heaps =
|
||||
static_cast<D3D12DescriptorHeap**>(Realloc(pool->Heaps, pool->Capacity * sizeof(D3D12DescriptorHeap*)));
|
||||
if (pool->Heaps[i] == heap)
|
||||
{
|
||||
heapIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pool->Heaps[pool->Count] = heap;
|
||||
pool->Count += 1;
|
||||
if (heapIndex != SIZE_MAX)
|
||||
{
|
||||
D3D12DescriptorHeap* temp = pool->Heaps[pool->Count];
|
||||
pool->Heaps[pool->Count] = pool->Heaps[heapIndex];
|
||||
pool->Heaps[heapIndex] = temp;
|
||||
pool->Count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should not happen if the logic is correct.
|
||||
// Maybe it was not in the pool? (e.g. error scenario).
|
||||
// In that case, we should probably add it?
|
||||
// But per constraints, we assume it was allocated via pool.
|
||||
Assert(false, "Returning a heap that was not found in the pool!");
|
||||
}
|
||||
}
|
||||
} // namespace Juliet::D3D12::Internal
|
||||
|
||||
@@ -44,11 +44,13 @@ namespace Juliet::D3D12::Internal
|
||||
size_t Count;
|
||||
};
|
||||
|
||||
using DescriptorHeapCreator = D3D12DescriptorHeap* (*)(NonNullPtr<D3D12Driver>, D3D12_DESCRIPTOR_HEAP_TYPE, uint32, bool);
|
||||
|
||||
extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging);
|
||||
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap);
|
||||
|
||||
extern D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver);
|
||||
extern D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver, DescriptorHeapCreator creator = CreateDescriptorHeap);
|
||||
extern void ReturnSamplerHeapToPool(NonNullPtr<D3D12Driver> d3d12Driver, D3D12DescriptorHeap* heap);
|
||||
|
||||
extern bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor);
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsPipeline.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
#include <Graphics/D3D12/D3D12InternalTests.h>
|
||||
#include <Graphics/D3D12/D3D12RenderPass.h>
|
||||
#include <Graphics/D3D12/D3D12Shader.h>
|
||||
#include <Graphics/D3D12/D3D12SwapChain.h>
|
||||
@@ -488,7 +490,7 @@ namespace Juliet::D3D12
|
||||
heapPool.Heaps[i] = nullptr;
|
||||
}
|
||||
}
|
||||
SafeFree(heapPool.Heaps);
|
||||
// SafeFree(heapPool.Heaps); // Allocated with Arena, do not free.
|
||||
}
|
||||
};
|
||||
DestroyDescriptorHeapPool(driver->SamplerHeapPool);
|
||||
@@ -643,8 +645,13 @@ namespace Juliet::D3D12
|
||||
Free(device.Get());
|
||||
}
|
||||
|
||||
|
||||
GraphicsDevice* CreateGraphicsDevice(bool enableDebug)
|
||||
{
|
||||
#if JULIET_DEBUG
|
||||
// Unit Tests for D3D12 Logic
|
||||
UnitTest::TestDescriptorHeapPool();
|
||||
#endif
|
||||
auto driver = static_cast<D3D12Driver*>(Calloc(1, sizeof(D3D12Driver)));
|
||||
|
||||
#if JULIET_DEBUG
|
||||
@@ -929,8 +936,7 @@ namespace Juliet::D3D12
|
||||
{
|
||||
heapPool.Capacity = 4;
|
||||
heapPool.Count = 4;
|
||||
heapPool.Heaps = static_cast<Internal::D3D12DescriptorHeap**>(
|
||||
Calloc(heapPool.Capacity, sizeof(Internal::D3D12DescriptorHeap*)));
|
||||
heapPool.Heaps = ArenaPushArray<Internal::D3D12DescriptorHeap*>(GetEngineArena(), heapPool.Capacity);
|
||||
|
||||
for (uint32 i = 0; i < heapPool.Capacity; ++i)
|
||||
{
|
||||
|
||||
141
Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp
Normal file
141
Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include <Graphics/D3D12/D3D12InternalTests.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
|
||||
#if JULIET_DEBUG
|
||||
|
||||
namespace Juliet::D3D12::UnitTest
|
||||
{
|
||||
using namespace Juliet::D3D12;
|
||||
using namespace Juliet::D3D12::Internal;
|
||||
|
||||
static D3D12DescriptorHeap* MockCreateDescriptorHeap(NonNullPtr<D3D12Driver>, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32, bool)
|
||||
{
|
||||
D3D12DescriptorHeap* heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
|
||||
if (heap)
|
||||
{
|
||||
heap->HeapType = type;
|
||||
heap->MaxDescriptors = 128;
|
||||
// Mock other fields as needed to pass verification
|
||||
}
|
||||
return heap;
|
||||
}
|
||||
|
||||
void TestDescriptorHeapPool()
|
||||
{
|
||||
D3D12Driver driver = {};
|
||||
ZeroStruct(driver);
|
||||
// Ensure pool is empty
|
||||
driver.SamplerHeapPool.Count = 0;
|
||||
driver.SamplerHeapPool.Capacity = 0;
|
||||
driver.SamplerHeapPool.Heaps = nullptr;
|
||||
|
||||
NonNullPtr<D3D12Driver> driverPtr(&driver);
|
||||
|
||||
// 1. Acquire from empty -> Should create new
|
||||
D3D12DescriptorHeap* heap1 = AcquireSamplerHeapFromPool(driverPtr, MockCreateDescriptorHeap);
|
||||
Assert(heap1 != nullptr);
|
||||
Assert(driver.SamplerHeapPool.Count == 0); // Used heaps are above Count
|
||||
Assert(driver.SamplerHeapPool.Capacity >= 1);
|
||||
Assert(driver.SamplerHeapPool.Heaps[0] == heap1);
|
||||
|
||||
// 2. Return -> Should become available
|
||||
ReturnSamplerHeapToPool(driverPtr, heap1);
|
||||
Assert(driver.SamplerHeapPool.Count == 1); // One available
|
||||
Assert(driver.SamplerHeapPool.Heaps[0] == heap1); // Available is at index 0
|
||||
|
||||
// 3. Acquire again -> Should reuse
|
||||
D3D12DescriptorHeap* heap2 = AcquireSamplerHeapFromPool(driverPtr, MockCreateDescriptorHeap);
|
||||
Assert(heap2 == heap1); // Reused
|
||||
Assert(driver.SamplerHeapPool.Count == 0); // No available left
|
||||
|
||||
// 4. Acquire another -> Should Expand and Create
|
||||
D3D12DescriptorHeap* heap3 = AcquireSamplerHeapFromPool(driverPtr, MockCreateDescriptorHeap);
|
||||
Assert(heap3 != nullptr);
|
||||
Assert(heap3 != heap1);
|
||||
Assert(driver.SamplerHeapPool.Count == 0);
|
||||
Assert(driver.SamplerHeapPool.Capacity >= 2);
|
||||
|
||||
// Cleanup
|
||||
(void)heap1; (void)heap2; (void)heap3;
|
||||
Free(heap1);
|
||||
Free(heap3);
|
||||
|
||||
// 5. Test Multiple Allocations (8 heaps)
|
||||
// Reset pool for clean test or continue? Let's reset to be sure of state,
|
||||
// effectively leaking previous pool array but that's fine for mock test.
|
||||
// Actually, let's just continue using the pool, it has Capacity >= 2.
|
||||
|
||||
// Return everything first to have clean slate if possible, but we already freed heap1 and heap3 mentally/physically.
|
||||
// The pool thinks heap3 is "Used" (outside Count).
|
||||
// We freed it physically, but pool has a dangling pointer in Heaps[1].
|
||||
// This is dangerous if we reuse it.
|
||||
// So we MUST correct the pool state or reset it.
|
||||
// Let's reset the pool state for the 8-loop test.
|
||||
driver.SamplerHeapPool.Count = 0;
|
||||
driver.SamplerHeapPool.Capacity = 0;
|
||||
driver.SamplerHeapPool.Heaps = nullptr; // Leaks previous array
|
||||
|
||||
const int kNumHeaps = 32;
|
||||
D3D12DescriptorHeap* heaps[kNumHeaps];
|
||||
|
||||
// 5.1 Acquire 8
|
||||
for (int i = 0; i < kNumHeaps; ++i)
|
||||
{
|
||||
heaps[i] = AcquireSamplerHeapFromPool(driverPtr, MockCreateDescriptorHeap);
|
||||
Assert(heaps[i] != nullptr);
|
||||
// Verify uniqueness
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
Assert(heaps[i] != heaps[j]);
|
||||
}
|
||||
}
|
||||
Assert(driver.SamplerHeapPool.Capacity >= kNumHeaps);
|
||||
Assert(driver.SamplerHeapPool.Count == 0);
|
||||
|
||||
// 5.2 Release 8
|
||||
for (int i = 0; i < kNumHeaps; ++i)
|
||||
{
|
||||
ReturnSamplerHeapToPool(driverPtr, heaps[i]);
|
||||
}
|
||||
Assert(driver.SamplerHeapPool.Count == kNumHeaps);
|
||||
|
||||
// 5.3 Acquire 8 Again (Should Reuse)
|
||||
D3D12DescriptorHeap* heapsAgain[kNumHeaps];
|
||||
for (int i = 0; i < kNumHeaps; ++i)
|
||||
{
|
||||
heapsAgain[i] = AcquireSamplerHeapFromPool(driverPtr, MockCreateDescriptorHeap);
|
||||
|
||||
// Verify it matches one of the original heaps (order might reverse due to stack-like behavior)
|
||||
bool found = false;
|
||||
for (int j = 0; j < kNumHeaps; ++j)
|
||||
{
|
||||
if (heapsAgain[i] == heaps[j])
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(found);
|
||||
// Verify uniqueness in the new set
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
Assert(heapsAgain[i] != heapsAgain[j]);
|
||||
}
|
||||
}
|
||||
Assert(driver.SamplerHeapPool.Count == 0);
|
||||
// Capacity should not have increased if we reused
|
||||
Assert(driver.SamplerHeapPool.Capacity == kNumHeaps); // Or >= 8
|
||||
|
||||
// Cleanup
|
||||
for (int i = 0; i < kNumHeaps; ++i)
|
||||
{
|
||||
Free(heaps[i]);
|
||||
}
|
||||
|
||||
// Note: heap2 is heap1.
|
||||
// Pool array in driver leaked for test scope, acceptable.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
9
Juliet/src/Graphics/D3D12/D3D12InternalTests.h
Normal file
9
Juliet/src/Graphics/D3D12/D3D12InternalTests.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
|
||||
#if JULIET_DEBUG
|
||||
namespace Juliet::D3D12::UnitTest
|
||||
{
|
||||
void TestDescriptorHeapPool();
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user