Finishing fences

+ moved some functions to an internal namespace to tidy stuff a bit
This commit is contained in:
2025-02-19 22:01:39 -05:00
parent cc9bbf0ef5
commit 8326772558
14 changed files with 683 additions and 485 deletions

View File

@@ -26,7 +26,7 @@ namespace Juliet::D3D12
bool ExtendStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptorPool& pool) bool ExtendStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptorPool& pool)
{ {
D3D12DescriptorHeap* heap = D3D12DescriptorHeap* heap =
CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
if (!heap) if (!heap)
{ {
return false; return false;
@@ -47,122 +47,126 @@ namespace Juliet::D3D12
} }
} // namespace } // namespace
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging) namespace Internal
{ {
ID3D12DescriptorHeap* handle; D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32 count, bool isStaging)
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
{ {
return nullptr; ID3D12DescriptorHeap* handle;
}
heap->CurrentDescriptorIndex = 0; auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
D3D12_DESCRIPTOR_HEAP_DESC heapDesc;
heapDesc.NumDescriptors = count;
heapDesc.Type = type;
heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
heapDesc.NodeMask = 0;
HRESULT result =
ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle);
if (FAILED(result))
{
LogError(driver, "Failed to create descriptor heap!", result);
DestroyDescriptorHeap(heap);
return nullptr;
}
heap->Handle = handle;
heap->HeapType = type;
heap->MaxDescriptors = count;
heap->Staging = isStaging;
heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type);
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart);
if (!isStaging)
{
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart);
}
return heap;
}
void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap)
{
if (heap->Handle)
{
ID3D12DescriptorHeap_Release(heap->Handle);
}
Free(heap.Get());
}
D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type)
{
D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return nullptr;
}
auto pool = static_cast<D3D12StagingDescriptorPool*>(Calloc(1, sizeof(D3D12StagingDescriptorPool)));
// First create the heaps
pool->HeapCount = 1;
pool->Heaps = static_cast<D3D12DescriptorHeap**>(Malloc(sizeof(D3D12DescriptorHeap*)));
pool->Heaps[0] = heap;
pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptors =
static_cast<D3D12StagingDescriptor*>(Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor)));
InitStagingDescriptorPool(heap, pool);
return pool;
}
bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor)
{
// TODO: Make it thread safe
D3D12StagingDescriptor* descriptor = nullptr;
D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type];
if (pool->FreeDescriptorCount == 0)
{
if (!ExtendStagingDescriptorPool(driver, *pool))
{ {
return false; return nullptr;
}
heap->CurrentDescriptorIndex = 0;
D3D12_DESCRIPTOR_HEAP_DESC heapDesc;
heapDesc.NumDescriptors = count;
heapDesc.Type = type;
heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
heapDesc.NodeMask = 0;
HRESULT result =
ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle);
if (FAILED(result))
{
LogError(driver, "Failed to create descriptor heap!", result);
DestroyDescriptorHeap(heap);
return nullptr;
}
heap->Handle = handle;
heap->HeapType = type;
heap->MaxDescriptors = count;
heap->Staging = isStaging;
heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type);
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart);
if (!isStaging)
{
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart);
}
return heap;
}
void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap)
{
if (heap->Handle)
{
ID3D12DescriptorHeap_Release(heap->Handle);
}
Free(heap.Get());
}
D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type)
{
D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return nullptr;
}
auto pool = static_cast<D3D12StagingDescriptorPool*>(Calloc(1, sizeof(D3D12StagingDescriptorPool)));
// First create the heaps
pool->HeapCount = 1;
pool->Heaps = static_cast<D3D12DescriptorHeap**>(Malloc(sizeof(D3D12DescriptorHeap*)));
pool->Heaps[0] = heap;
pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptors = static_cast<D3D12StagingDescriptor*>(
Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor)));
InitStagingDescriptorPool(heap, pool);
return pool;
}
bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor)
{
// TODO: Make it thread safe
D3D12StagingDescriptor* descriptor = nullptr;
D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type];
if (pool->FreeDescriptorCount == 0)
{
if (!ExtendStagingDescriptorPool(driver, *pool))
{
return false;
}
}
descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1];
MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount -= 1;
return true;
}
void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor)
{
D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool;
if (pool != nullptr)
{
MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount += 1;
} }
} }
descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1]; void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool)
MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount -= 1;
return true;
}
void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor)
{
D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool;
if (pool != nullptr)
{ {
MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); for (uint32 i = 0; i < pool->HeapCount; i += 1)
pool->FreeDescriptorCount += 1; {
} DestroyDescriptorHeap(pool->Heaps[i]);
} }
void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool) Free(pool->Heaps);
{ Free(pool->FreeDescriptors);
for (uint32 i = 0; i < pool->HeapCount; i += 1) Free(pool.Get());
{
DestroyDescriptorHeap(pool->Heaps[i]);
} }
} // namespace Internal
Free(pool->Heaps);
Free(pool->FreeDescriptors);
Free(pool.Get());
}
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -51,13 +51,16 @@ namespace Juliet::D3D12
uint32 CpuHandleIndex; uint32 CpuHandleIndex;
}; };
extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, namespace Internal
uint32 count, bool isStaging); {
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap); extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver,
D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging);
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap);
extern D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type); extern D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type);
extern bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, extern bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12StagingDescriptor& outDescriptor); D3D12StagingDescriptor& outDescriptor);
extern void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor); extern void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor);
extern void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool); extern void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool);
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -31,7 +31,7 @@ namespace Juliet::D3D12
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
{ {
auto* container = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].TargetTexture); auto* container = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].TargetTexture);
D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite( D3D12TextureSubresource* subresource = Internal::PrepareTextureSubresourceForWrite(
d3d12CommandList, container, d3d12CommandList, container,
container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex, container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex,
colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET); colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET);
@@ -61,9 +61,11 @@ namespace Juliet::D3D12
{ {
auto resolveContainer = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].ResolveTexture); auto resolveContainer = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].ResolveTexture);
D3D12TextureSubresource* resolveSubresource = D3D12TextureSubresource* resolveSubresource =
PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, colorTargetInfos[idx].ResolveLayerIndex, Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer,
colorTargetInfos[idx].ResolveMipLevel, colorTargetInfos[idx].CycleResolveTexture, colorTargetInfos[idx].ResolveLayerIndex,
D3D12_RESOURCE_STATE_RESOLVE_DEST); colorTargetInfos[idx].ResolveMipLevel,
colorTargetInfos[idx].CycleResolveTexture,
D3D12_RESOURCE_STATE_RESOLVE_DEST);
d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource;
@@ -114,27 +116,31 @@ namespace Juliet::D3D12
{ {
if (d3d12CommandList->ColorResolveSubresources[idx]) if (d3d12CommandList->ColorResolveSubresources[idx])
{ {
TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, Internal::TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET,
d3d12CommandList->ColorTargetSubresources[idx]); D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
d3d12CommandList->ColorTargetSubresources[idx]);
ID3D12GraphicsCommandList_ResolveSubresource( ID3D12GraphicsCommandList_ResolveSubresource(
d3d12CommandList->GraphicsCommandList.CommandList, d3d12CommandList->GraphicsCommandList.CommandList,
d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource,
d3d12CommandList->ColorResolveSubresources[idx]->Index, d3d12CommandList->ColorResolveSubresources[idx]->Index,
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource,
d3d12CommandList->ColorTargetSubresources[idx]->Index, d3d12CommandList->ColorTargetSubresources[idx]->Index,
ConvertToD3D12TextureFormat( Internal::ConvertToD3D12TextureFormat(
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format));
TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE); d3d12CommandList->ColorTargetSubresources[idx],
D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorResolveSubresources[idx], Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
D3D12_RESOURCE_STATE_RESOLVE_DEST); d3d12CommandList->ColorResolveSubresources[idx],
D3D12_RESOURCE_STATE_RESOLVE_DEST);
} }
else else
{ {
TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
D3D12_RESOURCE_STATE_RENDER_TARGET); d3d12CommandList->ColorTargetSubresources[idx],
D3D12_RESOURCE_STATE_RENDER_TARGET);
} }
} }
} }

