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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Juliet::D3D12
|
||||
D3D12StagingDescriptor SRVHandle;
|
||||
|
||||
// TODO: Should be atomic to support multithreading
|
||||
int32 RefCount;
|
||||
int32 ReferenceCount;
|
||||
};
|
||||
|
||||
namespace Internal
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user