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)
{
D3D12DescriptorHeap* heap =
CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return false;
@@ -47,122 +47,126 @@ namespace Juliet::D3D12
}
} // namespace
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging)
namespace Internal
{
ID3D12DescriptorHeap* handle;
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32 count, bool isStaging)
{
return nullptr;
}
ID3D12DescriptorHeap* handle;
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))
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
{
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];
MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount -= 1;
return true;
}
void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor)
{
D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool;
if (pool != nullptr)
void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool)
{
MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount += 1;
}
}
for (uint32 i = 0; i < pool->HeapCount; i += 1)
{
DestroyDescriptorHeap(pool->Heaps[i]);
}
void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool)
{
for (uint32 i = 0; i < pool->HeapCount; i += 1)
{
DestroyDescriptorHeap(pool->Heaps[i]);
Free(pool->Heaps);
Free(pool->FreeDescriptors);
Free(pool.Get());
}
Free(pool->Heaps);
Free(pool->FreeDescriptors);
Free(pool.Get());
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

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

View File

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

View File

@@ -8,91 +8,171 @@
namespace Juliet::D3D12
{
void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier)
namespace
{
D3D12_RESOURCE_BARRIER barrierDesc[2];
uint32 numBarriers = 0;
// No transition barrier is needed if the state is not changing.
if (sourceState != destinationState)
void ReleaseFenceToPool(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12Fence> fence)
{
barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
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;
if (driver->AvailableFenceCount + 1 >= driver->AvailableFenceCapacity)
{
driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2;
driver->AvailableFences = static_cast<D3D12Fence**>(
Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity));
}
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;
barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0);
barrierDesc[numBarriers].UAV.pResource = resource;
// Insert a signal into the end of the command queue...
ID3D12CommandQueue_Signal(d3d12driver->GraphicsQueue, fence->Handle, D3D12_FENCE_SIGNAL_VALUE);
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;
ID3D12Fence* handle;
// TODO :Thread safe (lock + atomic)
if (driver->AvailableFenceCount == 0)
void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex,
bool needsUavBarrier)
{
HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
if (FAILED(result))
D3D12_RESOURCE_BARRIER barrierDesc[2];
uint32 numBarriers = 0;
// No transition barrier is needed if the state is not changing.
if (sourceState != destinationState)
{
LogError(driver, "Failed to create fence!", result);
return nullptr;
barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
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 (!fence)
if (needsUavBarrier)
{
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];
driver->AvailableFenceCount -= 1;
ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE);
D3D12Fence* fence;
ID3D12Fence* handle;
// 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;
return fence;
}
void DestroyFence(NonNullPtr<D3D12Fence> fence)
{
if (fence->Handle)
void DestroyFence(NonNullPtr<D3D12Fence> fence)
{
ID3D12Fence_Release(fence->Handle);
}
if (fence->Handle)
{
ID3D12Fence_Release(fence->Handle);
}
if (fence->Event)
{
CloseHandle(fence->Event);
if (fence->Event)
{
CloseHandle(fence->Event);
}
Free(fence.Get());
}
Free(fence.Get());
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

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

View File

@@ -157,79 +157,84 @@ namespace Juliet::D3D12
}
} // namespace
D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureContainer> container, uint32 layer,
uint32 level, bool shouldCycle, D3D12_RESOURCE_STATES newTextureUsage)
namespace Internal
{
D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level);
if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0)
D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList,
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)
// CycleActiveTexture(commandList->Driver, container);
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level);
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);
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)
D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container, uint32 layer, uint32 level)
{
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,
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)
void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, NonNullPtr<D3D12TextureSubresource> textureSubresource)
{
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
DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format)
{
return JulietToD3D12_TextureFormat[ToUnderlying(format)];
}
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);
}
}
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

View File

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

View File