View File

@@ -8,91 +8,171 @@
namespace Juliet::D3D12 namespace Juliet::D3D12
{ {
void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState, namespace
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier)
{ {
D3D12_RESOURCE_BARRIER barrierDesc[2]; void ReleaseFenceToPool(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12Fence> fence)
uint32 numBarriers = 0;
// No transition barrier is needed if the state is not changing.
if (sourceState != destinationState)
{ {
barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; if (driver->AvailableFenceCount + 1 >= driver->AvailableFenceCapacity)
barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0); {
barrierDesc[numBarriers].Transition.StateBefore = sourceState; driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2;
barrierDesc[numBarriers].Transition.StateAfter = destinationState; driver->AvailableFences = static_cast<D3D12Fence**>(
barrierDesc[numBarriers].Transition.pResource = resource; Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity));
barrierDesc[numBarriers].Transition.Subresource = subresourceIndex; }
driver->AvailableFences[driver->AvailableFenceCount] = fence;
driver->AvailableFenceCount += 1;
}
} // namespace
numBarriers += 1; bool Wait(NonNullPtr<GPUDriver> driver)
{
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
D3D12Fence* fence = Internal::AcquireFence(d3d12driver);
if (!fence)
{
return false;
} }
if (needsUavBarrier) if (d3d12driver->GraphicsQueue)
{ {
barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; // Insert a signal into the end of the command queue...
barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0); ID3D12CommandQueue_Signal(d3d12driver->GraphicsQueue, fence->Handle, D3D12_FENCE_SIGNAL_VALUE);
barrierDesc[numBarriers].UAV.pResource = resource;
numBarriers += 1; // ...and then block on it.
if (ID3D12Fence_GetCompletedValue(fence->Handle) != D3D12_FENCE_SIGNAL_VALUE)
{
HRESULT result = ID3D12Fence_SetEventOnCompletion(fence->Handle, D3D12_FENCE_SIGNAL_VALUE, fence->Event);
if (FAILED(result))
{
LogError(d3d12driver, "Setting fence event failed!", result);
return false;
}
DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE);
if (waitResult == WAIT_FAILED)
{
LogError(d3d12driver, "Wait failed!", result);
return false;
}
}
} }
if (numBarriers > 0) ReleaseFence(driver, reinterpret_cast<Fence*>(fence));
bool result = true;
// Clean up
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; idx -= 1)
{ {
ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc); result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
}
return result;
}
bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
{
return true;
}
void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
{
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
auto d3d12Fence = reinterpret_cast<D3D12Fence*>(fence.Get());
if (--d3d12Fence->ReferenceCount == 0)
{
ReleaseFenceToPool(d3d12driver, d3d12Fence);
} }
} }
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver) namespace Internal
{ {
D3D12Fence* fence; void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
ID3D12Fence* handle; D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex,
bool needsUavBarrier)
// TODO :Thread safe (lock + atomic)
if (driver->AvailableFenceCount == 0)
{ {
HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, D3D12_RESOURCE_BARRIER barrierDesc[2];
IID_ID3D12Fence, reinterpret_cast<void**>(&handle)); uint32 numBarriers = 0;
if (FAILED(result))
// No transition barrier is needed if the state is not changing.
if (sourceState != destinationState)
{ {
LogError(driver, "Failed to create fence!", result); barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
return nullptr; barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0);
barrierDesc[numBarriers].Transition.StateBefore = sourceState;
barrierDesc[numBarriers].Transition.StateAfter = destinationState;
barrierDesc[numBarriers].Transition.pResource = resource;
barrierDesc[numBarriers].Transition.Subresource = subresourceIndex;
numBarriers += 1;
} }
fence = static_cast<D3D12Fence*>(Calloc(1, sizeof(D3D12Fence))); if (needsUavBarrier)
if (!fence)
{ {
ID3D12Fence_Release(handle); barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0);
barrierDesc[numBarriers].UAV.pResource = resource;
return nullptr; numBarriers += 1;
}
if (numBarriers > 0)
{
ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc);
} }
fence->Handle = handle;
fence->Event = CreateEvent(nullptr, false, false, nullptr);
fence->ReferenceCount = 0;
} }
else
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver)
{ {
fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; D3D12Fence* fence;
driver->AvailableFenceCount -= 1; ID3D12Fence* handle;
ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE);
// TODO :Thread safe (lock + atomic)
if (driver->AvailableFenceCount == 0)
{
HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
if (FAILED(result))
{
LogError(driver, "Failed to create fence!", result);
return nullptr;
}
fence = static_cast<D3D12Fence*>(Calloc(1, sizeof(D3D12Fence)));
if (!fence)
{
ID3D12Fence_Release(handle);
return nullptr;
}
fence->Handle = handle;
fence->Event = CreateEvent(nullptr, false, false, nullptr);
fence->ReferenceCount = 0;
}
else
{
fence = driver->AvailableFences[driver->AvailableFenceCount - 1];
driver->AvailableFenceCount -= 1;
ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE);
}
fence->ReferenceCount += 1;
return fence;
} }
fence->ReferenceCount += 1; void DestroyFence(NonNullPtr<D3D12Fence> fence)
return fence;
}
void DestroyFence(NonNullPtr<D3D12Fence> fence)
{
if (fence->Handle)
{ {
ID3D12Fence_Release(fence->Handle); if (fence->Handle)
} {
ID3D12Fence_Release(fence->Handle);
}
if (fence->Event) if (fence->Event)
{ {
CloseHandle(fence->Event); CloseHandle(fence->Event);
}
Free(fence.Get());
} }
Free(fence.Get()); } // namespace Internal
}
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -2,6 +2,13 @@
#include <Core/Common/NonNullPtr.h> #include <Core/Common/NonNullPtr.h>
#include <Graphics/D3D12/D3D12Common.h> #include <Graphics/D3D12/D3D12Common.h>
#include <Graphics/GraphicsDevice.h>
namespace Juliet
{
struct Fence;
struct GPUDriver;
} // namespace Juliet
namespace Juliet::D3D12 namespace Juliet::D3D12
{ {
@@ -18,10 +25,17 @@ namespace Juliet::D3D12
int32 ReferenceCount; // TODO : Atomic int32 ReferenceCount; // TODO : Atomic
}; };
extern void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState, extern bool Wait(NonNullPtr<GPUDriver> driver);
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
uint32 subresourceIndex, bool needsUavBarrier); extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
extern D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver); namespace Internal
extern void DestroyFence(NonNullPtr<D3D12Fence> fence); {
extern void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource,
uint32 subresourceIndex, bool needsUavBarrier);
extern D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver);
extern void DestroyFence(NonNullPtr<D3D12Fence> fence);
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -157,79 +157,84 @@ namespace Juliet::D3D12
} }
} // namespace } // namespace
D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList, namespace Internal
NonNullPtr<D3D12TextureContainer> container, uint32 layer,
uint32 level, bool shouldCycle, D3D12_RESOURCE_STATES newTextureUsage)
{ {
D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level); D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList,
if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0) NonNullPtr<D3D12TextureContainer> container,
uint32 layer, uint32 level, bool shouldCycle,
D3D12_RESOURCE_STATES newTextureUsage)
{ {
// TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level);
// CycleActiveTexture(commandList->Driver, container); if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0)
{
// TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective)
// CycleActiveTexture(commandList->Driver, container);
subresource = FetchTextureSubresource(container, layer, level); subresource = Internal::FetchTextureSubresource(container, layer, level);
}
Internal::TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage);
return subresource;
} }
TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container, uint32 layer, uint32 level)
return subresource;
}
D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container, uint32 layer, uint32 level)
{
uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount);
return &container->ActiveTexture->Subresources[index];
}
void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, NonNullPtr<D3D12TextureSubresource> textureSubresource)
{
TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags;
bool needsUAVBarrier = ((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) ||
((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None);
ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource,
textureSubresource->Index, needsUAVBarrier);
}
void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES toTextureUsage)
{
D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource);
}
void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
D3D12_RESOURCE_STATES toTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{ {
TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount);
return &container->ActiveTexture->Subresources[index];
} }
}
void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
NonNullPtr<D3D12TextureSubresource> subresource, D3D12_RESOURCE_STATES fromTextureUsage) D3D12_RESOURCE_STATES destinationState, NonNullPtr<D3D12TextureSubresource> textureSubresource)
{
D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource);
}
void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
D3D12_RESOURCE_STATES fromTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{ {
TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags;
bool needsUAVBarrier =
((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) ||
((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None);
Internal::ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource,
textureSubresource->Index, needsUAVBarrier);
} }
}
// Utils void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) NonNullPtr<D3D12TextureSubresource> subresource,
{ D3D12_RESOURCE_STATES toTextureUsage)
return JulietToD3D12_TextureFormat[ToUnderlying(format)]; {
} D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource);
}
void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES toTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{
TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage);
}
}
void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES fromTextureUsage)
{
D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource);
}
void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
D3D12_RESOURCE_STATES fromTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{
TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage);
}
}
// Utils
DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format)
{
return JulietToD3D12_TextureFormat[ToUnderlying(format)];
}
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -62,27 +62,31 @@ namespace Juliet::D3D12
int32 RefCount; int32 RefCount;
}; };
extern D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList>, namespace Internal
NonNullPtr<D3D12TextureContainer> container, {
uint32 layer, uint32 level, bool shouldCycle, extern D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList>,
D3D12_RESOURCE_STATES newTextureUsage); NonNullPtr<D3D12TextureContainer> container,
extern D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container, uint32 layer, uint32 level); uint32 layer, uint32 level, bool shouldCycle,
extern void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES newTextureUsage);
D3D12_RESOURCE_STATES destinationState, extern D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container,
NonNullPtr<D3D12TextureSubresource> textureSubresource); uint32 layer, uint32 level);
extern void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList,
D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES destinationState,
NonNullPtr<D3D12TextureSubresource> textureSubresource);
// Texture usage transition // Texture usage transition
extern void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList, extern void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource, NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES toTextureUsage); D3D12_RESOURCE_STATES toTextureUsage);
extern void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList, extern void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES toTextureUsage); NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES toTextureUsage);
extern void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, extern void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource, NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES fromTextureUsage); D3D12_RESOURCE_STATES fromTextureUsage);
extern void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, extern void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES fromTextureUsage); D3D12_RESOURCE_STATES fromTextureUsage);
// Utils // Utils
extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format); extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format);
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -10,7 +10,7 @@ namespace Juliet::D3D12
{ {
namespace namespace
{ {
bool HasD3D12CommandList(NonNullPtr<D3D12CommandList> commandList, QueueType queueType) bool HasD3D12CommandListForQueueType(NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
{ {
switch (queueType) switch (queueType)
{ {
@@ -37,7 +37,7 @@ namespace Juliet::D3D12
return true; return true;
} }
bool CreateD3D12CommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, QueueType queueType) bool CreateD3D12CommandListForQueueType(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
{ {
// TODO: String library // TODO: String library
std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID);
@@ -111,7 +111,7 @@ namespace Juliet::D3D12
if (!commandList) if (!commandList)
{ {
Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory");
DestroyCommandList(commandList); Internal::DestroyCommandList(commandList);
return false; return false;
} }
@@ -122,14 +122,18 @@ namespace Juliet::D3D12
{ {
Log(LogLevel::Error, LogCategory::Graphics, Log(LogLevel::Error, LogCategory::Graphics,
"Error not implemented, out of memory, handle that by deallocating stuff and returning false"); "Error not implemented, out of memory, handle that by deallocating stuff and returning false");
DestroyCommandList(commandList); Internal::DestroyCommandList(commandList);
return false; return false;
} }
driver->AvailableCommandLists = resizedArray; uint32 id = driver->AvailableCommandListCapacity;
driver->AvailableCommandLists[driver->AvailableCommandListCapacity] = commandList; driver->AvailableCommandListCapacity += 1;
driver->AvailableCommandLists = resizedArray;
commandList->ID = driver->AvailableCommandListCapacity; driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList;
driver->AvailableCommandListCount += 1;
commandList->ID = id;
commandList->Driver = driver; commandList->Driver = driver;
commandList->PresentDataCapacity = 1; commandList->PresentDataCapacity = 1;
@@ -137,35 +141,42 @@ namespace Juliet::D3D12
commandList->PresentDatas = commandList->PresentDatas =
static_cast<D3D12PresentData*>(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData))); static_cast<D3D12PresentData*>(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData)));
driver->AvailableCommandListCapacity += 1; // TODO : Simplify this
if (!HasD3D12CommandListForQueueType(commandList, queueType))
{
if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType))
{
Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list");
Internal::DestroyCommandList(commandList);
return false;
}
}
return true; return true;
} }
D3D12CommandList* AcquireCommandListFromPool(NonNullPtr<D3D12Driver> driver, QueueType queueType)
{
if (driver->AvailableCommandListCount == 0)
{
if (!AllocateCommandList(driver, queueType))
{
return nullptr;
}
}
D3D12CommandList* commandList = driver->AvailableCommandLists[driver->AvailableCommandListCount - 1];
driver->AvailableCommandListCount -= 1;
return commandList;
}
} // namespace } // namespace
CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType) CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType)
{ {
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get()); auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
uint8 currentCommandListIndex = d3d12Driver->AvailableCommandListCount; D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType);
if (currentCommandListIndex >= d3d12Driver->AvailableCommandListCapacity)
{
if (!AllocateCommandList(d3d12Driver, queueType))
{
return nullptr;
}
}
D3D12CommandList* commandList = d3d12Driver->AvailableCommandLists[currentCommandListIndex];
if (!HasD3D12CommandList(commandList, queueType))
{
if (!CreateD3D12CommandList(d3d12Driver, commandList, queueType))
{
Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list");
DestroyCommandList(commandList);
return nullptr;
}
}
// Get Proper allocator for the frame and reset both it and the requested queue // Get Proper allocator for the frame and reset both it and the requested queue
uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount; uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount;
@@ -195,7 +206,8 @@ namespace Juliet::D3D12
default: Assert(false && "Unsupported QueueType"); return nullptr; default: Assert(false && "Unsupported QueueType"); return nullptr;
} }
d3d12Driver->AvailableCommandListCount += 1; commandList->AutoReleaseFence = true;
return reinterpret_cast<CommandList*>(commandList); return reinterpret_cast<CommandList*>(commandList);
} }
@@ -212,7 +224,7 @@ namespace Juliet::D3D12
uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex;
D3D12TextureContainer* container = D3D12TextureContainer* container =
&d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex];
D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0); D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, 0, 0);
D3D12_RESOURCE_BARRIER barrierDesc; D3D12_RESOURCE_BARRIER barrierDesc;
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
@@ -248,7 +260,7 @@ namespace Juliet::D3D12
ID3D12CommandList_Release(commandLists[0]); ID3D12CommandList_Release(commandLists[0]);
// Acquire a fence and set it to the in-flight fence // Acquire a fence and set it to the in-flight fence
d3d12CommandList->InFlightFence = AcquireFence(d3d12Driver); d3d12CommandList->InFlightFence = Internal::AcquireFence(d3d12Driver);
if (!d3d12CommandList->InFlightFence) if (!d3d12CommandList->InFlightFence)
{ {
return false; return false;
@@ -263,16 +275,15 @@ namespace Juliet::D3D12
} }
// Mark the command list as submitted // Mark the command list as submitted
if (d3d12Driver->SubmittedCommandBufferCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) if (d3d12Driver->SubmittedCommandListCount + 1 >= d3d12Driver->SubmittedCommandListCapacity)
{ {
d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandBufferCount + 1; d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandListCount + 1;
d3d12Driver->SubmittedCommandLists = static_cast<D3D12CommandList**>( d3d12Driver->SubmittedCommandLists = static_cast<D3D12CommandList**>(
Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * d3d12Driver->SubmittedCommandListCapacity)); Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * d3d12Driver->SubmittedCommandListCapacity));
} }
d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList;
d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandBufferCount] = d3d12CommandList; d3d12Driver->SubmittedCommandListCount += 1;
d3d12Driver->SubmittedCommandBufferCount += 1;
bool success = true; bool success = true;
for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1)
@@ -308,19 +319,15 @@ namespace Juliet::D3D12
} }
// TODO : Correctly clean up and destroy // TODO : Correctly clean up and destroy
d3d12Driver->AvailableCommandListCount = 0;
// Check for cleanups // Check for cleanups
// for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { for (int32 i = d3d12Driver->SubmittedCommandListCount - 1; i >= 0; i -= 1)
// Uint64 fenceValue = ID3D12Fence_GetCompletedValue( {
// renderer->submittedCommandBuffers[i]->inFlightFence->handle); uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle);
// if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
// if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { {
// result &= D3D12_INTERNAL_CleanCommandBuffer( result &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
// renderer, }
// renderer->submittedCommandBuffers[i], }
// false);
// }
// }
// TODO Destroy anything (buffer, texture, etc...) // TODO Destroy anything (buffer, texture, etc...)
@@ -329,26 +336,6 @@ namespace Juliet::D3D12
return success; return success;
} }
void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList)
{
// TODO : Handle other kind of command list (copy compute)
if (commandList->GraphicsCommandList.CommandList)
{
ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList);
}
for (auto* allocator : commandList->GraphicsCommandList.Allocator)
{
if (allocator)
{
ID3D12CommandAllocator_Release(allocator);
}
}
Free(commandList->PresentDatas);
Free(commandList.Get());
}
void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort) void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort)
{ {
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get()); auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
@@ -386,4 +373,66 @@ namespace Juliet::D3D12
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get()); auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandList->GraphicsCommandList.CommandList, reference); ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandList->GraphicsCommandList.CommandList, reference);
} }
namespace Internal
{
void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList)
{
// TODO : Handle other kind of command list (copy compute)
if (commandList->GraphicsCommandList.CommandList)
{
ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList);
}
for (auto* allocator : commandList->GraphicsCommandList.Allocator)
{
if (allocator)
{
ID3D12CommandAllocator_Release(allocator);
}
}
Free(commandList->PresentDatas);
Free(commandList.Get());
}
bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel)
{
// No more presentation data
commandList->PresentDataCount = 0;
// Release Fence if needed
if (commandList->AutoReleaseFence)
{
ReleaseFence(driver.Get(), reinterpret_cast<Fence*>(commandList->InFlightFence));
commandList->InFlightFence = nullptr;
}
// Return the command list to the pool
if (driver->AvailableCommandListCount == driver->AvailableCommandListCapacity)
{
driver->AvailableCommandListCapacity += 1;
driver->AvailableCommandLists = static_cast<D3D12CommandList**>(
Realloc(driver->AvailableCommandLists, driver->AvailableCommandListCapacity * sizeof(D3D12CommandList*)));
}
driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList;
driver->AvailableCommandListCount += 1;
// Remove this command list from the submitted list
if (!cancel)
{
for (uint32 idx = 0; idx < driver->SubmittedCommandListCount; idx += 1)
{
if (driver->SubmittedCommandLists[idx] == commandList)
{
driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1];
driver->SubmittedCommandListCount -= 1;
}
}
}
return true;
}
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -46,6 +46,7 @@ namespace Juliet::D3D12
uint32 PresentDataCount; uint32 PresentDataCount;
D3D12Fence* InFlightFence; D3D12Fence* InFlightFence;
bool AutoReleaseFence;
D3D12GraphicsCommandListData GraphicsCommandList; D3D12GraphicsCommandListData GraphicsCommandList;
D3D12GraphicsCommandListData ComputeCommandList; D3D12GraphicsCommandListData ComputeCommandList;
@@ -57,9 +58,14 @@ namespace Juliet::D3D12
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType); extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
extern bool SubmitCommandLists(NonNullPtr<CommandList> commandList); extern bool SubmitCommandLists(NonNullPtr<CommandList> commandList);
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
extern void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort); extern void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort);
extern void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle); extern void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle);
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants); extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference); extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
namespace Internal
{
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
extern bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel);
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -174,7 +174,7 @@ namespace Juliet::D3D12
{ {
if (driver->StagingDescriptorPools[i]) if (driver->StagingDescriptorPools[i])
{ {
DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); Internal::DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
driver->StagingDescriptorPools[i] = nullptr; driver->StagingDescriptorPools[i] = nullptr;
} }
} }
@@ -184,7 +184,7 @@ namespace Juliet::D3D12
{ {
if (driver->AvailableCommandLists[i]) if (driver->AvailableCommandLists[i])
{ {
DestroyCommandList(driver->AvailableCommandLists[i]); Internal::DestroyCommandList(driver->AvailableCommandLists[i]);
driver->AvailableCommandLists[i] = nullptr; driver->AvailableCommandLists[i] = nullptr;
} }
} }
@@ -194,7 +194,7 @@ namespace Juliet::D3D12
{ {
if (driver->AvailableFences[i]) if (driver->AvailableFences[i])
{ {
DestroyFence(driver->AvailableFences[i]); Internal::DestroyFence(driver->AvailableFences[i]);
driver->AvailableFences[i] = nullptr; driver->AvailableFences[i] = nullptr;
} }
} }
@@ -202,7 +202,7 @@ namespace Juliet::D3D12
// Clean allocations // Clean allocations
Free(driver->AvailableCommandLists); Free(driver->AvailableCommandLists);
Free(driver->SubmittedCommandLists); Free(driver->SubmittedCommandLists);
Free(driver->WindowData); //Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now
Free(driver->AvailableFences); Free(driver->AvailableFences);
if (driver->IndirectDrawCommandSignature) if (driver->IndirectDrawCommandSignature)
@@ -278,7 +278,7 @@ namespace Juliet::D3D12
windowData->Window = window; windowData->Window = window;
if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) if (!Internal::CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync))
{ {
Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain.");
Free(windowData); Free(windowData);
@@ -294,12 +294,21 @@ namespace Juliet::D3D12
void DetachFromWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window) void DetachFromWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{ {
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get()); auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
auto* windowData = d3d12Driver->WindowData;
Assert(windowData && "Trying to destroy a swapchain but no Window Data exists");
Assert(d3d12Driver->WindowData && "Trying to destroy a swapchain but no Window Data exists"); Wait(driver);
// TODO : Wait for any remaining work and release the fences. for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1)
{
if (windowData->InFlightFences[idx] != nullptr)
{
ReleaseFence(driver, windowData->InFlightFences[idx]);
windowData->InFlightFences[idx] = nullptr;
}
}
DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); Internal::DestroySwapChain(d3d12Driver, d3d12Driver->WindowData);
Free(d3d12Driver->WindowData); Free(d3d12Driver->WindowData);
d3d12Driver->WindowData = nullptr; d3d12Driver->WindowData = nullptr;
@@ -548,7 +557,7 @@ namespace Juliet::D3D12
// Create Pools // Create Pools
driver->SubmittedCommandListCapacity = 4; driver->SubmittedCommandListCapacity = 4;
driver->SubmittedCommandBufferCount = 0; driver->SubmittedCommandListCount = 0;
driver->SubmittedCommandLists = driver->SubmittedCommandLists =
static_cast<D3D12CommandList**>(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*))); static_cast<D3D12CommandList**>(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*)));
if (!driver->SubmittedCommandLists) if (!driver->SubmittedCommandLists)
@@ -570,7 +579,7 @@ namespace Juliet::D3D12
for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1)
{ {
driver->StagingDescriptorPools[i] = driver->StagingDescriptorPools[i] =
CreateStagingDescriptorPool(driver, static_cast<D3D12_DESCRIPTOR_HEAP_TYPE>(i)); Internal::CreateStagingDescriptorPool(driver, static_cast<D3D12_DESCRIPTOR_HEAP_TYPE>(i));
if (driver->StagingDescriptorPools[i] == nullptr) if (driver->StagingDescriptorPools[i] == nullptr)
{ {
@@ -605,6 +614,10 @@ namespace Juliet::D3D12
device->SetBlendConstants = SetBlendConstants; device->SetBlendConstants = SetBlendConstants;
device->SetStencilReference = SetStencilReference; device->SetStencilReference = SetStencilReference;
device->Wait = Wait;
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
device->Driver = driver; device->Driver = driver;
driver->GraphicsDevice = device; driver->GraphicsDevice = device;

View File

@@ -71,7 +71,7 @@ namespace Juliet::D3D12
D3D12CommandList** SubmittedCommandLists; D3D12CommandList** SubmittedCommandLists;
uint8 SubmittedCommandListCapacity; uint8 SubmittedCommandListCapacity;
uint8 SubmittedCommandBufferCount; uint8 SubmittedCommandListCount;
D3D12Fence** AvailableFences; D3D12Fence** AvailableFences;
uint32 AvailableFenceCount; uint32 AvailableFenceCount;

View File

@@ -3,13 +3,14 @@
#include <Core/HAL/Display/Win32/Win32Window.h> #include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/Memory/Allocator.h> #include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Texture.h> #include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h> #include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Includes.h> #include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/D3D12/DX12SwapChain.h> #include <Graphics/D3D12/DX12SwapChain.h>
#include <Graphics/D3D12/DX12Utils.h> #include <Graphics/D3D12/DX12Utils.h>
#include <algorithm> #include <algorithm>
#include <DX12CommandList.h>
namespace Juliet::D3D12 namespace Juliet::D3D12
{ {
namespace namespace
@@ -105,7 +106,7 @@ namespace Juliet::D3D12
texture->IndexInContainer = 0; texture->IndexInContainer = 0;
// Assign SRV to the swapchain texture // Assign SRV to the swapchain texture
AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle); Internal::AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; srvDesc.Format = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
@@ -118,7 +119,7 @@ namespace Juliet::D3D12
// Assign RTV to the swapchain texture // Assign RTV to the swapchain texture
DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); Internal::AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
@@ -186,136 +187,140 @@ namespace Juliet::D3D12
} }
} // namespace } // namespace
bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode)
{
auto windowWin32State = static_cast<Win32::Window32State*>(windowData->Window->State);
HWND windowHandle = windowWin32State->Handle;
if (!IsWindow(windowHandle))
{
Assert(false && "windowWin32State->Handle is not a window handle ???");
return false;
}
// TODO: I have no way to test HDR easily except the steamdeck
DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
windowData->SwapChainTextureCount = std::clamp<uint8>(driver->FramesInFlight, 2, 3);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = 0; // Use the whole width
swapChainDesc.Height = 0; // Use the whole height
swapChainDesc.Format = swapChainFormat;
swapChainDesc.Stereo = 0;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = windowData->SwapChainTextureCount;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
if (driver->IsTearingSupported)
{
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
else
{
swapChainDesc.Flags = 0;
}
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {};
swapChainFullscreenDesc.RefreshRate.Numerator = 0;
swapChainFullscreenDesc.RefreshRate.Denominator = 0;
swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainFullscreenDesc.Windowed = true;
IDXGISwapChain1* swapChain = nullptr;
HRESULT result =
IDXGIFactory4_CreateSwapChainForHwnd(driver->DXGIFactory, reinterpret_cast<IUnknown*>(driver->GraphicsQueue),
windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain);
if (FAILED(result))
{
LogError(driver, "Failed to create SwapChain", result);
return false;
}
IDXGISwapChain3* swapChain3 = nullptr;
result = IDXGISwapChain1_QueryInterface(swapChain, IID_IDXGISwapChain3, reinterpret_cast<void**>(&swapChain3));
IDXGISwapChain1_Release(swapChain);
if (FAILED(result))
{
LogError(driver, "Could not query IDXGISwapChain3 interface", result);
return false;
}
if (composition != SwapChainComposition::SDR)
{
IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]);
}
IDXGIFactory1* parentFactory = nullptr;
result = IDXGISwapChain3_GetParent(swapChain3, IID_IDXGIFactory1, reinterpret_cast<void**>(&parentFactory));
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result);
}
else
{
// Disable DXGI window crap
result = IDXGIFactory1_MakeWindowAssociation(parentFactory, windowHandle, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result);
}
IDXGIFactory1_Release(parentFactory);
}
IDXGISwapChain3_GetDesc1(swapChain3, &swapChainDesc);
if (FAILED(result))
{
LogError(driver, "Failed to retrieve SwapChain descriptor", result);
return false;
}
windowData->SwapChain = swapChain3;
windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)];
windowData->SwapChainComposition = composition;
windowData->WindowFrameCounter = 0;
windowData->Width = swapChainDesc.Width;
windowData->Height = swapChainDesc.Height;
windowData->PresentMode = presentMode;
for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
{
if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx))
{
IDXGISwapChain3_Release(swapChain3);
return false;
}
}
return true;
}
bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture) bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
{ {
return AcquireSwapChainTexture(false, commandList, window, swapChainTexture); return AcquireSwapChainTexture(false, commandList, window, swapChainTexture);
} }
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData) namespace Internal
{ {
for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode)
{ {
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle); auto windowWin32State = static_cast<Win32::Window32State*>(windowData->Window->State);
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); HWND windowHandle = windowWin32State->Handle;
if (!IsWindow(windowHandle))
{
Assert(false && "windowWin32State->Handle is not a window handle ???");
return false;
}
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); // TODO: I have no way to test HDR easily except the steamdeck
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture);
Free(windowData->SwapChainTextureContainers[idx].Textures); windowData->SwapChainTextureCount = std::clamp<uint8>(driver->FramesInFlight, 2, 3);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = 0; // Use the whole width
swapChainDesc.Height = 0; // Use the whole height
swapChainDesc.Format = swapChainFormat;
swapChainDesc.Stereo = 0;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = windowData->SwapChainTextureCount;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
if (driver->IsTearingSupported)
{
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
else
{
swapChainDesc.Flags = 0;
}
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {};
swapChainFullscreenDesc.RefreshRate.Numerator = 0;
swapChainFullscreenDesc.RefreshRate.Denominator = 0;
swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainFullscreenDesc.Windowed = true;
IDXGISwapChain1* swapChain = nullptr;
HRESULT result =
IDXGIFactory4_CreateSwapChainForHwnd(driver->DXGIFactory, reinterpret_cast<IUnknown*>(driver->GraphicsQueue),
windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain);
if (FAILED(result))
{
LogError(driver, "Failed to create SwapChain", result);
return false;
}
IDXGISwapChain3* swapChain3 = nullptr;
result = IDXGISwapChain1_QueryInterface(swapChain, IID_IDXGISwapChain3, reinterpret_cast<void**>(&swapChain3));
IDXGISwapChain1_Release(swapChain);
if (FAILED(result))
{
LogError(driver, "Could not query IDXGISwapChain3 interface", result);
return false;
}
if (composition != SwapChainComposition::SDR)
{
IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]);
}
IDXGIFactory1* parentFactory = nullptr;
result = IDXGISwapChain3_GetParent(swapChain3, IID_IDXGIFactory1, reinterpret_cast<void**>(&parentFactory));
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result);
}
else
{
// Disable DXGI window crap
result = IDXGIFactory1_MakeWindowAssociation(parentFactory, windowHandle, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result);
}
IDXGIFactory1_Release(parentFactory);
}
IDXGISwapChain3_GetDesc1(swapChain3, &swapChainDesc);
if (FAILED(result))
{
LogError(driver, "Failed to retrieve SwapChain descriptor", result);
return false;
}
windowData->SwapChain = swapChain3;
windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)];
windowData->SwapChainComposition = composition;
windowData->WindowFrameCounter = 0;
windowData->Width = swapChainDesc.Width;
windowData->Height = swapChainDesc.Height;
windowData->PresentMode = presentMode;
for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
{
if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx))
{
IDXGISwapChain3_Release(swapChain3);
return false;
}
}
return true;
} }
IDXGISwapChain_Release(windowData->SwapChain); void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
windowData->SwapChain = nullptr; {
} for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
{
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle);
ReleaseStagingDescriptor(driver,
windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture);
Free(windowData->SwapChainTextureContainers[idx].Textures);
}
IDXGISwapChain_Release(windowData->SwapChain);
windowData->SwapChain = nullptr;
}
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -7,8 +7,12 @@ namespace Juliet::D3D12
struct D3D12Driver; struct D3D12Driver;
struct D3D12WindowData; struct D3D12WindowData;
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode);
extern bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture); extern bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
namespace Internal
{
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode);
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
} // namespace Internal
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -59,6 +59,11 @@ namespace Juliet
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants); void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference); void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference);
// Fences
bool (*Wait)(NonNullPtr<GPUDriver> driver);
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
const char* Name = "Unknown"; const char* Name = "Unknown";
GPUDriver* Driver = nullptr; GPUDriver* Driver = nullptr;
}; };