Added missing functions to allow wait for swap chain.

Proper resource tracking to allow for destruction of graphics pipeline
Textures are tracked but not released so nothing has been done yet
various changes
This commit is contained in:
2025-03-13 23:07:01 -04:00
parent 84e1194f21
commit f01c8c3ccb
15 changed files with 333 additions and 88 deletions

View File

@@ -19,8 +19,16 @@ namespace Juliet
} \
while (0)
#define Unimplemented() \
do \
{ \
Juliet::JulietAssert("Unimplemented!"); \
} \
while (0)
#else
#define Assert(Expression)
#define Unimplemented()
#endif
extern void JULIET_API JulietAssert(const char* expression);

View File

@@ -93,6 +93,9 @@ namespace Juliet
// SwapChain
extern JULIET_API bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window,
Texture** swapChainTexture);
extern JULIET_API bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList,
NonNullPtr<Window> window, Texture** swapChainTexture);
extern JULIET_API bool WaitForSwapchain(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
// Command List

View File

@@ -24,16 +24,15 @@ namespace Juliet::D3D12
bool CreateAllocator(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandListBaseData> baseData,
D3D12_COMMAND_QUEUE_DESC queueDesc)
{
for (auto& buffer : baseData->Allocator)
HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
reinterpret_cast<void**>(&baseData->Allocator));
if (FAILED(result))
{
HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
reinterpret_cast<void**>(&buffer));
if (FAILED(result))
{
Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator");
return false;
}
Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator");
return false;
}
ID3D12CommandAllocator_Reset(baseData->Allocator);
return true;
}
@@ -43,6 +42,8 @@ namespace Juliet::D3D12
std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID);
// TODO: Factorize this. Flemme
// Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator
auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)];
switch (queueType)
{
@@ -63,6 +64,8 @@ namespace Juliet::D3D12
commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList;
ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str());
ID3D12GraphicsCommandList6_Reset(d3d12GraphicsCommandList, commandList->GraphicsCommandList.Allocator, nullptr);
return true;
}
case QueueType::Compute:
@@ -82,6 +85,8 @@ namespace Juliet::D3D12
commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList;
ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str());
ID3D12GraphicsCommandList6_Reset(d3d12GraphicsCommandList, commandList->ComputeCommandList.Allocator, nullptr);
return true;
}
case QueueType::Copy:
@@ -99,6 +104,8 @@ namespace Juliet::D3D12
}
commandList->CopyCommandList.CommandList = d3d12CopyCommandList;
ID3D12GraphicsCommandList_SetName(d3d12CopyCommandList, wide_str.c_str());
ID3D12GraphicsCommandList_Reset(d3d12CopyCommandList, commandList->CopyCommandList.Allocator, nullptr);
return true;
}
default: return false;
@@ -136,11 +143,23 @@ namespace Juliet::D3D12
commandList->ID = id;
commandList->Driver = driver;
// Window Handling
commandList->PresentDataCapacity = 1;
commandList->PresentDataCount = 0;
commandList->PresentDatas =
static_cast<D3D12PresentData*>(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData)));
// Resource tracking
commandList->UsedTextureCapacity = 4;
commandList->UsedTextureCount = 0;
commandList->UsedTextures =
static_cast<D3D12Texture**>(Calloc(commandList->UsedTextureCapacity, sizeof(D3D12Texture*)));
commandList->UsedGraphicsPipelineCapacity = 4;
commandList->UsedGraphicsPipelineCount = 0;
commandList->UsedGraphicsPipelines = static_cast<D3D12GraphicsPipeline**>(
Calloc(commandList->UsedGraphicsPipelineCapacity, sizeof(D3D12GraphicsPipeline*)));
// TODO : Simplify this
if (!HasD3D12CommandListForQueueType(commandList, queueType))
{
@@ -178,34 +197,6 @@ namespace Juliet::D3D12
D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType);
// Get Proper allocator for the frame and reset both it and the requested queue
uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount;
switch (queueType)
{
case QueueType::Graphics:
{
auto* allocator = commandList->GraphicsCommandList.Allocator[bufferIndex];
ID3D12CommandAllocator_Reset(allocator);
ID3D12GraphicsCommandList6_Reset(commandList->GraphicsCommandList.CommandList, allocator, nullptr);
break;
}
case QueueType::Compute:
{
auto* allocator = commandList->ComputeCommandList.Allocator[bufferIndex];
ID3D12CommandAllocator_Reset(allocator);
ID3D12GraphicsCommandList6_Reset(commandList->ComputeCommandList.CommandList, allocator, nullptr);
break;
}
case QueueType::Copy:
{
auto* allocator = commandList->CopyCommandList.Allocator[bufferIndex];
ID3D12CommandAllocator_Reset(allocator);
ID3D12GraphicsCommandList6_Reset(commandList->CopyCommandList.CommandList, allocator, nullptr);
break;
}
default: Assert(false && "Unsupported QueueType"); return nullptr;
}
commandList->AutoReleaseFence = true;
return reinterpret_cast<CommandList*>(commandList);
@@ -384,15 +375,11 @@ namespace Juliet::D3D12
ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList);
}
for (auto* allocator : commandList->GraphicsCommandList.Allocator)
{
if (allocator)
{
ID3D12CommandAllocator_Release(allocator);
}
}
ID3D12CommandAllocator_Release(commandList->GraphicsCommandList.Allocator);
SafeFree(commandList->PresentDatas);
SafeFree(commandList->UsedTextures);
SafeFree(commandList->UsedGraphicsPipelines);
Free(commandList.Get());
}
@@ -401,6 +388,34 @@ namespace Juliet::D3D12
// No more presentation data
commandList->PresentDataCount = 0;
HRESULT result = ID3D12CommandAllocator_Reset(commandList->GraphicsCommandList.Allocator);
if (FAILED(result))
{
LogError(driver, "Could not reset command allocator", result);
return false;
}
result = ID3D12GraphicsCommandList_Reset(commandList->GraphicsCommandList.CommandList,
commandList->GraphicsCommandList.Allocator, NULL);
if (FAILED(result))
{
LogError(driver, "Could not reset command list", result);
return false;
}
// Clean up resource tracking
for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx)
{
--commandList->UsedTextures[idx]->ReferenceCount;
}
commandList->UsedTextureCount = 0;
for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx)
{
--commandList->UsedGraphicsPipelines[idx]->ReferenceCount;
}
commandList->UsedGraphicsPipelineCount = 0;
// Release Fence if needed
if (commandList->AutoReleaseFence)
{
@@ -434,5 +449,35 @@ namespace Juliet::D3D12
return true;
}
#define TRACK_RESOURCE(resource, type, array, count, capacity) \
uint32 i; \
\
for (i = 0; i < commandList->count; i += 1) \
{ \
if (commandList->array[i] == (resource)) \
{ \
return; \
} \
} \
\
if (commandList->count == commandList->capacity) \
{ \
commandList->capacity += 1; \
commandList->array = (type*)Realloc(commandList->array, commandList->capacity * sizeof(type)); \
} \
commandList->array[commandList->count] = resource; \
commandList->count += 1; \
++(resource)->ReferenceCount;
void TrackGraphicsPipeline(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12GraphicsPipeline> pipeline)
{
TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity)
}
void TrackTexture(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture)
{
TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity)
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -11,12 +11,13 @@ namespace Juliet::D3D12
// Forward Declare
struct D3D12Driver;
struct D3D12Fence;
struct D3D12Texture;
struct D3D12TextureSubresource;
struct D3D12WindowData;
struct D3D12CommandListBaseData
{
ID3D12CommandAllocator* Allocator[GPUDriver::kResourceBufferCount];
ID3D12CommandAllocator* Allocator;
};
struct D3D12CopyCommandListData : D3D12CommandListBaseData
@@ -70,8 +71,17 @@ namespace Juliet::D3D12
bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage];
bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage];
//D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
//D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
// D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
// D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
// Resource Tracking
D3D12Texture** UsedTextures;
uint32 UsedTextureCount;
uint32 UsedTextureCapacity;
D3D12GraphicsPipeline** UsedGraphicsPipelines;
uint32 UsedGraphicsPipelineCount;
uint32 UsedGraphicsPipelineCapacity;
};
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
@@ -85,5 +95,8 @@ namespace Juliet::D3D12
{
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
extern bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel);
extern void TrackGraphicsPipeline(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12GraphicsPipeline> pipeline);
extern void TrackTexture(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -310,6 +310,7 @@ namespace Juliet::D3D12
// Clean allocations
SafeFree(driver->AvailableCommandLists);
SafeFree(driver->SubmittedCommandLists);
SafeFree(driver->GraphicsPipelinesToDispose);
// Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now
SafeFree(driver->AvailableFences);
@@ -709,6 +710,20 @@ namespace Juliet::D3D12
}
}
// Deferred dispose vectors
driver->GraphicsPipelinesToDisposeCapacity = 4;
driver->GraphicsPipelinesToDisposeCount = 0;
driver->GraphicsPipelinesToDispose = static_cast<D3D12GraphicsPipeline**>(
Calloc(driver->GraphicsPipelinesToDisposeCapacity, sizeof(D3D12GraphicsPipeline*)));
if (!driver->GraphicsPipelinesToDispose)
{
DestroyDriver_Internal(driver);
return nullptr;
}
driver->Semantic = WrapString("TEXCOORD");
driver->FramesInFlight = 2;
auto device = static_cast<GraphicsDevice*>(Calloc(1, sizeof(GraphicsDevice)));
if (!device)
{
@@ -717,36 +732,35 @@ namespace Juliet::D3D12
}
// Assign Functions to the device
device->DestroyDevice = DestroyGraphicsDevice;
device->AttachToWindow = AttachToWindow;
device->DetachFromWindow = DetachFromWindow;
device->AcquireSwapChainTexture = AcquireSwapChainTexture;
device->GetSwapChainTextureFormat = GetSwapChainTextureFormat;
device->AcquireCommandList = AcquireCommandList;
device->SubmitCommandLists = SubmitCommandLists;
device->BeginRenderPass = BeginRenderPass;
device->EndRenderPass = EndRenderPass;
device->SetViewPort = SetViewPort;
device->SetScissorRect = SetScissorRect;
device->SetBlendConstants = SetBlendConstants;
device->SetStencilReference = SetStencilReference;
device->BindGraphicsPipeline = BindGraphicsPipeline;
device->DrawPrimitives = DrawPrimitives;
device->Wait = Wait;
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
device->CreateShader = CreateShader;
device->DestroyShader = DestroyShader;
device->CreateGraphicsPipeline = CreateGraphicsPipeline;
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
device->DestroyDevice = DestroyGraphicsDevice;
device->AttachToWindow = AttachToWindow;
device->DetachFromWindow = DetachFromWindow;
device->AcquireSwapChainTexture = AcquireSwapChainTexture;
device->WaitAndAcquireSwapChainTexture = WaitAndAcquireSwapChainTexture;
device->GetSwapChainTextureFormat = GetSwapChainTextureFormat;
device->AcquireCommandList = AcquireCommandList;
device->SubmitCommandLists = SubmitCommandLists;
device->BeginRenderPass = BeginRenderPass;
device->EndRenderPass = EndRenderPass;
device->SetViewPort = SetViewPort;
device->SetScissorRect = SetScissorRect;
device->SetBlendConstants = SetBlendConstants;
device->SetStencilReference = SetStencilReference;
device->BindGraphicsPipeline = BindGraphicsPipeline;
device->DrawPrimitives = DrawPrimitives;
device->Wait = Wait;
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
device->CreateShader = CreateShader;
device->DestroyShader = DestroyShader;
device->CreateGraphicsPipeline = CreateGraphicsPipeline;
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
device->Driver = driver;
device->DebugEnabled = enableDebug;
device->Driver = driver;
driver->GraphicsDevice = device;
driver->Semantic = WrapString("TEXCOORD");
driver->FramesInFlight = 2;
return device;
}
} // namespace
@@ -758,7 +772,7 @@ namespace Juliet::D3D12
// TODO Destroy anything (buffer, texture, etc...)
for (int32 idx = driver->GraphicsPipelinesToDisposeCount - 1; idx >= 0; --idx)
{
if ((--(driver->GraphicsPipelinesToDispose[idx]->ReferenceCount)) == 0)
if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0)
{
ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]);