@@ -10,7 +10,7 @@ namespace Juliet::D3D12
{
namespace
{
bool HasD3D12CommandList(NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
bool HasD3D12CommandListForQueueType(NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
{
switch (queueType)
{
@@ -37,7 +37,7 @@ namespace Juliet::D3D12
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
std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID);
@@ -111,7 +111,7 @@ namespace Juliet::D3D12
if (!commandList)
{
Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory");
DestroyCommandList(commandList);
Internal::DestroyCommandList(commandList);
return false;
}
@@ -122,14 +122,18 @@ namespace Juliet::D3D12
{
Log(LogLevel::Error, LogCategory::Graphics,
"Error not implemented, out of memory, handle that by deallocating stuff and returning false");
DestroyCommandList(commandList);
Internal::DestroyCommandList(commandList);
return false;
}
driver->AvailableCommandLists = resizedArray;
driver->AvailableCommandLists[driver->AvailableCommandListCapacity] = commandList;
uint32 id = driver->AvailableCommandListCapacity;
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->PresentDataCapacity = 1;
@@ -137,35 +141,42 @@ namespace Juliet::D3D12
commandList->PresentDatas =
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;
}
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
CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
uint8 currentCommandListIndex = d3d12Driver->AvailableCommandListCount;
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;
}
}
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;
@@ -195,7 +206,8 @@ namespace Juliet::D3D12
default: Assert(false && "Unsupported QueueType"); return nullptr;
}
d3d12Driver->AvailableCommandListCount += 1;
commandList->AutoReleaseFence = true;
return reinterpret_cast<CommandList*>(commandList);
}
@@ -212,7 +224,7 @@ namespace Juliet::D3D12
uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex;
D3D12TextureContainer* container =
&d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex];
D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0);
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, 0, 0);
D3D12_RESOURCE_BARRIER barrierDesc;
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
@@ -248,7 +260,7 @@ namespace Juliet::D3D12
ID3D12CommandList_Release(commandLists[0]);
// Acquire a fence and set it to the in-flight fence
d3d12CommandList->InFlightFence = AcquireFence(d3d12Driver);
d3d12CommandList->InFlightFence = Internal::AcquireFence(d3d12Driver);
if (!d3d12CommandList->InFlightFence)
{
return false;
@@ -263,16 +275,15 @@ namespace Juliet::D3D12
}
// 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**>(
Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * d3d12Driver->SubmittedCommandListCapacity));
}
d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandBufferCount] = d3d12CommandList;
d3d12Driver->SubmittedCommandBufferCount += 1;
d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList;
d3d12Driver->SubmittedCommandListCount += 1;
bool success = true;
for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1)
@@ -308,19 +319,15 @@ namespace Juliet::D3D12
}
// TODO : Correctly clean up and destroy
d3d12Driver->AvailableCommandListCount = 0;
// Check for cleanups
// for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
// Uint64 fenceValue = ID3D12Fence_GetCompletedValue(
// renderer->submittedCommandBuffers[i]->inFlightFence->handle);
//
// if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) {
// result &= D3D12_INTERNAL_CleanCommandBuffer(
// renderer,
// renderer->submittedCommandBuffers[i],
// false);
// }
// }
for (int32 i = d3d12Driver->SubmittedCommandListCount - 1; i >= 0; i -= 1)
{
uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle);
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
{
result &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
}
}
// TODO Destroy anything (buffer, texture, etc...)
@@ -329,26 +336,6 @@ namespace Juliet::D3D12
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)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
@@ -386,4 +373,66 @@ namespace Juliet::D3D12
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
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

View File

@@ -46,6 +46,7 @@ namespace Juliet::D3D12
uint32 PresentDataCount;
D3D12Fence* InFlightFence;
bool AutoReleaseFence;
D3D12GraphicsCommandListData GraphicsCommandList;
D3D12GraphicsCommandListData ComputeCommandList;
@@ -57,9 +58,14 @@ namespace Juliet::D3D12
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
extern bool SubmitCommandLists(NonNullPtr<CommandList> commandList);
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
extern void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort);
extern void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle);
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
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

View File

@@ -174,7 +174,7 @@ namespace Juliet::D3D12
{
if (driver->StagingDescriptorPools[i])
{
DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
Internal::DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
driver->StagingDescriptorPools[i] = nullptr;
}
}
@@ -184,7 +184,7 @@ namespace Juliet::D3D12
{
if (driver->AvailableCommandLists[i])
{
DestroyCommandList(driver->AvailableCommandLists[i]);
Internal::DestroyCommandList(driver->AvailableCommandLists[i]);
driver->AvailableCommandLists[i] = nullptr;
}
}
@@ -194,7 +194,7 @@ namespace Juliet::D3D12
{
if (driver->AvailableFences[i])
{
DestroyFence(driver->AvailableFences[i]);
Internal::DestroyFence(driver->AvailableFences[i]);
driver->AvailableFences[i] = nullptr;
}
}
@@ -202,7 +202,7 @@ namespace Juliet::D3D12
// Clean allocations
Free(driver->AvailableCommandLists);
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);
if (driver->IndirectDrawCommandSignature)
@@ -278,7 +278,7 @@ namespace Juliet::D3D12
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.");
Free(windowData);
@@ -294,12 +294,21 @@ namespace Juliet::D3D12
void DetachFromWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
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);
d3d12Driver->WindowData = nullptr;
@@ -548,7 +557,7 @@ namespace Juliet::D3D12
// Create Pools
driver->SubmittedCommandListCapacity = 4;
driver->SubmittedCommandBufferCount = 0;
driver->SubmittedCommandListCount = 0;
driver->SubmittedCommandLists =
static_cast<D3D12CommandList**>(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*)));
if (!driver->SubmittedCommandLists)
@@ -570,7 +579,7 @@ namespace Juliet::D3D12
for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1)
{
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)
{
@@ -605,6 +614,10 @@ namespace Juliet::D3D12
device->SetBlendConstants = SetBlendConstants;
device->SetStencilReference = SetStencilReference;
device->Wait = Wait;
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
device->Driver = driver;
driver->GraphicsDevice = device;

View File

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

View File

@@ -3,13 +3,14 @@
#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/D3D12/DX12SwapChain.h>
#include <Graphics/D3D12/DX12Utils.h>
#include <algorithm>
#include <DX12CommandList.h>
namespace Juliet::D3D12
{
namespace
@@ -105,7 +106,7 @@ namespace Juliet::D3D12
texture->IndexInContainer = 0;
// 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;
srvDesc.Format = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
@@ -118,7 +119,7 @@ namespace Juliet::D3D12
// Assign RTV to the swapchain texture
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;
rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
@@ -186,136 +187,140 @@ namespace Juliet::D3D12
}
} // 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)
{
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);
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]);
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;
}
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture);
Free(windowData->SwapChainTextureContainers[idx].Textures);
// 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;
}
IDXGISwapChain_Release(windowData->SwapChain);
windowData->SwapChain = nullptr;
}
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
{
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

View File

@@ -7,8 +7,12 @@ namespace Juliet::D3D12
struct D3D12Driver;
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 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

View File

@@ -59,6 +59,11 @@ namespace Juliet
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
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";
GPUDriver* Driver = nullptr;
};