Fixing the D3D12DescriptorHeap.cpp memory leak. Was creating descriptor heap every time a pipeline was bound when we only need it once per commandlist.

fixed some vibe code weird shit
This commit is contained in:
2026-01-23 21:43:48 -05:00
parent c10d371836
commit d4e4229d61
11 changed files with 97 additions and 295 deletions

View File

@@ -1,7 +1,6 @@
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12CommandList.h>
#include <Graphics/D3D12/D3D12CommandList.h>
#include <Graphics/D3D12/D3D12Buffer.h>
#include <Graphics/D3D12/D3D12CommandList.h>
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
#include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/D3D12Utils.h>
@@ -28,7 +27,8 @@ namespace Juliet::D3D12
bool CreateAllocator(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandListBaseData> baseData,
D3D12_COMMAND_QUEUE_DESC queueDesc)
{
HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator, reinterpret_cast<void**>(&baseData->Allocator));
HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator,
reinterpret_cast<void**>(&baseData->Allocator));
if (FAILED(result))
{
AssertHR(result, "Cannot create ID3D12CommandAllocator");
@@ -96,8 +96,10 @@ namespace Juliet::D3D12
{
CreateAllocator(driver, &commandList->CopyCommandList, queueDesc);
ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr;
HRESULT result = driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type,
D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList, reinterpret_cast<void**>(&d3d12CopyCommandList));
HRESULT result =
driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type,
D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList,
reinterpret_cast<void**>(&d3d12CopyCommandList));
if (FAILED(result))
{
@@ -392,8 +394,8 @@ namespace Juliet::D3D12
{
auto d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
// For now we assume Graphics Root Signature. Compute support would need a check or separate function.
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(
rootParameterIndex, numConstants, constants, 0);
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex,
numConstants, constants, 0);
}
namespace Internal
@@ -409,7 +411,7 @@ namespace Juliet::D3D12
samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver);
commandList->CRB_SRV_UAV_Heap = viewHeap;
commandList->RTV_Heap = samplerHeap;
commandList->Sampler_Heap = samplerHeap;
heaps[0] = viewHeap->Handle;
heaps[1] = samplerHeap->Handle;
@@ -445,19 +447,16 @@ namespace Juliet::D3D12
return false;
}
result = commandList->GraphicsCommandList.CommandList->Reset(
commandList->GraphicsCommandList.Allocator, nullptr);
result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr);
if (FAILED(result))
{
LogError(driver->D3D12Device, "Could not reset command list", result);
return false;
}
// Return heap descriptor to pool
// CRB_SRV_UAV_Heap is global bindless, do not return it.
ReturnSamplerHeapToPool(driver, commandList->RTV_Heap);
ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap);
commandList->Sampler_Heap = nullptr;
commandList->CRB_SRV_UAV_Heap = nullptr;
commandList->RTV_Heap = nullptr;
// Clean up resource tracking
for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx)

View File