View File

@@ -70,7 +70,7 @@ namespace Juliet::D3D12
RTVs[idx] = rtv;
d3d12CommandList->ColorTargetSubresources[idx] = subresource;
// TODO: TrackTexture
Internal::TrackTexture(d3d12CommandList, subresource->Parent);
if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve ||
colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore)
@@ -85,7 +85,7 @@ namespace Juliet::D3D12
d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource;
// TODO: TrackTexture Resolve
Internal::TrackTexture(d3d12CommandList, resolveSubresource->Parent);
}
}
@@ -233,6 +233,8 @@ namespace Juliet::D3D12
// d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer);
// }
}
Internal::TrackGraphicsPipeline(d3d12CommandList, pipeline);
}
void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance)

View File

@@ -10,6 +10,7 @@
#include <Graphics/D3D12/D3D12Utils.h>
#include <algorithm>
#include <D3D12Synchronization.h>
namespace Juliet::D3D12
{
@@ -56,7 +57,7 @@ namespace Juliet::D3D12
return false;
}
texture->RefCount += 1;
texture->ReferenceCount += 1;
texture->SubresourceCount = 1;
texture->Subresources = static_cast<D3D12TextureSubresource*>(Calloc(1, sizeof(D3D12TextureSubresource)));
if (!texture->Subresources)
@@ -145,8 +146,30 @@ namespace Juliet::D3D12
auto* windowData = driver->WindowData;
Assert(windowData->Window == window.Get());
// TODO : FENCES
Assert(!block);
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
{
if (block)
{
// Wait until the fence for the frame is signaled.
// In VSYNC this means waiting that the least recent presented frame is done
if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], 1))
{
return false;
}
}
else
{
// If work is not done, the least recent fence wont be signaled.
// In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture
if (!QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter]))
{
return true;
}
}
ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter]);
windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr;
}
uint32 swapchainIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(windowData->SwapChain);
HRESULT result =
@@ -192,6 +215,32 @@ namespace Juliet::D3D12
return AcquireSwapChainTexture(false, commandList, window, swapChainTexture);
}
bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
{
return AcquireSwapChainTexture(true, commandList, window, swapChainTexture);
}
bool WaitForSwapchain(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
auto* windowData = d3d12Driver->WindowData;
if (!windowData)
{
LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain");
return false;
}
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
{
if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], 1))
{
return false;
}
}
return true;
}
TextureFormat GetSwapChainTextureFormat(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());

View File

@@ -8,7 +8,9 @@ namespace Juliet::D3D12
struct D3D12WindowData;
extern bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
extern TextureFormat GetSwapChainTextureFormat(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
extern bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
extern bool WaitForSwapchain(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
extern TextureFormat GetSwapChainTextureFormat(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
namespace Internal
{

View File

@@ -61,7 +61,7 @@ namespace Juliet::D3D12
bool result = true;
// Clean up
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; idx -= 1)
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx)
{
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
}
@@ -71,8 +71,54 @@ namespace Juliet::D3D12
return result;
}
bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences)
{
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
// TODO: use scratch allocator for alloca (stack alloc)
auto events = static_cast<HANDLE*>(alloca(sizeof(HANDLE) * numFences));
for (uint32 i = 0; i < numFences; ++i)
{
auto fence = reinterpret_cast<D3D12Fence*>(fences[i]);
HRESULT res = ID3D12Fence_SetEventOnCompletion(fence->Handle, D3D12_FENCE_SIGNAL_VALUE, fence->Event);
if (FAILED(res))
{
LogError(d3d12driver, "Setting fence event failed!", res);
return false;
}
events[i] = fence->Event;
}
DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE);
if (waitResult == WAIT_FAILED)
{
LogError(LogCategory::Graphics, "Wait failed");
return false;
}
bool result = true;
// Clean up
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx -= 1)
{
uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle);
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
{
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
}
}
Internal::DisposePendingResourcces(d3d12driver);
return result;
}
bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
{
Unimplemented();
return true;
}