@@ -39,9 +39,10 @@ namespace Juliet::D3D12
struct D3D12CommandList
{
CommandListHeader Common;
uint64 ID;
CommandListHeader Common;
D3D12Driver* Driver;
D3D12PresentData* PresentDatas;
@@ -77,7 +78,7 @@ namespace Juliet::D3D12
// D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
Internal::D3D12DescriptorHeap* CRB_SRV_UAV_Heap;
Internal::D3D12DescriptorHeap* RTV_Heap;
Internal::D3D12DescriptorHeap* Sampler_Heap;
// Resource Tracking
D3D12Texture** UsedTextures;
@@ -97,7 +98,8 @@ namespace Juliet::D3D12
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format);
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex, uint32 numConstants, const void* constants);
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
uint32 numConstants, const void* constants);
namespace Internal
{

View File

@@ -1,3 +1,5 @@
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>
#include <Core/Memory/EngineArena.h>
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
@@ -8,8 +10,6 @@ namespace Juliet::D3D12::Internal
{
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging)
{
ID3D12DescriptorHeap* handle;
auto heap = ArenaPushType<D3D12DescriptorHeap>(GetEngineArena(), ConstString("D3D12DescriptorHeap"));
if (!heap)
{
@@ -28,7 +28,9 @@ namespace Juliet::D3D12::Internal
heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
heapDesc.NodeMask = 0;
HRESULT result = driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle);
ID3D12DescriptorHeap* handle;
HRESULT result =
driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, reinterpret_cast<void**>(&handle));
if (FAILED(result))
{
LogError(driver->D3D12Device, "Failed to create descriptor heap!", result);
@@ -101,8 +103,10 @@ namespace Juliet::D3D12::Internal
if (heap->FreeIndicesCount >= heap->FreeIndicesCapacity)
{
size_t oldCapacity = heap->FreeIndicesCapacity;
heap->FreeIndicesCapacity *= 2;
heap->FreeIndices = static_cast<uint32*>(Realloc(heap->FreeIndices, heap->FreeIndicesCapacity * sizeof(uint32)));
heap->FreeIndices = ArenaRealloc<uint32>(GetEngineArena(), heap->FreeIndices, oldCapacity,
heap->FreeIndicesCapacity, ConstString("FreeIndices"));
}
heap->FreeIndices[heap->FreeIndicesCount] = descriptor.Index;
@@ -111,62 +115,20 @@ namespace Juliet::D3D12::Internal
D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver, DescriptorHeapCreator creator)
{
D3D12DescriptorHeap* result;
D3D12DescriptorHeapPool* pool = &d3d12Driver->SamplerHeapPool;
uint32 count = GPUDriver::kSampler_HeapDescriptorCount;
if (pool->Count > 0)
{
result = pool->Heaps[pool->Count - 1];
pool->Count -= 1;
return pool->Heaps[pool->Count];
}
// 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)
else
{
if (pool->Heaps[i] == nullptr)
{
freeSlotIndex = i;
break;
}
result = creator(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GPUDriver::kSampler_HeapDescriptorCount, false);
}
if (freeSlotIndex == SIZE_MAX)
{
// No free slot, expand
size_t oldCapacity = pool->Capacity;
pool->Capacity = pool->Capacity == 0 ? 1 : pool->Capacity * 2;
pool->Heaps = ArenaRealloc<D3D12DescriptorHeap*>(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity,
ConstString("DescriptorHeapArray"));
// 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];
return result;
}
void ReturnSamplerHeapToPool(NonNullPtr<D3D12Driver> d3d12Driver, D3D12DescriptorHeap* heap)
@@ -176,40 +138,18 @@ namespace Juliet::D3D12::Internal
return;
}
Assert(heap->HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
D3D12DescriptorHeapPool* pool = &d3d12Driver->SamplerHeapPool;
heap->CurrentDescriptorIndex = 0;
// 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)
if (pool->Count >= pool->Capacity)
{
if (pool->Heaps[i] == heap)
{
heapIndex = i;
break;
}
size_t oldCapacity = pool->Capacity;
pool->Capacity *= 2;
pool->Heaps = ArenaRealloc(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity, ConstString("Heaps"));
}
if (heapIndex != SIZE_MAX)
{
D3D12DescriptorHeap* temp = pool->Heaps[pool->Count];
pool->Heaps[pool->Count] = pool->Heaps[heapIndex];
pool->Heaps[heapIndex] = temp;
pool->Heaps[pool->Count] = heap;
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

View File

@@ -742,13 +742,7 @@ namespace Juliet::D3D12
#endif
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

View File

@@ -1,7 +1,7 @@
#include <Graphics/D3D12/D3D12InternalTests.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
#include <Graphics/D3D12/D3D12InternalTests.h>
#if JULIET_DEBUG
@@ -9,136 +9,5 @@ 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.
printf("DescriptorHeapPool tests passed.\n");
}
}
} // namespace Juliet::D3D12::UnitTest
#endif

View File

@@ -4,6 +4,5 @@
#if JULIET_DEBUG
namespace Juliet::D3D12::UnitTest
{
void TestDescriptorHeapPool();
}
#endif

View File