View File

@@ -26,6 +26,7 @@ namespace Juliet::D3D12
};
extern bool Wait(NonNullPtr<GPUDriver> driver);
extern bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences);
extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);

View File

@@ -276,7 +276,7 @@ namespace Juliet::D3D12
D3D12_RESOURCE_STATES newTextureUsage)
{
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level);
if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0)
if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0)
{
// TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective)
// CycleActiveTexture(commandList->Driver, container);

View File

@@ -59,7 +59,7 @@ namespace Juliet::D3D12
D3D12StagingDescriptor SRVHandle;
// TODO: Should be atomic to support multithreading
int32 RefCount;
int32 ReferenceCount;
};
namespace Internal

View File

@@ -79,6 +79,27 @@ namespace Juliet
{
auto header = reinterpret_cast<CommandListHeader*>(commandList.Get());
if (header->Device->DebugEnabled)
{
bool error = false;
if (header->Submitted)
{
error = true;
Assert(false && "Cannot submit command list twice");
}
if (header->RenderPass.IsInProgress)
{
error = true;
Assert(false && "Cannot submit command list twice");
}
if (error)
{
return false;
}
}
header->Device->AcquireSwapChainTexture(commandList, window, swapChainTexture);
if (swapChainTexture)
{
@@ -88,6 +109,45 @@ namespace Juliet
return true;
}
bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
{
auto header = reinterpret_cast<CommandListHeader*>(commandList.Get());
if (header->Device->DebugEnabled)
{
bool error = false;
if (header->Submitted)
{
error = true;
Assert(false && "Cannot submit command list twice");
}
if (header->RenderPass.IsInProgress)
{
error = true;
Assert(false && "Cannot submit command list twice");
}
if (error)
{
return false;
}
}
header->Device->WaitAndAcquireSwapChainTexture(commandList, window, swapChainTexture);
if (swapChainTexture)
{
header->AcquiredSwapChain = true;
}
return true;
}
bool WaitForSwapchain(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
{
return device->WaitForSwapchain(device->Driver, window);
}
TextureFormat GetSwapChainTextureFormat(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
{
return device->GetSwapChainTextureFormat(device->Driver, window);
@@ -105,6 +165,7 @@ namespace Juliet
auto header = reinterpret_cast<CommandListHeader*>(cmdList);
header->Device = device.Get();
header->RenderPass.CommandList = cmdList;
header->Submitted = false;
return cmdList;
}
@@ -181,7 +242,7 @@ namespace Juliet
commandListHeader->Device->SetStencilReference(commandList, reference);
}
void BindGraphicsPipeline(NonNullPtr<RenderPass> renderPass, NonNullPtr<GraphicsPipeline> graphicsPipeline)
void BindGraphicsPipeline(NonNullPtr<RenderPass> renderPass, NonNullPtr<GraphicsPipeline> graphicsPipeline)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
@@ -189,8 +250,7 @@ namespace Juliet
commandListHeader->Device->BindGraphicsPipeline(commandList, graphicsPipeline);
}
void DrawPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numVertices, uint32 numInstances,
uint32 firstVertex, uint32 firstInstance)
void DrawPrimitives(NonNullPtr<RenderPass> renderPass, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);

View File

@@ -30,7 +30,6 @@ namespace Juliet
struct GPUDriver
{
static constexpr uint8 kResourceBufferCount = 2;
static constexpr uint8 kMaxFramesInFlight = 3;
static constexpr uint8 kMaxColorTargetInfo = 4;
static constexpr uint8 kMaxUniformBuffersPerStage = 4;
@@ -47,6 +46,8 @@ namespace Juliet
// SwapChain
bool (*AcquireSwapChainTexture)(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
bool (*WaitAndAcquireSwapChainTexture)(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
bool (*WaitForSwapchain)(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
TextureFormat (*GetSwapChainTextureFormat)(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
// CommandLists
@@ -82,6 +83,7 @@ namespace Juliet
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;
bool DebugEnabled : 1;
};
struct GraphicsDeviceFactory

View File

@@ -188,7 +188,7 @@ void JulietApplication::Update()
}
Texture* swapChainTexture = nullptr;
if (!AcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture))
if (!WaitAndAcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture))
{
Log(LogLevel::Error, LogCategory::Tool, "Failed to acquire swapchain texture.");
Running = false;