@@ -52,8 +52,8 @@ namespace Juliet::D3D12
frameBufferWidth = Min(width, frameBufferWidth);
frameBufferHeight = Min(height, frameBufferHeight);
D3D12TextureSubresource* subresource = Internal::PrepareTextureSubresourceForWrite(
d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE);
D3D12TextureSubresource* subresource =
Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE);
DSV = subresource->DSVHandle.CpuHandle;
hasDSV = true;
@@ -67,9 +67,10 @@ namespace Juliet::D3D12
// TODO: Check if texture has stencil
// if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV,
clearFlags, depthStencilTargetInfo->ClearDepth,
depthStencilTargetInfo->ClearStencil, 0, nullptr);
d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags,
depthStencilTargetInfo->ClearDepth,
depthStencilTargetInfo->ClearStencil,
0, nullptr);
}
}
@@ -93,8 +94,7 @@ namespace Juliet::D3D12
clearColor[2] = colorTargetInfos[idx].ClearColor.B;
clearColor[3] = colorTargetInfos[idx].ClearColor.A;
d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv,
clearColor, 0, nullptr);
d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr);
}
RTVs[idx] = rtv;
@@ -119,8 +119,8 @@ namespace Juliet::D3D12
}
}
d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(
colorTargetInfoCount, RTVs, false, hasDSV ? &DSV : nullptr);
d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false,
hasDSV ? &DSV : nullptr);
// Set defaults graphics states
GraphicsViewPort defaultViewport;
@@ -191,8 +191,7 @@ namespace Juliet::D3D12
// Reset Depth Stencil state
if (d3d12CommandList->DepthStencilSubresource)
{
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
d3d12CommandList->DepthStencilSubresource,
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource,
D3D12_RESOURCE_STATE_DEPTH_WRITE);
d3d12CommandList->DepthStencilSubresource = nullptr;
}
@@ -232,12 +231,14 @@ namespace Juliet::D3D12
d3d12CommandList->CurrentGraphicsPipeline = pipeline;
// Set the Descriptor heap
if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr)
{
Internal::SetDescriptorHeaps(d3d12CommandList);
}
// Set the pipeline state
d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState);
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(
pipeline->RootSignature->Handle);
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle);
d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology(
JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]);
@@ -280,7 +281,6 @@ namespace Juliet::D3D12
// TODO : Last missing piece
// D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices,
numInstances, firstVertex, firstInstance);
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance);
}
} // namespace Juliet::D3D12

View File

@@ -41,8 +41,7 @@ namespace Juliet::D3D12
SwapChainComposition composition, NonNullPtr<D3D12TextureContainer> textureContainer, uint8 index)
{
ID3D12Resource* swapChainTexture = nullptr;
HRESULT result =
swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast<void**>(&swapChainTexture));
HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast<void**>(&swapChainTexture));
if (FAILED(result))
{
LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result);
@@ -161,15 +160,16 @@ namespace Juliet::D3D12
}
uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex();
HRESULT result =
windowData->SwapChain->GetBuffer(swapchainIndex, IID_ID3D12Resource, reinterpret_cast<void**>(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource));
HRESULT result = windowData->SwapChain->GetBuffer(
swapchainIndex, IID_ID3D12Resource,
reinterpret_cast<void**>(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource));
if (FAILED(result))
{
LogError(driver->D3D12Device, "Could not acquire swapchain", result);
return false;
}
// When the swap chain texture is acquired its time to present
// When the swap chain texture is acquired it's time to present
if (d3d12CommandList->PresentDataCount == d3d12CommandList->PresentDataCapacity)
{
d3d12CommandList->PresentDataCapacity += 1;
@@ -290,9 +290,9 @@ namespace Juliet::D3D12
swapChainFullscreenDesc.Windowed = true;
IDXGISwapChain1* swapChain = nullptr;
HRESULT result =
driver->DXGIFactory->CreateSwapChainForHwnd(static_cast<IUnknown*>(driver->GraphicsQueue),
windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain);
HRESULT result = driver->DXGIFactory->CreateSwapChainForHwnd(static_cast<IUnknown*>(driver->GraphicsQueue),
windowHandle, &swapChainDesc,
&swapChainFullscreenDesc, nullptr, &swapChain);
if (FAILED(result))
{
LogError(driver->D3D12Device, "Failed to create SwapChain", result);

View File

@@ -280,7 +280,6 @@ namespace Juliet
void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera)
{
if (!g_DebugState.Initialized)
{
return;
@@ -302,7 +301,8 @@ namespace Juliet
BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline);
// Pack VP matrix + buffer index into push constants
struct {
struct
{
Matrix vp;
uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes)
@@ -322,7 +322,8 @@ namespace Juliet
BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline);
// Pack VP matrix + buffer index into push constants
struct {
struct
{
Matrix vp;
uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes)

View File

@@ -173,7 +173,6 @@ void JulietApplication::Init()
CopyBuffer(initCmd, ConstantBuffer, TransferBuffer, 256);
TransitionBufferToReadable(initCmd, ConstantBuffer);
SubmitCommandLists(initCmd);
WaitUntilGPUIsIdle(GraphicsDevice);
}
}
@@ -284,7 +283,6 @@ void JulietApplication::Update()
ImGui::ShowDemoWindow();
#endif
// Debug display shapes - can be called from anywhere before engine flush
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);