Merged all d3d12 files into one file
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/CoreTypes.h>
|
||||
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
namespace Juliet
|
||||
|
||||
@@ -1,357 +0,0 @@
|
||||
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Linked List of free buffers
|
||||
D3D12Buffer* FreeBuffers = nullptr;
|
||||
|
||||
enum class D3D12BufferType : uint8
|
||||
{
|
||||
Base,
|
||||
TransferDownload,
|
||||
TransferUpload,
|
||||
};
|
||||
|
||||
[[nodiscard]] const char* D3D12BufferTypeToString(D3D12BufferType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case D3D12BufferType::Base: return "Base";
|
||||
case D3D12BufferType::TransferDownload: return "TransferDownload";
|
||||
case D3D12BufferType::TransferUpload: return "TransferUpload";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* BufferUsageToString(BufferUsage usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case BufferUsage::None: return "None";
|
||||
case BufferUsage::ConstantBuffer: return "ConstantBuffer";
|
||||
case BufferUsage::StructuredBuffer: return "StructuredBuffer";
|
||||
case BufferUsage::IndexBuffer: return "IndexBuffer";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void DestroyBuffer(D3D12Buffer* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer->Descriptor.Index != UINT32_MAX)
|
||||
{
|
||||
Internal::ReleaseDescriptor(buffer->Descriptor);
|
||||
}
|
||||
buffer->Descriptor = {};
|
||||
|
||||
if (buffer->Handle)
|
||||
{
|
||||
buffer->Handle->Release();
|
||||
buffer->Handle = nullptr;
|
||||
}
|
||||
buffer->CurrentState = D3D12_RESOURCE_STATE_COMMON;
|
||||
buffer->Size = 0;
|
||||
|
||||
buffer->Next = FreeBuffers;
|
||||
FreeBuffers = buffer;
|
||||
}
|
||||
|
||||
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, size_t stride, BufferUsage usage,
|
||||
D3D12BufferType type, bool isDynamic)
|
||||
{
|
||||
D3D12Buffer* buffer = nullptr;
|
||||
if (FreeBuffers)
|
||||
{
|
||||
buffer = FreeBuffers;
|
||||
FreeBuffers = buffer->Next;
|
||||
buffer->Next = nullptr;
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
buffer = ArenaPushStruct<D3D12Buffer>(d3d12Driver->DriverArena JULIET_DEBUG_PARAM("D3D12Buffer"));
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (type == D3D12BufferType::Base && usage == BufferUsage::None)
|
||||
{
|
||||
Assert(false, "Creating Base buffer with BufferUsage::None is invalid");
|
||||
DestroyBuffer(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Align size for Constant Buffers
|
||||
if (usage == BufferUsage::ConstantBuffer)
|
||||
{
|
||||
size = (size + 255U) & ~255U;
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties = {};
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
|
||||
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||
|
||||
// Constant buffers or Dynamic buffers generally need to be uploaded every frame
|
||||
const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer);
|
||||
|
||||
if (type == D3D12BufferType::TransferDownload)
|
||||
{
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
else if (isUpload)
|
||||
{
|
||||
if (d3d12Driver->GPUUploadHeapSupported)
|
||||
{
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
|
||||
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||
}
|
||||
else
|
||||
{
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must be a static buffer (Base type)
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Alignment = 0;
|
||||
desc.Width = size;
|
||||
desc.Height = 1;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s",
|
||||
(void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage));
|
||||
|
||||
ID3D12Resource* handle = nullptr;
|
||||
HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc,
|
||||
initialState, nullptr, IID_ID3D12Resource,
|
||||
reinterpret_cast<void**>(&handle));
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast<uint32>(result));
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d",
|
||||
(unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type);
|
||||
|
||||
HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason();
|
||||
if (FAILED(removeReason))
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast<uint32>(removeReason));
|
||||
}
|
||||
|
||||
DestroyBuffer(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer->Handle = handle;
|
||||
buffer->CurrentState = initialState;
|
||||
buffer->Descriptor.Index = UINT32_MAX;
|
||||
buffer->Size = size;
|
||||
|
||||
if (usage == BufferUsage::ConstantBuffer || usage == BufferUsage::StructuredBuffer)
|
||||
{
|
||||
auto& heap = d3d12Driver->BindlessDescriptorHeap;
|
||||
|
||||
Internal::D3D12Descriptor descriptor;
|
||||
if (Internal::AssignDescriptor(heap, descriptor))
|
||||
{
|
||||
buffer->Descriptor = descriptor;
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.CpuHandle;
|
||||
|
||||
if (usage == BufferUsage::ConstantBuffer)
|
||||
{
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
|
||||
cbvDesc.SizeInBytes = static_cast<uint32>(size);
|
||||
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||
}
|
||||
else if (usage == BufferUsage::StructuredBuffer)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.Buffer.FirstElement = 0;
|
||||
|
||||
if (stride > 0)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
srvDesc.Buffer.NumElements = static_cast<uint32>(size / stride);
|
||||
srvDesc.Buffer.StructureByteStride = static_cast<uint32>(stride);
|
||||
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
|
||||
srvDesc.Buffer.StructureByteStride = 0;
|
||||
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
|
||||
}
|
||||
|
||||
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
|
||||
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Bindless Heap Full or Invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic)
|
||||
{
|
||||
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
return reinterpret_cast<GraphicsBuffer*>(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic));
|
||||
}
|
||||
|
||||
void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer)
|
||||
{
|
||||
DestroyBuffer(reinterpret_cast<D3D12Buffer*>(buffer.Get()));
|
||||
}
|
||||
|
||||
GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage)
|
||||
{
|
||||
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
return reinterpret_cast<GraphicsTransferBuffer*>(
|
||||
CreateBuffer(d3d12Driver, size, 0, BufferUsage::None,
|
||||
usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload,
|
||||
false));
|
||||
}
|
||||
|
||||
void DestroyGraphicsTransferBuffer(NonNullPtr<GraphicsTransferBuffer> buffer)
|
||||
{
|
||||
DestroyBuffer(reinterpret_cast<D3D12Buffer*>(buffer.Get()));
|
||||
}
|
||||
|
||||
void* MapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsTransferBuffer> buffer)
|
||||
{
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
void* ptr = nullptr;
|
||||
|
||||
// 0-0 range means we don't intend to read anything.
|
||||
D3D12_RANGE readRange = { 0, 0 };
|
||||
if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void UnmapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsTransferBuffer> buffer)
|
||||
{
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
d3d12Buffer->Handle->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
void* MapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
|
||||
{
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
void* ptr = nullptr;
|
||||
D3D12_RANGE readRange = { 0, 0 };
|
||||
if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void UnmapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
|
||||
{
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
d3d12Buffer->Handle->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
uint32 GetDescriptorIndex(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
|
||||
{
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
return d3d12Buffer->Descriptor.Index;
|
||||
}
|
||||
|
||||
void CopyBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> dst,
|
||||
NonNullPtr<GraphicsTransferBuffer> src, size_t size, size_t dstOffset, size_t srcOffset)
|
||||
{
|
||||
auto d3d12CmdList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
auto d3d12Dst = reinterpret_cast<D3D12Buffer*>(dst.Get());
|
||||
auto d3d12Src = reinterpret_cast<D3D12Buffer*>(src.Get());
|
||||
|
||||
// Transition DST to COPY_DEST if needed
|
||||
if (d3d12Dst->CurrentState != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = d3d12Dst->Handle;
|
||||
barrier.Transition.StateBefore = d3d12Dst->CurrentState;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
|
||||
d3d12Dst->CurrentState = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
|
||||
// Src is Upload Buffer, usually effectively GenericRead/Common but for Upload heaps it's simpler.
|
||||
// We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc.
|
||||
// D3D12 Upload heaps start in GENERIC_READ and cannot transition.
|
||||
|
||||
d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, d3d12Src->Handle,
|
||||
srcOffset, size);
|
||||
}
|
||||
|
||||
void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer)
|
||||
{
|
||||
auto d3d12CmdList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
|
||||
D3D12_RESOURCE_STATES neededState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
|
||||
if (d3d12Buffer->CurrentState != neededState)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = d3d12Buffer->Handle;
|
||||
barrier.Transition.StateBefore = d3d12Buffer->CurrentState;
|
||||
barrier.Transition.StateAfter = neededState;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
|
||||
d3d12Buffer->CurrentState = neededState;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/GraphicsBuffer.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct CommandList;
|
||||
struct GPUDriver;
|
||||
} // namespace Juliet
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Buffer
|
||||
{
|
||||
// Note: This three variables need to stay at the top and in this order
|
||||
Internal::D3D12Descriptor Descriptor;
|
||||
ID3D12Resource* Handle;
|
||||
D3D12_RESOURCE_STATES CurrentState;
|
||||
|
||||
// Anything here can be any order
|
||||
D3D12Buffer* Next;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride,
|
||||
BufferUsage usage, bool isDynamic);
|
||||
extern void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer);
|
||||
|
||||
extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage);
|
||||
extern void DestroyGraphicsTransferBuffer(NonNullPtr<GraphicsTransferBuffer> buffer);
|
||||
|
||||
extern void* MapBuffer(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsTransferBuffer> buffer);
|
||||
extern void UnmapBuffer(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsTransferBuffer> buffer);
|
||||
extern void* MapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer);
|
||||
extern void UnmapBuffer(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
|
||||
|
||||
extern uint32 GetDescriptorIndex(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
|
||||
extern void CopyBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> dst,
|
||||
NonNullPtr<GraphicsTransferBuffer> src, size_t size, size_t dstOffset, size_t srcOffset);
|
||||
extern void TransitionBufferToReadable(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer);
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,558 +0,0 @@
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Graphics/D3D12/D3D12Buffer.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Synchronization.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr size_t kMaxTexturePerCommandList = 1024;
|
||||
constexpr size_t kMaxGraphicsPipelinePerCommandList = 1024;
|
||||
constexpr size_t kMaxPresentDataPerCommandList = 1;
|
||||
constexpr size_t kMaxCommandListCount = 4;
|
||||
|
||||
index_t CommandListID = 0;
|
||||
|
||||
index_t GetNewCommandListID()
|
||||
{
|
||||
return CommandListID++;
|
||||
}
|
||||
|
||||
bool HasD3D12CommandListForQueueType(NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
|
||||
{
|
||||
switch (queueType)
|
||||
{
|
||||
case QueueType::Graphics: return commandList->GraphicsCommandList.CommandList != nullptr;
|
||||
case QueueType::Compute: return commandList->ComputeCommandList.CommandList != nullptr;
|
||||
case QueueType::Copy: return commandList->CopyCommandList.CommandList != nullptr;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CreateAllocator(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandListBaseData> baseData,
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc)
|
||||
{
|
||||
HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator,
|
||||
reinterpret_cast<void**>(&baseData->Allocator));
|
||||
if (FAILED(result))
|
||||
{
|
||||
AssertHR(result, "Cannot create ID3D12CommandAllocator");
|
||||
return false;
|
||||
}
|
||||
|
||||
baseData->Allocator->Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// TODO: Factorize this. Flemme
|
||||
|
||||
// Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator
|
||||
auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)];
|
||||
switch (queueType)
|
||||
{
|
||||
case QueueType::Graphics:
|
||||
{
|
||||
CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc);
|
||||
ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
|
||||
HRESULT result =
|
||||
driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type,
|
||||
D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
|
||||
reinterpret_cast<void**>(&d3d12GraphicsCommandList));
|
||||
if (FAILED(result))
|
||||
{
|
||||
Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or "
|
||||
"compute command list");
|
||||
return false;
|
||||
}
|
||||
|
||||
commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList;
|
||||
d3d12GraphicsCommandList->SetName(wide_str.c_str());
|
||||
d3d12GraphicsCommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
case QueueType::Compute:
|
||||
{
|
||||
CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc);
|
||||
ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
|
||||
HRESULT result =
|
||||
driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type,
|
||||
D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
|
||||
reinterpret_cast<void**>(&d3d12GraphicsCommandList));
|
||||
if (FAILED(result))
|
||||
{
|
||||
Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or "
|
||||
"compute command list");
|
||||
return false;
|
||||
}
|
||||
|
||||
commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList;
|
||||
d3d12GraphicsCommandList->SetName(wide_str.c_str());
|
||||
d3d12GraphicsCommandList->Reset(commandList->ComputeCommandList.Allocator, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
case QueueType::Copy:
|
||||
{
|
||||
CreateAllocator(driver, &commandList->CopyCommandList, queueDesc);
|
||||
ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr;
|
||||
HRESULT result =
|
||||
driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type,
|
||||
D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList,
|
||||
reinterpret_cast<void**>(&d3d12CopyCommandList));
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
AssertHR(result, "cannot create ID3D12GraphicsCommandList (copy command list)");
|
||||
return false;
|
||||
}
|
||||
commandList->CopyCommandList.CommandList = d3d12CopyCommandList;
|
||||
d3d12CopyCommandList->SetName(wide_str.c_str());
|
||||
d3d12CopyCommandList->Reset(commandList->CopyCommandList.Allocator, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocateCommandList(NonNullPtr<D3D12Driver> driver, QueueType queueType)
|
||||
{
|
||||
if (driver->AvailableCommandLists == nullptr)
|
||||
{
|
||||
driver->AvailableCommandLists =
|
||||
ArenaPushArray<D3D12CommandList*>(driver->DriverArena,
|
||||
kMaxCommandListCount JULIET_DEBUG_PARAM("Command list count {}",
|
||||
kMaxCommandListCount));
|
||||
driver->AvailableCommandListCapacity = kMaxCommandListCount;
|
||||
}
|
||||
const index_t id = GetNewCommandListID();
|
||||
|
||||
auto* commandList =
|
||||
ArenaPushStruct<D3D12CommandList>(driver->DriverArena JULIET_DEBUG_PARAM("D3D12CommandList [{}]", id));
|
||||
if (!commandList)
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory");
|
||||
Internal::DestroyCommandList(commandList);
|
||||
return false;
|
||||
}
|
||||
|
||||
driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList;
|
||||
driver->AvailableCommandListCount += 1;
|
||||
|
||||
commandList->ID = id;
|
||||
commandList->Driver = driver;
|
||||
|
||||
// Window Handling
|
||||
commandList->PresentDataCapacity = kMaxPresentDataPerCommandList;
|
||||
commandList->PresentDataCount = 0;
|
||||
commandList->PresentDatas = ArenaPushArray<D3D12PresentData>(
|
||||
driver->DriverArena,
|
||||
kMaxPresentDataPerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12PresentData ptr array count "
|
||||
"{}",
|
||||
id, kMaxPresentDataPerCommandList));
|
||||
|
||||
// Resource tracking
|
||||
commandList->UsedTextureCapacity = kMaxTexturePerCommandList;
|
||||
commandList->UsedTextureCount = 0;
|
||||
commandList->UsedTextures = ArenaPushArray<D3D12Texture*>(
|
||||
driver->DriverArena,
|
||||
kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12Texture ptr array count "
|
||||
"{}",
|
||||
id, kMaxTexturePerCommandList));
|
||||
|
||||
commandList->UsedGraphicsPipelineCapacity = kMaxGraphicsPipelinePerCommandList;
|
||||
commandList->UsedGraphicsPipelineCount = 0;
|
||||
commandList->UsedGraphicsPipelines = ArenaPushArray<D3D12GraphicsPipeline*>(
|
||||
driver->DriverArena,
|
||||
kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12GraphicsPipeline ptr array count "
|
||||
"{}",
|
||||
id, kMaxTexturePerCommandList));
|
||||
|
||||
// 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());
|
||||
|
||||
D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType);
|
||||
|
||||
commandList->AutoReleaseFence = true;
|
||||
|
||||
return reinterpret_cast<CommandList*>(commandList);
|
||||
}
|
||||
|
||||
bool SubmitCommandLists(NonNullPtr<CommandList> commandList)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
auto* d3d12Driver = d3d12CommandList->Driver;
|
||||
// TODO : Use QueueType to choose the correct CommandList and Command Queue
|
||||
// Only use graphics for now
|
||||
|
||||
// Transition present textures to present mode
|
||||
for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1)
|
||||
{
|
||||
uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex;
|
||||
D3D12TextureContainer* container =
|
||||
&d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex];
|
||||
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, 0, 0);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrierDesc;
|
||||
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrierDesc.Transition.pResource = subresource->Parent->Resource;
|
||||
barrierDesc.Transition.Subresource = subresource->Index;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc);
|
||||
}
|
||||
|
||||
// Notify the command buffer that we have completed recording
|
||||
HRESULT result = d3d12CommandList->GraphicsCommandList.CommandList->Close();
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(d3d12Driver->D3D12Device, "Failed to close command list!", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3D12CommandList* ppCommandLists[] = { d3d12CommandList->GraphicsCommandList.CommandList };
|
||||
|
||||
// Submit the command list to the queue
|
||||
d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists);
|
||||
|
||||
// Acquire a fence and set it to the in-flight fence
|
||||
d3d12CommandList->InFlightFence =
|
||||
Internal::AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists")));
|
||||
if (!d3d12CommandList->InFlightFence)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark that a fence should be signaled after command list execution
|
||||
result = d3d12Driver->GraphicsQueue->Signal(d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(d3d12Driver->D3D12Device, "Failed to enqueue fence signal!", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark the command list as submitted
|
||||
[[maybe_unused]] const uint32 newValue = static_cast<uint32>(d3d12Driver->SubmittedCommandListCount) + 1U;
|
||||
Assert(newValue <= 0xFF && "Command List count exceeded uint8 capacity!");
|
||||
Assert(newValue <= d3d12Driver->SubmittedCommandListCapacity);
|
||||
|
||||
d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList;
|
||||
d3d12Driver->SubmittedCommandListCount += 1;
|
||||
|
||||
bool success = true;
|
||||
for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1)
|
||||
{
|
||||
D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i];
|
||||
auto* windowData = presentData->WindowData;
|
||||
|
||||
// NOTE: flip discard always supported since DXGI 1.4 is required
|
||||
uint32 syncInterval = 1;
|
||||
if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox)
|
||||
{
|
||||
syncInterval = 0;
|
||||
}
|
||||
|
||||
uint32 presentFlags = 0;
|
||||
if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate)
|
||||
{
|
||||
presentFlags = DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
result = windowData->SwapChain->Present(syncInterval, presentFlags);
|
||||
if (FAILED(result))
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource->Release();
|
||||
|
||||
windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast<Fence*>(d3d12CommandList->InFlightFence);
|
||||
d3d12CommandList->InFlightFence->ReferenceCount += 1;
|
||||
windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight;
|
||||
}
|
||||
|
||||
// Check for cleanups
|
||||
{
|
||||
int32 i = 0;
|
||||
while (i < d3d12Driver->SubmittedCommandListCount)
|
||||
{
|
||||
uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue();
|
||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||
{
|
||||
success &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
|
||||
// CleanCommandList swaps [i] with last and decrements count.
|
||||
// Don't increment — re-check the swapped-in element.
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Internal::DisposePendingResourcces(d3d12Driver);
|
||||
|
||||
++d3d12Driver->FrameCounter;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
|
||||
D3D12_VIEWPORT d3d12Viewport;
|
||||
d3d12Viewport.TopLeftX = viewPort.X;
|
||||
d3d12Viewport.TopLeftY = viewPort.Y;
|
||||
d3d12Viewport.Width = viewPort.Width;
|
||||
d3d12Viewport.Height = viewPort.Height;
|
||||
d3d12Viewport.MinDepth = viewPort.MinDepth;
|
||||
d3d12Viewport.MaxDepth = viewPort.MaxDepth;
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->RSSetViewports(1, &d3d12Viewport);
|
||||
}
|
||||
|
||||
void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
D3D12_RECT scissorRect;
|
||||
scissorRect.left = rectangle.X;
|
||||
scissorRect.top = rectangle.Y;
|
||||
scissorRect.right = rectangle.X + rectangle.Width;
|
||||
scissorRect.bottom = rectangle.Y + rectangle.Height;
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->RSSetScissorRects(1, &scissorRect);
|
||||
}
|
||||
|
||||
void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A };
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->OMSetBlendFactor(blendFactor);
|
||||
}
|
||||
|
||||
void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference);
|
||||
}
|
||||
|
||||
void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer, IndexFormat format,
|
||||
size_t indexCount, index_t offset)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
auto* d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
|
||||
|
||||
// Transition to INDEX_BUFFER state if needed
|
||||
if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = d3d12Buffer->Handle;
|
||||
barrier.Transition.StateBefore = d3d12Buffer->CurrentState;
|
||||
barrier.Transition.StateAfter =
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier);
|
||||
d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||
}
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW ibView;
|
||||
ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset;
|
||||
if (format == IndexFormat::UInt16)
|
||||
{
|
||||
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint16));
|
||||
ibView.Format = DXGI_FORMAT_R16_UINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ibView.SizeInBytes = static_cast<UINT>(indexCount * sizeof(uint32));
|
||||
ibView.Format = DXGI_FORMAT_R32_UINT;
|
||||
}
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView);
|
||||
}
|
||||
|
||||
void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage /*stage*/, uint32 rootParameterIndex,
|
||||
uint32 numConstants, const void* constants)
|
||||
{
|
||||
auto d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
// For now we assume Graphics Root Signature. Compute support would need a check or separate function.
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex,
|
||||
numConstants, constants, 0);
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
void SetDescriptorHeaps(NonNullPtr<D3D12CommandList> commandList)
|
||||
{
|
||||
ID3D12DescriptorHeap* heaps[2];
|
||||
D3D12DescriptorHeap* viewHeap = nullptr;
|
||||
D3D12DescriptorHeap* samplerHeap = nullptr;
|
||||
|
||||
viewHeap = commandList->Driver->BindlessDescriptorHeap;
|
||||
|
||||
samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver);
|
||||
|
||||
commandList->CRB_SRV_UAV_Heap = viewHeap;
|
||||
commandList->Sampler_Heap = samplerHeap;
|
||||
|
||||
heaps[0] = viewHeap->Handle;
|
||||
heaps[1] = samplerHeap->Handle;
|
||||
|
||||
commandList->GraphicsCommandList.CommandList->SetDescriptorHeaps(2, heaps);
|
||||
}
|
||||
|
||||
void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList)
|
||||
{
|
||||
// TODO : Handle other kind of command list (copy compute)
|
||||
if (commandList->GraphicsCommandList.CommandList)
|
||||
{
|
||||
commandList->GraphicsCommandList.CommandList->Release();
|
||||
}
|
||||
|
||||
commandList->GraphicsCommandList.Allocator->Release();
|
||||
}
|
||||
|
||||
bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel)
|
||||
{
|
||||
// No more presentation data
|
||||
commandList->PresentDataCount = 0;
|
||||
|
||||
HRESULT result = commandList->GraphicsCommandList.Allocator->Reset();
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Could not reset command allocator", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Could not reset command list", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commandList->Sampler_Heap) [[likely]]
|
||||
{
|
||||
ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap);
|
||||
commandList->Sampler_Heap = nullptr;
|
||||
}
|
||||
commandList->CRB_SRV_UAV_Heap = nullptr;
|
||||
|
||||
// Clean up resource tracking
|
||||
for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx)
|
||||
{
|
||||
--commandList->UsedTextures[idx]->ReferenceCount;
|
||||
}
|
||||
commandList->UsedTextureCount = 0;
|
||||
|
||||
for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx)
|
||||
{
|
||||
--commandList->UsedGraphicsPipelines[idx]->ReferenceCount;
|
||||
}
|
||||
commandList->UsedGraphicsPipelineCount = 0;
|
||||
|
||||
// Release Fence if needed
|
||||
if (commandList->AutoReleaseFence)
|
||||
{
|
||||
ReleaseFence(driver.Get(), reinterpret_cast<Fence*>(commandList->InFlightFence)
|
||||
JULIET_DEBUG_PARAM(ConstString("CleanCommandList")));
|
||||
commandList->InFlightFence = nullptr;
|
||||
}
|
||||
|
||||
// Return the command list to the pool
|
||||
Assert(driver->AvailableCommandListCount + 1 <= driver->AvailableCommandListCapacity);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define TRACK_RESOURCE(resource, type, array, count, capacity) \
|
||||
uint32 i; \
|
||||
\
|
||||
for (i = 0; i < commandList->count; i += 1) \
|
||||
{ \
|
||||
if (commandList->array[i] == (resource)) \
|
||||
{ \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
Assert(commandList->count + 1 <= commandList->capacity); \
|
||||
commandList->array[commandList->count] = resource; \
|
||||
commandList->count += 1; \
|
||||
++(resource)->ReferenceCount;
|
||||
|
||||
void TrackGraphicsPipeline(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12GraphicsPipeline> pipeline)
|
||||
{
|
||||
TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity)
|
||||
}
|
||||
|
||||
void TrackTexture(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture)
|
||||
{
|
||||
TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity)
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,115 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Math/Shape.h>
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsPipeline.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
// Forward Declare
|
||||
struct D3D12Driver;
|
||||
struct D3D12Fence;
|
||||
struct D3D12Texture;
|
||||
struct D3D12TextureSubresource;
|
||||
struct D3D12WindowData;
|
||||
|
||||
struct D3D12CommandListBaseData
|
||||
{
|
||||
ID3D12CommandAllocator* Allocator;
|
||||
};
|
||||
|
||||
struct D3D12CopyCommandListData : D3D12CommandListBaseData
|
||||
{
|
||||
ID3D12GraphicsCommandList* CommandList;
|
||||
};
|
||||
|
||||
struct D3D12GraphicsCommandListData : D3D12CommandListBaseData
|
||||
{
|
||||
ID3D12GraphicsCommandList6* CommandList;
|
||||
};
|
||||
|
||||
struct D3D12PresentData
|
||||
{
|
||||
D3D12WindowData* WindowData;
|
||||
uint32 SwapChainImageIndex;
|
||||
};
|
||||
|
||||
struct D3D12CommandList
|
||||
{
|
||||
CommandListHeader Common;
|
||||
|
||||
index_t ID;
|
||||
|
||||
D3D12Driver* Driver;
|
||||
|
||||
D3D12PresentData* PresentDatas;
|
||||
uint32 PresentDataCapacity;
|
||||
uint32 PresentDataCount;
|
||||
|
||||
D3D12Fence* InFlightFence;
|
||||
bool AutoReleaseFence;
|
||||
|
||||
D3D12GraphicsCommandListData GraphicsCommandList;
|
||||
D3D12GraphicsCommandListData ComputeCommandList;
|
||||
D3D12CopyCommandListData CopyCommandList;
|
||||
|
||||
D3D12GraphicsPipeline* CurrentGraphicsPipeline;
|
||||
|
||||
D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo];
|
||||
D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo];
|
||||
D3D12TextureSubresource* DepthStencilSubresource;
|
||||
|
||||
bool NeedVertexBufferBind : 1;
|
||||
bool NeedVertexSamplerBind : 1;
|
||||
bool NeedVertexStorageTextureBind : 1;
|
||||
bool NeedVertexStorageBufferBind : 1;
|
||||
|
||||
bool NeedFragmentSamplerBind : 1;
|
||||
bool NeedFragmentStorageTextureBind : 1;
|
||||
bool NeedFragmentStorageBufferBind : 1;
|
||||
|
||||
bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage];
|
||||
bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage];
|
||||
|
||||
// D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
|
||||
// D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage];
|
||||
|
||||
Internal::D3D12DescriptorHeap* CRB_SRV_UAV_Heap;
|
||||
Internal::D3D12DescriptorHeap* Sampler_Heap;
|
||||
|
||||
// Resource Tracking
|
||||
D3D12Texture** UsedTextures;
|
||||
uint32 UsedTextureCount;
|
||||
uint32 UsedTextureCapacity;
|
||||
|
||||
D3D12GraphicsPipeline** UsedGraphicsPipelines;
|
||||
uint32 UsedGraphicsPipelineCount;
|
||||
uint32 UsedGraphicsPipelineCapacity;
|
||||
};
|
||||
|
||||
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
|
||||
extern bool SubmitCommandLists(NonNullPtr<CommandList> 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 SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
|
||||
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
|
||||
extern void SetIndexBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> buffer,
|
||||
IndexFormat format, size_t indexCount, index_t offset);
|
||||
extern void SetPushConstants(NonNullPtr<CommandList> commandList, ShaderStage stage, uint32 rootParameterIndex,
|
||||
uint32 numConstants, const void* constants);
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
extern void SetDescriptorHeaps(NonNullPtr<D3D12CommandList> commandList);
|
||||
|
||||
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
|
||||
extern bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel);
|
||||
|
||||
extern void TrackGraphicsPipeline(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12GraphicsPipeline> pipeline);
|
||||
extern void TrackTexture(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture);
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,122 +0,0 @@
|
||||
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
|
||||
// TODO: Convert the whole file to memory arenas
|
||||
// Use the driver arena
|
||||
// Use a linked list to support "free" descriptors
|
||||
// Extend -> Push a new descriptor thats it...
|
||||
namespace Juliet::D3D12::Internal
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr size_t kStagingHeapDescriptorExpectedCount = 1024;
|
||||
|
||||
void InitStagingDescriptorPool(NonNullPtr<D3D12DescriptorHeap> heap, NonNullPtr<D3D12StagingDescriptorPool> pool)
|
||||
{
|
||||
for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx)
|
||||
{
|
||||
pool->FreeDescriptors[idx].Pool = pool;
|
||||
pool->FreeDescriptors[idx].Heap = heap.Get();
|
||||
pool->FreeDescriptors[idx].CpuHandleIndex = idx;
|
||||
pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtendStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptorPool& pool)
|
||||
{
|
||||
D3D12DescriptorHeap* heap =
|
||||
Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
|
||||
if (!heap)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pool.HeapCount += 1;
|
||||
pool.Heaps = static_cast<D3D12DescriptorHeap**>(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*)));
|
||||
pool.Heaps[pool.HeapCount - 1] = heap;
|
||||
|
||||
pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount;
|
||||
pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount;
|
||||
pool.FreeDescriptors = static_cast<D3D12StagingDescriptor*>(
|
||||
Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor)));
|
||||
|
||||
InitStagingDescriptorPool(heap, &pool);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
} // namespace Juliet::D3D12::Internal
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Thread/Mutex.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
|
||||
// Definitions:
|
||||
// RTV = Render Target View
|
||||
// DSV = Depth Stencil View
|
||||
// SRV = Shader Resource View
|
||||
// UAV = Unordered Access View
|
||||
// CBV = Constant Buffer View
|
||||
// PSO = Pipeline State Object
|
||||
|
||||
// Inspired (copy pasted a lot) by SDL GPU
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
// Forward declare
|
||||
struct D3D12Driver;
|
||||
struct D3D12StagingDescriptor;
|
||||
|
||||
struct D3D12StagingDescriptorPool
|
||||
{
|
||||
Internal::D3D12DescriptorHeap** Heaps;
|
||||
uint32 HeapCount;
|
||||
|
||||
// Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap.
|
||||
uint32 FreeDescriptorCapacity;
|
||||
uint32 FreeDescriptorCount;
|
||||
D3D12StagingDescriptor* FreeDescriptors;
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview
|
||||
struct D3D12StagingDescriptor
|
||||
{
|
||||
D3D12StagingDescriptorPool* Pool;
|
||||
Internal::D3D12DescriptorHeap* Heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle;
|
||||
uint32 CpuHandleIndex;
|
||||
};
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
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
|
||||
@@ -1,166 +0,0 @@
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/AgilitySDK/D3D12TokenizedProgramFormat.hpp>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12::Internal
|
||||
{
|
||||
void CreateDescriptorHeapPool(NonNullPtr<D3D12Driver> driver, D3D12DescriptorHeapPool& heapPool,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count)
|
||||
{
|
||||
// Heap pool is just single linked list of free elements
|
||||
constexpr size_t kInitialCapacity = 4;
|
||||
heapPool.FirstFreeDescriptorHeap = nullptr;
|
||||
|
||||
// Pre allocate 4
|
||||
for (uint32 i = 0; i < kInitialCapacity; ++i)
|
||||
{
|
||||
D3D12DescriptorHeap* descriptorHeap = CreateDescriptorHeap(driver, type, count, false);
|
||||
descriptorHeap->Next = heapPool.FirstFreeDescriptorHeap;
|
||||
heapPool.FirstFreeDescriptorHeap = descriptorHeap;
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& heapPool)
|
||||
{
|
||||
D3D12DescriptorHeap* current = heapPool.FirstFreeDescriptorHeap;
|
||||
while (current != nullptr)
|
||||
{
|
||||
D3D12DescriptorHeap* next = current->Next;
|
||||
DestroyDescriptorHeap(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging)
|
||||
{
|
||||
D3D12DescriptorHeap* heap = ArenaPushStruct<D3D12DescriptorHeap>(
|
||||
driver->DriverArena JULIET_DEBUG_PARAM("Descriptor Heap Type {}", CStr(GetDescriptorTypeNane(type))));
|
||||
Assert(heap);
|
||||
|
||||
heap->CurrentDescriptorIndex = 0;
|
||||
|
||||
heap->FreeIndices.Create(driver->DriverArena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices"));
|
||||
heap->FreeIndices.Resize(16);
|
||||
heap->CurrentFreeIndex = 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;
|
||||
|
||||
ID3D12DescriptorHeap* handle;
|
||||
HRESULT result =
|
||||
driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, reinterpret_cast<void**>(&handle));
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Failed to create descriptor heap!", result);
|
||||
DestroyDescriptorHeap(heap);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
heap->Handle = handle;
|
||||
heap->HeapType = type;
|
||||
heap->MaxDescriptors = count;
|
||||
heap->Staging = isStaging;
|
||||
heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type);
|
||||
heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart();
|
||||
if (!isStaging)
|
||||
{
|
||||
heap->DescriptorHeapGPUStart = handle->GetGPUDescriptorHandleForHeapStart();
|
||||
}
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap)
|
||||
{
|
||||
heap->FreeIndices.Destroy();
|
||||
if (heap->Handle)
|
||||
{
|
||||
heap->Handle->Release();
|
||||
}
|
||||
}
|
||||
|
||||
bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor)
|
||||
{
|
||||
uint32 index = UINT32_MAX;
|
||||
|
||||
if (heap->CurrentFreeIndex > 0)
|
||||
{
|
||||
heap->CurrentFreeIndex -= 1;
|
||||
index = heap->FreeIndices[heap->CurrentFreeIndex];
|
||||
}
|
||||
else if (heap->CurrentDescriptorIndex < heap->MaxDescriptors)
|
||||
{
|
||||
index = heap->CurrentDescriptorIndex;
|
||||
heap->CurrentDescriptorIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(false, "Descriptor Heap Full!");
|
||||
return false;
|
||||
}
|
||||
|
||||
outDescriptor.Heap = heap;
|
||||
outDescriptor.Index = index;
|
||||
outDescriptor.CpuHandle = heap->DescriptorHeapCPUStart;
|
||||
outDescriptor.CpuHandle.ptr += heap->DescriptorSize * index;
|
||||
outDescriptor.GpuHandle = heap->DescriptorHeapGPUStart;
|
||||
outDescriptor.GpuHandle.ptr += heap->DescriptorSize * index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseDescriptor(const D3D12Descriptor& descriptor)
|
||||
{
|
||||
if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12DescriptorHeap* heap = descriptor.Heap;
|
||||
|
||||
if (heap->CurrentFreeIndex >= heap->FreeIndices.Count)
|
||||
{
|
||||
heap->FreeIndices.PushBack(descriptor.Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap->FreeIndices[heap->CurrentFreeIndex] = descriptor.Index;
|
||||
heap->CurrentFreeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver)
|
||||
{
|
||||
D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool;
|
||||
|
||||
D3D12DescriptorHeap* result = pool.FirstFreeDescriptorHeap;
|
||||
if (result)
|
||||
{
|
||||
pool.FirstFreeDescriptorHeap = pool.FirstFreeDescriptorHeap->Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
GPUDriver::kSampler_HeapDescriptorCount, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReturnSamplerHeapToPool(NonNullPtr<D3D12Driver> d3d12Driver, NonNullPtr<D3D12DescriptorHeap> heap)
|
||||
{
|
||||
D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool;
|
||||
|
||||
heap->CurrentDescriptorIndex = 0;
|
||||
|
||||
heap->Next = pool.FirstFreeDescriptorHeap;
|
||||
pool.FirstFreeDescriptorHeap = heap;
|
||||
}
|
||||
} // namespace Juliet::D3D12::Internal
|
||||
@@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Networking/NetworkPacket.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
|
||||
// Forward declare
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Driver;
|
||||
}
|
||||
|
||||
namespace Juliet::D3D12::Internal
|
||||
{
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps
|
||||
struct D3D12DescriptorHeap
|
||||
{
|
||||
D3D12DescriptorHeap* Next;
|
||||
ID3D12DescriptorHeap* Handle;
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE HeapType;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps
|
||||
uint32 MaxDescriptors;
|
||||
uint32 DescriptorSize;
|
||||
uint32 CurrentDescriptorIndex; // only used by GPU heaps
|
||||
|
||||
VectorArena<uint32> FreeIndices;
|
||||
index_t CurrentFreeIndex;
|
||||
|
||||
bool Staging : 1;
|
||||
};
|
||||
|
||||
struct D3D12Descriptor
|
||||
{
|
||||
D3D12DescriptorHeap* Heap;
|
||||
uint32 Index;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle;
|
||||
};
|
||||
|
||||
struct D3D12DescriptorHeapPool
|
||||
{
|
||||
D3D12DescriptorHeap* FirstFreeDescriptorHeap;
|
||||
};
|
||||
|
||||
using DescriptorHeapCreator = D3D12DescriptorHeap* (*)(NonNullPtr<D3D12Driver>, D3D12DescriptorHeapPool& heapPool,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE, uint32, bool);
|
||||
|
||||
extern void CreateDescriptorHeapPool(NonNullPtr<D3D12Driver> driver, D3D12DescriptorHeapPool& heapPool,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count);
|
||||
extern void DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& pool);
|
||||
|
||||
extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
uint32 count, bool isStaging);
|
||||
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap);
|
||||
|
||||
extern D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr<D3D12Driver> d3d12Driver);
|
||||
extern void ReturnSamplerHeapToPool(NonNullPtr<D3D12Driver> d3d12Driver, NonNullPtr<D3D12DescriptorHeap> heap);
|
||||
|
||||
extern bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor);
|
||||
extern void ReleaseDescriptor(const D3D12Descriptor& descriptor);
|
||||
} // namespace Juliet::D3D12::Internal
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,119 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsPipeline.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct DynamicLibrary;
|
||||
}
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12StagingDescriptorPool;
|
||||
// Forward Declare
|
||||
struct D3D12CommandList;
|
||||
struct D3D12Fence;
|
||||
|
||||
enum class RootParameters : uint8
|
||||
{
|
||||
Constants32Bits,
|
||||
Count,
|
||||
};
|
||||
|
||||
struct D3D12WindowData
|
||||
{
|
||||
Window* Window;
|
||||
|
||||
IDXGISwapChain3* SwapChain;
|
||||
D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight];
|
||||
DXGI_COLOR_SPACE_TYPE SwapChainColorSpace;
|
||||
SwapChainComposition SwapChainComposition;
|
||||
uint8 SwapChainTextureCount;
|
||||
|
||||
PresentMode PresentMode;
|
||||
|
||||
Fence* InFlightFences[GPUDriver::kMaxFramesInFlight];
|
||||
|
||||
uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
};
|
||||
|
||||
struct D3D12Driver : GPUDriver
|
||||
{
|
||||
GraphicsDevice* GraphicsDevice;
|
||||
|
||||
// D3D12
|
||||
DynamicLibrary* D3D12DLL;
|
||||
ID3D12Device5* D3D12Device;
|
||||
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignatureFct;
|
||||
ID3D12CommandQueue* GraphicsQueue;
|
||||
D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Count)];
|
||||
#if JULIET_DEBUG
|
||||
ID3D12Debug1* D3D12Debug;
|
||||
#endif
|
||||
|
||||
// Indirect commands signature
|
||||
ID3D12CommandSignature* IndirectDrawCommandSignature;
|
||||
ID3D12CommandSignature* IndirectIndexedDrawCommandSignature;
|
||||
ID3D12CommandSignature* IndirectDispatchCommandSignature;
|
||||
|
||||
// DXGI
|
||||
IDXGIFactory4* DXGIFactory;
|
||||
IDXGIAdapter1* DXGIAdapter;
|
||||
#if JULIET_DEBUG
|
||||
DynamicLibrary* DXGIDebugDLL;
|
||||
IDXGIDebug* DXGIDebug;
|
||||
#ifdef IDXGIINFOQUEUE_SUPPORTED
|
||||
IDXGIInfoQueue* DXGIInfoQueue;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Windows
|
||||
// TODO: Support more than one window
|
||||
D3D12WindowData* WindowData;
|
||||
|
||||
// Resources
|
||||
D3D12CommandList** AvailableCommandLists;
|
||||
uint8 AvailableCommandListCapacity;
|
||||
uint8 AvailableCommandListCount;
|
||||
|
||||
D3D12CommandList** SubmittedCommandLists;
|
||||
uint8 SubmittedCommandListCapacity;
|
||||
uint8 SubmittedCommandListCount;
|
||||
|
||||
D3D12Fence** AvailableFences;
|
||||
uint32 AvailableFenceCount;
|
||||
uint32 AvailableFenceCapacity;
|
||||
|
||||
D3D12GraphicsPipeline** GraphicsPipelinesToDispose;
|
||||
uint32 GraphicsPipelinesToDisposeCount;
|
||||
uint32 GraphicsPipelinesToDisposeCapacity;
|
||||
|
||||
D3D12GraphicsRootSignature* BindlessRootSignature;
|
||||
|
||||
D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
|
||||
Internal::D3D12DescriptorHeap* BindlessDescriptorHeap;
|
||||
Internal::D3D12DescriptorHeapPool SamplerHeapPool;
|
||||
|
||||
String Semantic;
|
||||
|
||||
uint8 FramesInFlight;
|
||||
uint64 FrameCounter = 0; // Number of frame since inception
|
||||
|
||||
bool IsTearingSupported : 1;
|
||||
bool IsUMAAvailable : 1;
|
||||
bool IsUMACacheCoherent : 1;
|
||||
bool GPUUploadHeapSupported : 1;
|
||||
};
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
void DisposePendingResourcces(NonNullPtr<D3D12Driver> driver);
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,557 +0,0 @@
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsPipeline.h>
|
||||
#include <Graphics/D3D12/D3D12Shader.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] =
|
||||
{
|
||||
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX
|
||||
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_CULL_MODE JulietToD3D12_CullMode[] =
|
||||
{
|
||||
D3D12_CULL_MODE_NONE,
|
||||
D3D12_CULL_MODE_FRONT,
|
||||
D3D12_CULL_MODE_BACK
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_FILL_MODE JulietToD3D12_FillMode[] =
|
||||
{
|
||||
D3D12_FILL_MODE_SOLID,
|
||||
D3D12_FILL_MODE_WIREFRAME
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count));
|
||||
|
||||
DXGI_FORMAT JulietToD3D12_VertexFormat[] = {
|
||||
DXGI_FORMAT_UNKNOWN, // Unknown
|
||||
DXGI_FORMAT_R32_SINT, // Int
|
||||
DXGI_FORMAT_R32G32_SINT, // Int2
|
||||
DXGI_FORMAT_R32G32B32_SINT, // Int3
|
||||
DXGI_FORMAT_R32G32B32A32_SINT, // Int4
|
||||
DXGI_FORMAT_R32_UINT, // UInt
|
||||
DXGI_FORMAT_R32G32_UINT, // UInt2
|
||||
DXGI_FORMAT_R32G32B32_UINT, // UInt3
|
||||
DXGI_FORMAT_R32G32B32A32_UINT, // UInt4
|
||||
DXGI_FORMAT_R32_FLOAT, // Float
|
||||
DXGI_FORMAT_R32G32_FLOAT, // Float2
|
||||
DXGI_FORMAT_R32G32B32_FLOAT, // Float3
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4
|
||||
DXGI_FORMAT_R8G8_SINT, // Byte2
|
||||
DXGI_FORMAT_R8G8B8A8_SINT, // Byte4
|
||||
DXGI_FORMAT_R8G8_UINT, // UByte2
|
||||
DXGI_FORMAT_R8G8B8A8_UINT, // UByte4
|
||||
DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm
|
||||
DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm
|
||||
DXGI_FORMAT_R16G16_SINT, // Short2
|
||||
DXGI_FORMAT_R16G16B16A16_SINT, // Short4
|
||||
DXGI_FORMAT_R16G16_UINT, // UShort2
|
||||
DXGI_FORMAT_R16G16B16A16_UINT, // UShort4
|
||||
DXGI_FORMAT_R16G16_SNORM, // Short2_Norm
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm
|
||||
DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm
|
||||
DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm
|
||||
DXGI_FORMAT_R16G16_FLOAT, // Half2
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT // Half4
|
||||
};
|
||||
static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) ==
|
||||
ToUnderlying(VertexElementFormat::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_PrimitiveTopologyType[] = {
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) ==
|
||||
ToUnderlying(PrimitiveType::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_BLEND JulietToD3D12_BlendFactor[] =
|
||||
{
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_ONE,
|
||||
D3D12_BLEND_SRC_COLOR,
|
||||
D3D12_BLEND_INV_SRC_COLOR,
|
||||
D3D12_BLEND_DEST_COLOR,
|
||||
D3D12_BLEND_INV_DEST_COLOR,
|
||||
D3D12_BLEND_SRC_ALPHA,
|
||||
D3D12_BLEND_INV_SRC_ALPHA,
|
||||
D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA,
|
||||
D3D12_BLEND_BLEND_FACTOR,
|
||||
D3D12_BLEND_INV_BLEND_FACTOR,
|
||||
D3D12_BLEND_SRC_ALPHA_SAT,
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_BLEND JulietToD3D12_BlendFactorAlpha[] =
|
||||
{
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_ONE,
|
||||
D3D12_BLEND_SRC_ALPHA,
|
||||
D3D12_BLEND_INV_SRC_ALPHA,
|
||||
D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA,
|
||||
D3D12_BLEND_SRC_ALPHA,
|
||||
D3D12_BLEND_INV_SRC_ALPHA,
|
||||
D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA,
|
||||
D3D12_BLEND_BLEND_FACTOR,
|
||||
D3D12_BLEND_INV_BLEND_FACTOR,
|
||||
D3D12_BLEND_SRC_ALPHA_SAT,
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) ==
|
||||
ToUnderlying(BlendFactor::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_BLEND_OP JulietToD3D12_BlendOperation[] =
|
||||
{
|
||||
D3D12_BLEND_OP_ADD,
|
||||
D3D12_BLEND_OP_ADD,
|
||||
D3D12_BLEND_OP_SUBTRACT,
|
||||
D3D12_BLEND_OP_REV_SUBTRACT,
|
||||
D3D12_BLEND_OP_MIN,
|
||||
D3D12_BLEND_OP_MAX
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) ==
|
||||
ToUnderlying(BlendOperation::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] =
|
||||
{
|
||||
D3D12_COMPARISON_FUNC_NEVER,
|
||||
D3D12_COMPARISON_FUNC_NEVER,
|
||||
D3D12_COMPARISON_FUNC_LESS,
|
||||
D3D12_COMPARISON_FUNC_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_GREATER,
|
||||
D3D12_COMPARISON_FUNC_NOT_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_GREATER_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_ALWAYS
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) ==
|
||||
ToUnderlying(CompareOperation::Count));
|
||||
|
||||
// clang-format off
|
||||
D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] =
|
||||
{
|
||||
D3D12_STENCIL_OP_KEEP,
|
||||
D3D12_STENCIL_OP_KEEP,
|
||||
D3D12_STENCIL_OP_ZERO,
|
||||
D3D12_STENCIL_OP_REPLACE,
|
||||
D3D12_STENCIL_OP_INCR_SAT,
|
||||
D3D12_STENCIL_OP_DECR_SAT,
|
||||
D3D12_STENCIL_OP_INVERT,
|
||||
D3D12_STENCIL_OP_INCR,
|
||||
D3D12_STENCIL_OP_DECR
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) ==
|
||||
ToUnderlying(StencilOperation::Count));
|
||||
|
||||
bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic)
|
||||
{
|
||||
if (desc == nullptr || vertexInputState.NumVertexAttributes == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx)
|
||||
{
|
||||
VertexAttribute attribute = vertexInputState.VertexAttributes[idx];
|
||||
|
||||
desc[idx].SemanticName = CStr(semantic);
|
||||
desc[idx].SemanticIndex = attribute.Location;
|
||||
desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)];
|
||||
desc[idx].InputSlot = attribute.BufferSlot;
|
||||
desc[idx].AlignedByteOffset = attribute.Offset;
|
||||
desc[idx].InputSlotClass =
|
||||
JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)];
|
||||
desc[idx].InstanceDataStepRate =
|
||||
(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance)
|
||||
? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate
|
||||
: 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc)
|
||||
{
|
||||
desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)];
|
||||
desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)];
|
||||
|
||||
switch (rasterizerState.FrontFace)
|
||||
{
|
||||
case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break;
|
||||
case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break;
|
||||
default: return false;
|
||||
}
|
||||
static_assert(ToUnderlying(FrontFace::Count) == 2);
|
||||
|
||||
if (rasterizerState.EnableDepthBias)
|
||||
{
|
||||
desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor);
|
||||
desc.DepthBiasClamp = rasterizerState.DepthBiasClamp;
|
||||
desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.DepthBias = 0;
|
||||
desc.DepthBiasClamp = 0.0f;
|
||||
desc.SlopeScaledDepthBias = 0.0f;
|
||||
}
|
||||
|
||||
desc.DepthClipEnable = rasterizerState.EnableDepthClip;
|
||||
desc.MultisampleEnable = FALSE;
|
||||
desc.AntialiasedLineEnable = FALSE;
|
||||
desc.ForcedSampleCount = 0;
|
||||
desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc)
|
||||
{
|
||||
ZeroStruct(blendDesc);
|
||||
blendDesc.AlphaToCoverageEnable = FALSE;
|
||||
blendDesc.IndependentBlendEnable = FALSE;
|
||||
|
||||
for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; i += 1)
|
||||
{
|
||||
D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc;
|
||||
rtBlendDesc.BlendEnable = FALSE;
|
||||
rtBlendDesc.LogicOpEnable = FALSE;
|
||||
rtBlendDesc.SrcBlend = D3D12_BLEND_ONE;
|
||||
rtBlendDesc.DestBlend = D3D12_BLEND_ZERO;
|
||||
rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
|
||||
rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||
rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
|
||||
rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||
rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
|
||||
rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
// If target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot
|
||||
if (i < createInfo.TargetInfo.NumColorTargets)
|
||||
{
|
||||
ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState;
|
||||
ColorComponentFlags colorWriteMask =
|
||||
blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast<ColorComponentFlags>(0xF);
|
||||
|
||||
rtBlendDesc.BlendEnable = blendState.EnableBlend;
|
||||
rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)];
|
||||
rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)];
|
||||
rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)];
|
||||
rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)];
|
||||
rtBlendDesc.DestBlendAlpha =
|
||||
JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)];
|
||||
rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)];
|
||||
rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
blendDesc.IndependentBlendEnable = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
blendDesc.RenderTarget[i] = rtBlendDesc;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc)
|
||||
{
|
||||
desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE;
|
||||
desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)];
|
||||
desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE;
|
||||
desc.StencilReadMask = depthStencilState.CompareMask;
|
||||
desc.StencilWriteMask = depthStencilState.WriteMask;
|
||||
|
||||
desc.FrontFace.StencilFailOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)];
|
||||
desc.FrontFace.StencilDepthFailOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)];
|
||||
desc.FrontFace.StencilPassOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)];
|
||||
desc.FrontFace.StencilFunc =
|
||||
JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)];
|
||||
|
||||
desc.BackFace.StencilFailOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)];
|
||||
desc.BackFace.StencilDepthFailOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)];
|
||||
desc.BackFace.StencilPassOp =
|
||||
JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)];
|
||||
desc.BackFace.StencilFunc =
|
||||
JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
void CopyShader(NonNullPtr<D3D12Shader> destination, NonNullPtr<D3D12Shader> source)
|
||||
{
|
||||
D3D12Shader* src = source.Get();
|
||||
D3D12Shader* dst = destination.Get();
|
||||
|
||||
ByteBuffer dstBuffer = dst->ByteCode;
|
||||
|
||||
if (src->ByteCode.Size != dstBuffer.Size)
|
||||
{
|
||||
dstBuffer.Data = static_cast<Byte*>(Realloc(dstBuffer.Data, src->ByteCode.Size));
|
||||
dstBuffer.Size = src->ByteCode.Size;
|
||||
}
|
||||
// Copy the shader data. Infortunately this will overwrite the bytecode if it exists so we patch it back just after
|
||||
MemCopy(dst, src, sizeof(D3D12Shader));
|
||||
dst->ByteCode = dstBuffer;
|
||||
|
||||
MemCopy(dst->ByteCode.Data, src->ByteCode.Data, src->ByteCode.Size);
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr<GPUDriver> driver, const GraphicsPipelineCreateInfo& createInfo)
|
||||
{
|
||||
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto vertexShader = reinterpret_cast<D3D12Shader*>(createInfo.VertexShader);
|
||||
auto fragmentShader = reinterpret_cast<D3D12Shader*>(createInfo.FragmentShader);
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
||||
psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data;
|
||||
psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size;
|
||||
psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader
|
||||
psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size;
|
||||
|
||||
if (createInfo.VertexInputState.NumVertexAttributes > 0)
|
||||
{
|
||||
D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT];
|
||||
psoDesc.InputLayout.pInputElementDescs = inputElementDescs;
|
||||
psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes;
|
||||
ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic);
|
||||
}
|
||||
|
||||
psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)];
|
||||
|
||||
if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!ConvertBlendState(createInfo, psoDesc.BlendState))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto pipeline = static_cast<D3D12GraphicsPipeline*>(Calloc(1, sizeof(D3D12GraphicsPipeline)));
|
||||
if (!pipeline)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF;
|
||||
|
||||
psoDesc.SampleMask = sampleMask;
|
||||
psoDesc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)];
|
||||
psoDesc.SampleDesc.Quality =
|
||||
(createInfo.MultisampleState.SampleCount > TextureSampleCount::One) ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN : 0;
|
||||
|
||||
psoDesc.DSVFormat = Internal::ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat);
|
||||
psoDesc.NumRenderTargets = static_cast<uint32>(createInfo.TargetInfo.NumColorTargets);
|
||||
for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx)
|
||||
{
|
||||
psoDesc.RTVFormats[idx] =
|
||||
Internal::ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format);
|
||||
}
|
||||
|
||||
// Assuming some default values or further initialization
|
||||
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
||||
psoDesc.CachedPSO.CachedBlobSizeInBytes = 0;
|
||||
psoDesc.CachedPSO.pCachedBlob = nullptr;
|
||||
|
||||
psoDesc.NodeMask = 0;
|
||||
|
||||
pipeline->RootSignature = d3d12Driver->BindlessRootSignature;
|
||||
psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle;
|
||||
|
||||
ID3D12PipelineState* pipelineState;
|
||||
HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState,
|
||||
reinterpret_cast<void**>(&pipelineState));
|
||||
if (FAILED(res))
|
||||
{
|
||||
LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res);
|
||||
Internal::ReleaseGraphicsPipeline(pipeline);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pipeline->PipelineState = pipelineState;
|
||||
|
||||
for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1)
|
||||
{
|
||||
pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] =
|
||||
createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes;
|
||||
}
|
||||
|
||||
pipeline->PrimitiveType = createInfo.PrimitiveType;
|
||||
|
||||
pipeline->VertexSamplerCount = vertexShader->NumSamplers;
|
||||
pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures;
|
||||
pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers;
|
||||
pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers;
|
||||
|
||||
pipeline->FragmentSamplerCount = fragmentShader->NumSamplers;
|
||||
pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures;
|
||||
pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers;
|
||||
pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers;
|
||||
|
||||
pipeline->ReferenceCount = 0;
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
// Save the PSODesc and shaders to be able to recreate the graphics pipeline when needed
|
||||
pipeline->PSODescTemplate = psoDesc;
|
||||
|
||||
pipeline->VertexShaderCache = static_cast<D3D12Shader*>(Calloc(1, sizeof(D3D12Shader)));
|
||||
pipeline->FragmentShaderCache = static_cast<D3D12Shader*>(Calloc(1, sizeof(D3D12Shader)));
|
||||
CopyShader(pipeline->VertexShaderCache, vertexShader);
|
||||
CopyShader(pipeline->FragmentShaderCache, fragmentShader);
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<GraphicsPipeline*>(pipeline);
|
||||
}
|
||||
|
||||
void DestroyGraphicsPipeline(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline)
|
||||
{
|
||||
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto d3d12GraphicsPipeline = reinterpret_cast<D3D12GraphicsPipeline*>(graphicsPipeline.Get());
|
||||
|
||||
if (d3d12Driver->GraphicsPipelinesToDisposeCount + 1 >= d3d12Driver->GraphicsPipelinesToDisposeCapacity)
|
||||
{
|
||||
d3d12Driver->GraphicsPipelinesToDisposeCapacity = d3d12Driver->GraphicsPipelinesToDisposeCapacity * 2;
|
||||
d3d12Driver->GraphicsPipelinesToDispose = static_cast<D3D12GraphicsPipeline**>(
|
||||
Realloc(d3d12Driver->GraphicsPipelinesToDispose,
|
||||
sizeof(D3D12GraphicsPipeline*) * d3d12Driver->GraphicsPipelinesToDisposeCapacity));
|
||||
}
|
||||
d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = d3d12GraphicsPipeline;
|
||||
d3d12Driver->GraphicsPipelinesToDisposeCount += 1;
|
||||
}
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
bool UpdateGraphicsPipelineShaders(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline,
|
||||
Shader* optional_vertexShader, Shader* optional_fragmentShader)
|
||||
{
|
||||
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto d3d12GraphicsPipeline = reinterpret_cast<D3D12GraphicsPipeline*>(graphicsPipeline.Get());
|
||||
|
||||
Assert(d3d12GraphicsPipeline->ReferenceCount == 0 &&
|
||||
"Trying to update a d3d12 graphics pipeline that is currently being used! Call WaitUntilGPUIsIdle "
|
||||
"before updating!");
|
||||
|
||||
auto vertexShader = reinterpret_cast<D3D12Shader*>(optional_vertexShader);
|
||||
auto fragmentShader = reinterpret_cast<D3D12Shader*>(optional_fragmentShader);
|
||||
|
||||
if (!vertexShader)
|
||||
{
|
||||
vertexShader = d3d12GraphicsPipeline->VertexShaderCache;
|
||||
}
|
||||
|
||||
if (!fragmentShader)
|
||||
{
|
||||
fragmentShader = d3d12GraphicsPipeline->FragmentShaderCache;
|
||||
}
|
||||
|
||||
auto psoDesc = d3d12GraphicsPipeline->PSODescTemplate;
|
||||
psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data;
|
||||
psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size;
|
||||
psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data;
|
||||
psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size;
|
||||
|
||||
psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle;
|
||||
|
||||
ID3D12PipelineState* pipelineState;
|
||||
HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState,
|
||||
reinterpret_cast<void**>(&pipelineState));
|
||||
if (FAILED(res))
|
||||
{
|
||||
LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
d3d12GraphicsPipeline->VertexSamplerCount = vertexShader->NumSamplers;
|
||||
d3d12GraphicsPipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures;
|
||||
d3d12GraphicsPipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers;
|
||||
d3d12GraphicsPipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers;
|
||||
|
||||
d3d12GraphicsPipeline->FragmentSamplerCount = fragmentShader->NumSamplers;
|
||||
d3d12GraphicsPipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures;
|
||||
d3d12GraphicsPipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers;
|
||||
d3d12GraphicsPipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers;
|
||||
|
||||
// If everything worked, we patch the graphics pipeline and destroy everything irrelevant
|
||||
if (d3d12GraphicsPipeline->PipelineState)
|
||||
{
|
||||
d3d12GraphicsPipeline->PipelineState->Release();
|
||||
}
|
||||
d3d12GraphicsPipeline->PipelineState = pipelineState;
|
||||
|
||||
if (vertexShader != d3d12GraphicsPipeline->VertexShaderCache)
|
||||
{
|
||||
CopyShader(d3d12GraphicsPipeline->VertexShaderCache, vertexShader);
|
||||
}
|
||||
if (fragmentShader != d3d12GraphicsPipeline->FragmentShaderCache)
|
||||
{
|
||||
CopyShader(d3d12GraphicsPipeline->FragmentShaderCache, fragmentShader);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
void ReleaseGraphicsPipeline(NonNullPtr<D3D12GraphicsPipeline> d3d12GraphicsPipeline)
|
||||
{
|
||||
if (d3d12GraphicsPipeline->PipelineState)
|
||||
{
|
||||
d3d12GraphicsPipeline->PipelineState->Release();
|
||||
}
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
SafeFree(d3d12GraphicsPipeline->VertexShaderCache);
|
||||
SafeFree(d3d12GraphicsPipeline->FragmentShaderCache);
|
||||
#endif
|
||||
|
||||
Free(d3d12GraphicsPipeline.Get());
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
#include <Graphics/D3D12/D3D12Shader.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
#include <Graphics/GraphicsPipeline.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct GraphicsPipelineCreateInfo;
|
||||
struct GPUDriver;
|
||||
struct GraphicsPipeline;
|
||||
} // namespace Juliet
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Shader;
|
||||
|
||||
struct D3D12GraphicsRootSignature
|
||||
{
|
||||
ID3D12RootSignature* Handle;
|
||||
};
|
||||
|
||||
struct D3D12GraphicsPipeline
|
||||
{
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
// Template to recreate an ID3D12PipelineState when shader are hot reloaded
|
||||
// Stripped out in shipping build as the struct is huge
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC PSODescTemplate;
|
||||
|
||||
// Keeping shaders byte code to make it easier to recreate the ID3D12PipelineState
|
||||
// Those will be freed when the pipeline is destroyed or updated
|
||||
D3D12Shader* VertexShaderCache;
|
||||
D3D12Shader* FragmentShaderCache;
|
||||
#endif
|
||||
|
||||
ID3D12PipelineState* PipelineState;
|
||||
D3D12GraphicsRootSignature* RootSignature;
|
||||
PrimitiveType PrimitiveType;
|
||||
|
||||
uint32 VertexStrides[GPUDriver::kMaxVertexBuffers];
|
||||
|
||||
uint32 VertexSamplerCount;
|
||||
uint32 VertexUniformBufferCount;
|
||||
uint32 VertexStorageBufferCount;
|
||||
uint32 VertexStorageTextureCount;
|
||||
|
||||
uint32 FragmentSamplerCount;
|
||||
uint32 FragmentUniformBufferCount;
|
||||
uint32 FragmentStorageBufferCount;
|
||||
uint32 FragmentStorageTextureCount;
|
||||
|
||||
int ReferenceCount;
|
||||
};
|
||||
|
||||
extern GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr<GPUDriver> driver, const GraphicsPipelineCreateInfo& createInfo);
|
||||
extern void DestroyGraphicsPipeline(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
||||
extern bool UpdateGraphicsPipelineShaders(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline,
|
||||
Shader* optional_vertexShader, Shader* optional_fragmentShader);
|
||||
namespace Internal
|
||||
{
|
||||
extern void ReleaseGraphicsPipeline(NonNullPtr<D3D12GraphicsPipeline> d3d12GraphicsPipeline);
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12InternalTests.h>
|
||||
|
||||
#if JULIET_DEBUG
|
||||
|
||||
namespace Juliet::D3D12::UnitTest
|
||||
{
|
||||
using namespace Juliet::D3D12;
|
||||
using namespace Juliet::D3D12::Internal;
|
||||
} // namespace Juliet::D3D12::UnitTest
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
|
||||
#if JULIET_DEBUG
|
||||
namespace Juliet::D3D12::UnitTest
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -1,294 +0,0 @@
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsPipeline.h>
|
||||
#include <Graphics/D3D12/D3D12RenderPass.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
D3D12_PRIMITIVE_TOPOLOGY JulietToD3D12_PrimitiveType[] =
|
||||
{
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
||||
D3D_PRIMITIVE_TOPOLOGY_LINELIST,
|
||||
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
|
||||
D3D_PRIMITIVE_TOPOLOGY_POINTLIST
|
||||
};
|
||||
// clang-format on
|
||||
static_assert(sizeof(JulietToD3D12_PrimitiveType) / sizeof(JulietToD3D12_PrimitiveType[0]) ==
|
||||
ToUnderlying(PrimitiveType::Count));
|
||||
} // namespace
|
||||
|
||||
void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
|
||||
uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
|
||||
uint32 frameBufferWidth = uint32Max;
|
||||
uint32 frameBufferHeight = uint32Max;
|
||||
|
||||
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
|
||||
{
|
||||
auto* container = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].TargetTexture);
|
||||
uint32 width = container->Header.CreateInfo.Width >> colorTargetInfos[idx].MipLevel;
|
||||
uint32 height = container->Header.CreateInfo.Height >> colorTargetInfos[idx].MipLevel;
|
||||
|
||||
// Scale the framebuffer to fit the smallest target.
|
||||
frameBufferWidth = Min(width, frameBufferWidth);
|
||||
frameBufferHeight = Min(height, frameBufferHeight);
|
||||
}
|
||||
|
||||
// Depth Stencil and DSV
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE DSV;
|
||||
bool hasDSV = false;
|
||||
if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture)
|
||||
{
|
||||
auto* container = reinterpret_cast<D3D12TextureContainer*>(depthStencilTargetInfo->TargetTexture);
|
||||
uint32 width = container->Header.CreateInfo.Width;
|
||||
uint32 height = container->Header.CreateInfo.Height;
|
||||
|
||||
frameBufferWidth = Min(width, frameBufferWidth);
|
||||
frameBufferHeight = Min(height, frameBufferHeight);
|
||||
|
||||
D3D12TextureSubresource* subresource =
|
||||
Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
|
||||
DSV = subresource->DSVHandle.CpuHandle;
|
||||
hasDSV = true;
|
||||
d3d12CommandList->DepthStencilSubresource = subresource;
|
||||
|
||||
Internal::TrackTexture(d3d12CommandList, subresource->Parent);
|
||||
|
||||
if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear)
|
||||
{
|
||||
D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH;
|
||||
// TODO: Check if texture has stencil
|
||||
// if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags,
|
||||
depthStencilTargetInfo->ClearDepth,
|
||||
depthStencilTargetInfo->ClearStencil,
|
||||
0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo];
|
||||
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
|
||||
{
|
||||
auto* container = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].TargetTexture);
|
||||
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);
|
||||
|
||||
uint32 RTVIndex = container->Header.CreateInfo.Type == TextureType::Texture_3D ? colorTargetInfos[idx].DepthPlane : 0;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->RTVHandles[RTVIndex].CpuHandle;
|
||||
|
||||
if (colorTargetInfos[idx].LoadOperation == LoadOperation::Clear)
|
||||
{
|
||||
float clearColor[4];
|
||||
clearColor[0] = colorTargetInfos[idx].ClearColor.R;
|
||||
clearColor[1] = colorTargetInfos[idx].ClearColor.G;
|
||||
clearColor[2] = colorTargetInfos[idx].ClearColor.B;
|
||||
clearColor[3] = colorTargetInfos[idx].ClearColor.A;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr);
|
||||
}
|
||||
|
||||
RTVs[idx] = rtv;
|
||||
d3d12CommandList->ColorTargetSubresources[idx] = subresource;
|
||||
|
||||
Internal::TrackTexture(d3d12CommandList, subresource->Parent);
|
||||
|
||||
if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve ||
|
||||
colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore)
|
||||
{
|
||||
auto resolveContainer = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].ResolveTexture);
|
||||
D3D12TextureSubresource* resolveSubresource =
|
||||
Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer,
|
||||
colorTargetInfos[idx].ResolveLayerIndex,
|
||||
colorTargetInfos[idx].ResolveMipLevel,
|
||||
colorTargetInfos[idx].CycleResolveTexture,
|
||||
D3D12_RESOURCE_STATE_RESOLVE_DEST);
|
||||
|
||||
d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource;
|
||||
|
||||
Internal::TrackTexture(d3d12CommandList, resolveSubresource->Parent);
|
||||
}
|
||||
}
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false,
|
||||
hasDSV ? &DSV : nullptr);
|
||||
|
||||
// Set defaults graphics states
|
||||
GraphicsViewPort defaultViewport;
|
||||
defaultViewport.X = 0.f;
|
||||
defaultViewport.Y = 0.f;
|
||||
defaultViewport.Width = static_cast<float>(frameBufferWidth);
|
||||
defaultViewport.Height = static_cast<float>(frameBufferHeight);
|
||||
defaultViewport.MinDepth = 0.f;
|
||||
defaultViewport.MaxDepth = 1.f;
|
||||
SetViewPort(commandList, defaultViewport);
|
||||
|
||||
Rectangle defaultScissor;
|
||||
defaultScissor.X = 0;
|
||||
defaultScissor.Y = 0;
|
||||
defaultScissor.Width = static_cast<int32>(frameBufferWidth);
|
||||
defaultScissor.Height = static_cast<int32>(frameBufferHeight);
|
||||
SetScissorRect(commandList, defaultScissor);
|
||||
|
||||
SetStencilReference(commandList, 0);
|
||||
|
||||
FColor blendConstants;
|
||||
blendConstants.R = 1.0f;
|
||||
blendConstants.G = 1.0f;
|
||||
blendConstants.B = 1.0f;
|
||||
blendConstants.A = 1.0f;
|
||||
SetBlendConstants(commandList, blendConstants);
|
||||
}
|
||||
|
||||
void EndRenderPass(NonNullPtr<CommandList> commandList)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
|
||||
// Reset Color Target state and optionally resolve color texture
|
||||
for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx)
|
||||
{
|
||||
if (d3d12CommandList->ColorTargetSubresources[idx])
|
||||
{
|
||||
if (d3d12CommandList->ColorResolveSubresources[idx])
|
||||
{
|
||||
Internal::TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
|
||||
d3d12CommandList->ColorTargetSubresources[idx]);
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ResolveSubresource(
|
||||
d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource,
|
||||
d3d12CommandList->ColorResolveSubresources[idx]->Index,
|
||||
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource,
|
||||
d3d12CommandList->ColorTargetSubresources[idx]->Index,
|
||||
Internal::ConvertToD3D12TextureFormat(
|
||||
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format));
|
||||
|
||||
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
|
||||
d3d12CommandList->ColorTargetSubresources[idx],
|
||||
D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
|
||||
|
||||
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
|
||||
d3d12CommandList->ColorResolveSubresources[idx],
|
||||
D3D12_RESOURCE_STATE_RESOLVE_DEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
|
||||
d3d12CommandList->ColorTargetSubresources[idx],
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset Depth Stencil state
|
||||
if (d3d12CommandList->DepthStencilSubresource)
|
||||
{
|
||||
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource,
|
||||
D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
d3d12CommandList->DepthStencilSubresource = nullptr;
|
||||
}
|
||||
d3d12CommandList->CurrentGraphicsPipeline = nullptr;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(0, nullptr, false, nullptr);
|
||||
|
||||
// Reset bind states
|
||||
ZeroArray(d3d12CommandList->ColorTargetSubresources);
|
||||
ZeroArray(d3d12CommandList->ColorResolveSubresources);
|
||||
// TODO : reset depth stencil subresources
|
||||
// d3d12CommandList->DepthStencilTextureSubresource = NULL;
|
||||
|
||||
// TODO : vertex buffer
|
||||
// TODO :Vertex sampler and fragment sampler
|
||||
|
||||
// ZeroArray(d3d12CommandList->VertexBuffers);
|
||||
// ZeroArray(d3d12CommandList->VertexBufferOffsets);
|
||||
// d3d12CommandList->VertexBufferCount = 0;
|
||||
//
|
||||
// ZeroArray(d3d12CommandList->VertexSamplerTextures);
|
||||
// ZeroArray(d3d12CommandList->VertexSamplers);
|
||||
// ZeroArray(d3d12CommandList->VertexStorageTextures);
|
||||
// ZeroArray(d3d12CommandList->VertexStorageBuffers);
|
||||
//
|
||||
// ZeroArray(d3d12CommandList->FragmentSamplerTextures);
|
||||
// ZeroArray(d3d12CommandList->FragmentSamplers);
|
||||
// ZeroArray(d3d12CommandList->FragmentStorageTextures);
|
||||
// ZeroArray(d3d12CommandList->FragmentStorageBuffers);
|
||||
}
|
||||
|
||||
void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
auto pipeline = reinterpret_cast<D3D12GraphicsPipeline*>(graphicsPipeline.Get());
|
||||
|
||||
d3d12CommandList->CurrentGraphicsPipeline = pipeline;
|
||||
|
||||
// Set the Descriptor heap
|
||||
if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr)
|
||||
{
|
||||
Internal::SetDescriptorHeaps(d3d12CommandList);
|
||||
}
|
||||
|
||||
// Set the pipeline state
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState);
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle);
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology(
|
||||
JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]);
|
||||
|
||||
// Mark that bindings are needed
|
||||
d3d12CommandList->NeedVertexSamplerBind = true;
|
||||
d3d12CommandList->NeedVertexStorageTextureBind = true;
|
||||
d3d12CommandList->NeedVertexStorageBufferBind = true;
|
||||
d3d12CommandList->NeedFragmentSamplerBind = true;
|
||||
d3d12CommandList->NeedFragmentStorageTextureBind = true;
|
||||
d3d12CommandList->NeedFragmentStorageBufferBind = true;
|
||||
|
||||
for (uint32 idx = 0; idx < GPUDriver::kMaxUniformBuffersPerStage; ++idx)
|
||||
{
|
||||
d3d12CommandList->NeedVertexUniformBufferBind[idx] = true;
|
||||
d3d12CommandList->NeedFragmentUniformBufferBind[idx] = true;
|
||||
}
|
||||
|
||||
for (uint32 idx = 0; idx < pipeline->VertexUniformBufferCount; ++idx)
|
||||
{
|
||||
// if (d3d12CommandList->VertexUniformBuffers[i] == NULL)
|
||||
// {
|
||||
// d3d12CommandList->VertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer);
|
||||
// }
|
||||
}
|
||||
|
||||
for (uint32 idx = 0; idx < pipeline->FragmentUniformBufferCount; ++idx)
|
||||
{
|
||||
// if (d3d12CommandList->FragmentUniformBuffers[i] == NULL)
|
||||
// {
|
||||
// d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer);
|
||||
// }
|
||||
}
|
||||
|
||||
Internal::TrackGraphicsPipeline(d3d12CommandList, pipeline);
|
||||
}
|
||||
|
||||
void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
// TODO : Last missing piece
|
||||
// D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance);
|
||||
}
|
||||
|
||||
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
|
||||
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
|
||||
{
|
||||
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex,
|
||||
static_cast<INT>(vertexOffset), firstInstance);
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
extern void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
|
||||
uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo);
|
||||
extern void EndRenderPass(NonNullPtr<CommandList> commandList);
|
||||
|
||||
extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);
|
||||
extern void DrawPrimitives(NonNullPtr<CommandList> commandList, uint32 numVertices, uint32 numInstances,
|
||||
uint32 firstVertex, uint32 firstInstance);
|
||||
void DrawIndexedPrimitives(NonNullPtr<CommandList> commandList, uint32 numIndices, uint32 numInstances,
|
||||
uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance);
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,48 +0,0 @@
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12Shader.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
Shader* CreateShader(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode,
|
||||
ShaderCreateInfo& /*shaderCreateInfo*/ JULIET_DEBUG_PARAM(String filename))
|
||||
{
|
||||
if (!IsValid(shaderByteCode))
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Invalid shader byte code");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size;
|
||||
auto* shader = static_cast<D3D12Shader*>(
|
||||
ArenaPushSize(driver->DriverArena, allocSize, AlignOf(D3D12Shader),
|
||||
true JULIET_DEBUG_PARAM("D3D12Shader [{}] | Size [{}]", CStr(filename), shaderByteCode.Size)));
|
||||
if (!shader)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Uses the bytes after the struct to store the shader byte code.
|
||||
shader->ByteCode.Data = reinterpret_cast<Byte*>(shader + 1);
|
||||
shader->ByteCode.Size = shaderByteCode.Size;
|
||||
MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size);
|
||||
|
||||
// Make sure the data is correctly copied
|
||||
if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Memory copy failed");
|
||||
Free(shader);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<Shader*>(shader);
|
||||
}
|
||||
|
||||
void DestroyShader(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<Shader> /*shader*/)
|
||||
{
|
||||
// For now we never destroy the shader, it stays in the arena.
|
||||
// If we create too many and need to switch dynamically we will need a way to release the slot for other asset
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
#include <Graphics/Shader.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Shader
|
||||
{
|
||||
ByteBuffer ByteCode;
|
||||
|
||||
uint32 NumSamplers;
|
||||
uint32 NumUniformBuffers;
|
||||
uint32 NumStorageBuffers;
|
||||
uint32 NumStorageTextures;
|
||||
};
|
||||
|
||||
extern Shader* CreateShader(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode,
|
||||
ShaderCreateInfo& shaderCreateInfo JULIET_DEBUG_PARAM(String filename));
|
||||
extern void DestroyShader(NonNullPtr<GPUDriver> driver, NonNullPtr<Shader> shader);
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,372 +0,0 @@
|
||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
#include <Graphics/D3D12/D3D12SwapChain.h>
|
||||
#include <Graphics/D3D12/D3D12Synchronization.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = {
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084
|
||||
};
|
||||
|
||||
DXGI_FORMAT SwapchainCompositionToTextureFormat[] = {
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, // SDR
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format)
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084
|
||||
};
|
||||
|
||||
TextureFormat SwapchainCompositionToJulietTextureFormat[] = {
|
||||
TextureFormat::B8G8R8A8_UNORM, // SDR
|
||||
TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR
|
||||
TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR
|
||||
TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084
|
||||
};
|
||||
|
||||
bool CreateSwapChainTexture(NonNullPtr<D3D12Driver> driver, NonNullPtr<IDXGISwapChain3> swapChain,
|
||||
SwapChainComposition composition, NonNullPtr<D3D12TextureContainer> textureContainer, uint8 index)
|
||||
{
|
||||
ID3D12Resource* swapChainTexture = nullptr;
|
||||
HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast<void**>(&swapChainTexture));
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = static_cast<D3D12Texture*>(Calloc(1, sizeof(D3D12Texture)));
|
||||
if (!texture)
|
||||
{
|
||||
LogError(driver->D3D12Device, "Cannot allocate D3D12Texture (out of memory)", result);
|
||||
swapChainTexture->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
texture->ReferenceCount += 1;
|
||||
texture->SubresourceCount = 1;
|
||||
texture->Subresources = static_cast<D3D12TextureSubresource*>(Calloc(1, sizeof(D3D12TextureSubresource)));
|
||||
if (!texture->Subresources)
|
||||
{
|
||||
LogError(driver->D3D12Device, "Cannot allocate D3D12TextureSubresource (out of memory)", result);
|
||||
Free(texture);
|
||||
swapChainTexture->Release();
|
||||
return false;
|
||||
}
|
||||
texture->Subresources[0].RTVHandles =
|
||||
static_cast<D3D12StagingDescriptor*>(Calloc(1, sizeof(D3D12StagingDescriptor)));
|
||||
texture->Subresources[0].UAVHandle.Heap = nullptr;
|
||||
texture->Subresources[0].UAVHandle.Heap = nullptr;
|
||||
texture->Subresources[0].Parent = texture;
|
||||
texture->Subresources[0].Index = 0;
|
||||
texture->Subresources[0].Layer = 0;
|
||||
texture->Subresources[0].Depth = 1;
|
||||
texture->Subresources[0].Level = 0;
|
||||
|
||||
D3D12_RESOURCE_DESC textureDesc = swapChainTexture->GetDesc();
|
||||
textureContainer->Header.CreateInfo.Width = static_cast<uint32>(textureDesc.Width);
|
||||
textureContainer->Header.CreateInfo.Height = static_cast<uint32>(textureDesc.Height);
|
||||
textureContainer->Header.CreateInfo.LayerCount = 1;
|
||||
textureContainer->Header.CreateInfo.MipLevelCount = 1;
|
||||
textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D;
|
||||
textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget;
|
||||
textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One;
|
||||
textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)];
|
||||
|
||||
textureContainer->Textures = static_cast<D3D12Texture**>(Calloc(1, sizeof(D3D12Texture*)));
|
||||
if (!textureContainer->Textures)
|
||||
{
|
||||
Free(texture->Subresources);
|
||||
Free(texture);
|
||||
swapChainTexture->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
textureContainer->Capacity = 1;
|
||||
textureContainer->Count = 1;
|
||||
textureContainer->Textures[0] = texture;
|
||||
textureContainer->ActiveTexture = texture;
|
||||
textureContainer->CanBeCycled = false;
|
||||
|
||||
texture->Container = textureContainer;
|
||||
texture->IndexInContainer = 0;
|
||||
|
||||
// Assign RTV to the swapchain texture
|
||||
DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
|
||||
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;
|
||||
rtvDesc.Texture2D.MipSlice = 0;
|
||||
rtvDesc.Texture2D.PlaneSlice = 0;
|
||||
|
||||
driver->D3D12Device->CreateRenderTargetView(swapChainTexture, &rtvDesc,
|
||||
texture->Subresources[0].RTVHandles[0].CpuHandle);
|
||||
|
||||
swapChainTexture->Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AcquireSwapChainTexture(bool block, NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapchainTexture)
|
||||
{
|
||||
auto d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
|
||||
|
||||
auto* driver = d3d12CommandList->Driver;
|
||||
Assert(driver->WindowData);
|
||||
|
||||
// TODO: Find a way to fetch window data more smoothly from the window ptr
|
||||
// In the mean time i will just void it or the variable is unused and cause a warning
|
||||
(void)window;
|
||||
auto* windowData = driver->WindowData;
|
||||
Assert(windowData->Window == window.Get());
|
||||
|
||||
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
|
||||
{
|
||||
if (block)
|
||||
{
|
||||
// Wait until the fence for the frame is signaled.
|
||||
// In VSYNC this means waiting that the least recent presented frame is done
|
||||
if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter],
|
||||
1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture"))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If work is not done, the least recent fence wont be signaled.
|
||||
// In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture
|
||||
if (!QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM(
|
||||
ConstString("AcquireSwapChainTexture")));
|
||||
windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr;
|
||||
}
|
||||
|
||||
uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex();
|
||||
HRESULT result = windowData->SwapChain->GetBuffer(
|
||||
swapchainIndex, IID_ID3D12Resource,
|
||||
reinterpret_cast<void**>(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource));
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Could not acquire swapchain", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// When the swap chain texture is acquired it's time to present
|
||||
Assert(d3d12CommandList->PresentDataCount + 1 <= d3d12CommandList->PresentDataCapacity);
|
||||
d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData;
|
||||
d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex;
|
||||
d3d12CommandList->PresentDataCount += 1;
|
||||
|
||||
// Create the presentation barrier.
|
||||
D3D12_RESOURCE_BARRIER barrierDesc;
|
||||
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrierDesc.Transition.pResource = windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource;
|
||||
barrierDesc.Transition.Subresource = 0;
|
||||
|
||||
d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc);
|
||||
|
||||
*swapchainTexture = reinterpret_cast<Texture*>(&windowData->SwapChainTextureContainers[swapchainIndex]);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
|
||||
{
|
||||
return AcquireSwapChainTexture(false, commandList, window, swapChainTexture);
|
||||
}
|
||||
|
||||
bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
|
||||
{
|
||||
return AcquireSwapChainTexture(true, commandList, window, swapChainTexture);
|
||||
}
|
||||
|
||||
bool WaitForSwapchain(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> /*window*/)
|
||||
{
|
||||
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto* windowData = d3d12Driver->WindowData;
|
||||
if (!windowData)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr)
|
||||
{
|
||||
if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter],
|
||||
1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain"))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TextureFormat GetSwapChainTextureFormat(NonNullPtr<GPUDriver> driver, [[maybe_unused]] NonNullPtr<Window> window)
|
||||
{
|
||||
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
|
||||
auto* windowData = d3d12Driver->WindowData;
|
||||
if (!windowData)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Cannot get swapchain format. Window has no Swapchain");
|
||||
return TextureFormat::Invalid;
|
||||
}
|
||||
|
||||
Assert(windowData->Window == window.Get());
|
||||
return windowData->SwapChainTextureContainers[windowData->WindowFrameCounter].Header.CreateInfo.Format;
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
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 = driver->DXGIFactory->CreateSwapChainForHwnd(static_cast<IUnknown*>(driver->GraphicsQueue),
|
||||
windowHandle, &swapChainDesc,
|
||||
&swapChainFullscreenDesc, nullptr, &swapChain);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Failed to create SwapChain", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
IDXGISwapChain3* swapChain3 = nullptr;
|
||||
result = swapChain->QueryInterface(IID_IDXGISwapChain3, reinterpret_cast<void**>(&swapChain3));
|
||||
swapChain->Release();
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Could not query IDXGISwapChain3 interface", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (composition != SwapChainComposition::SDR)
|
||||
{
|
||||
swapChain3->SetColorSpace1(SwapchainCompositionToColorSpace[ToUnderlying(composition)]);
|
||||
}
|
||||
|
||||
IDXGIFactory1* parentFactory = nullptr;
|
||||
result = swapChain3->GetParent(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 = parentFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES);
|
||||
if (FAILED(result))
|
||||
{
|
||||
Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result);
|
||||
}
|
||||
parentFactory->Release();
|
||||
}
|
||||
|
||||
swapChain3->GetDesc1(&swapChainDesc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "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))
|
||||
{
|
||||
swapChain3->Release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
|
||||
{
|
||||
for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
windowData->SwapChain->Release();
|
||||
windowData->SwapChain = nullptr;
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
// Forward Declare
|
||||
struct D3D12Driver;
|
||||
struct D3D12WindowData;
|
||||
|
||||
extern bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
|
||||
extern bool WaitAndAcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
|
||||
extern bool WaitForSwapchain(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
|
||||
extern TextureFormat GetSwapChainTextureFormat(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
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
|
||||
@@ -1,268 +0,0 @@
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Synchronization.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void ReleaseFenceToPool(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12Fence> fence)
|
||||
{
|
||||
Assert(driver->AvailableFenceCount + 1 <= driver->AvailableFenceCapacity);
|
||||
|
||||
driver->AvailableFences[driver->AvailableFenceCount] = fence;
|
||||
driver->AvailableFenceCount += 1;
|
||||
|
||||
LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d",
|
||||
fence.Get(), fence->Handle, fence->Event, fence->ReferenceCount);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver)
|
||||
{
|
||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
D3D12Fence* fence = Internal::AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle")));
|
||||
if (!fence)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d3d12driver->GraphicsQueue)
|
||||
{
|
||||
// Insert a signal into the end of the command queue...
|
||||
d3d12driver->GraphicsQueue->Signal(fence->Handle, D3D12_FENCE_SIGNAL_VALUE);
|
||||
|
||||
// ...and then block on it.
|
||||
if (fence->Handle->GetCompletedValue() != D3D12_FENCE_SIGNAL_VALUE)
|
||||
{
|
||||
HRESULT result = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(d3d12driver->D3D12Device, "Setting fence event failed!", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE);
|
||||
if (waitResult == WAIT_FAILED)
|
||||
{
|
||||
LogError(d3d12driver->D3D12Device, "Wait failed!", result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseFence(driver, reinterpret_cast<Fence*>(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle")));
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Clean up
|
||||
{
|
||||
int32 idx = 0;
|
||||
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||
{
|
||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
||||
// CleanCommandList swaps [idx] with last and decrements count.
|
||||
// Don't increment — re-check the swapped-in element.
|
||||
}
|
||||
}
|
||||
|
||||
Internal::DisposePendingResourcces(d3d12driver);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences, uint32 numFences JULIET_DEBUG_PARAM(String querier))
|
||||
{
|
||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
|
||||
TempArena tempArena = ArenaTempBegin(d3d12driver->DriverArena);
|
||||
|
||||
HANDLE* events =
|
||||
ArenaPushArray<HANDLE>(tempArena.Arena, numFences JULIET_DEBUG_PARAM("Wait() HANDLE - JUST IN CASE"));
|
||||
MemoryZero(events, sizeof(HANDLE) * numFences);
|
||||
|
||||
for (uint32 i = 0; i < numFences; ++i)
|
||||
{
|
||||
D3D12Fence* fence = reinterpret_cast<D3D12Fence*>(fences[i]);
|
||||
|
||||
HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event);
|
||||
if (FAILED(res))
|
||||
{
|
||||
LogError(d3d12driver->D3D12Device, "Setting fence event failed!", res);
|
||||
ArenaTempEnd(tempArena);
|
||||
return false;
|
||||
}
|
||||
|
||||
events[i] = fence->Event;
|
||||
}
|
||||
#if JULIET_DEBUG
|
||||
LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier));
|
||||
#endif
|
||||
for (uint32 i = 0; i < numFences; ++i)
|
||||
{
|
||||
D3D12Fence* d3d12fence = reinterpret_cast<D3D12Fence*>(fences[i]);
|
||||
LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence,
|
||||
d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount);
|
||||
}
|
||||
|
||||
DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE);
|
||||
|
||||
ArenaTempEnd(tempArena);
|
||||
|
||||
if (waitResult == WAIT_FAILED)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Wait failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Clean up
|
||||
{
|
||||
int32 idx = 0;
|
||||
while (idx < d3d12driver->SubmittedCommandListCount)
|
||||
{
|
||||
uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue();
|
||||
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
|
||||
{
|
||||
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Internal::DisposePendingResourcces(d3d12driver);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QueryFence(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<Fence> /*fence*/)
|
||||
{
|
||||
Unimplemented();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier))
|
||||
{
|
||||
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto d3d12Fence = reinterpret_cast<D3D12Fence*>(fence.Get());
|
||||
|
||||
#if JULIET_DEBUG
|
||||
LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s",
|
||||
d3d12Fence, d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier));
|
||||
#endif
|
||||
if (--d3d12Fence->ReferenceCount == 0)
|
||||
{
|
||||
ReleaseFenceToPool(d3d12driver, d3d12Fence);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
|
||||
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex,
|
||||
bool needsUavBarrier)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrierDesc[2];
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (needsUavBarrier)
|
||||
{
|
||||
barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
|
||||
barrierDesc[numBarriers].Flags = static_cast<D3D12_RESOURCE_BARRIER_FLAGS>(0);
|
||||
barrierDesc[numBarriers].UAV.pResource = resource;
|
||||
|
||||
numBarriers += 1;
|
||||
}
|
||||
|
||||
if (numBarriers > 0)
|
||||
{
|
||||
commandList->GraphicsCommandList.CommandList->ResourceBarrier(numBarriers, barrierDesc);
|
||||
}
|
||||
}
|
||||
|
||||
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver JULIET_DEBUG_PARAM(String querier))
|
||||
{
|
||||
D3D12Fence* fence;
|
||||
ID3D12Fence* handle;
|
||||
|
||||
// TODO :Thread safe (lock + atomic)
|
||||
|
||||
if (driver->AvailableFenceCount == 0)
|
||||
{
|
||||
HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
|
||||
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver->D3D12Device, "Failed to create fence!", result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fence = ArenaPushStruct<D3D12Fence>(driver->DriverArena JULIET_DEBUG_PARAM("D3D12Fence"));
|
||||
if (!fence)
|
||||
{
|
||||
handle->Release();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
fence->Handle = handle;
|
||||
fence->Event = CreateEvent(nullptr, false, false, nullptr);
|
||||
fence->ReferenceCount = 0;
|
||||
#if JULIET_DEBUG
|
||||
LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
fence = driver->AvailableFences[driver->AvailableFenceCount - 1];
|
||||
driver->AvailableFenceCount -= 1;
|
||||
fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE);
|
||||
#if JULIET_DEBUG
|
||||
LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier));
|
||||
#endif
|
||||
}
|
||||
|
||||
fence->ReferenceCount += 1;
|
||||
Assert(fence->ReferenceCount == 1);
|
||||
|
||||
#if JULIET_DEBUG
|
||||
LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d",
|
||||
CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount);
|
||||
#endif
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
void DestroyFence(NonNullPtr<D3D12Fence> fence)
|
||||
{
|
||||
if (fence->Handle)
|
||||
{
|
||||
fence->Handle->Release();
|
||||
}
|
||||
|
||||
if (fence->Event)
|
||||
{
|
||||
CloseHandle(fence->Event);
|
||||
}
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
{
|
||||
#define D3D12_FENCE_UNSIGNALED_VALUE 0
|
||||
#define D3D12_FENCE_SIGNAL_VALUE 1
|
||||
|
||||
// Forward Declare
|
||||
struct D3D12CommandList;
|
||||
|
||||
struct D3D12Fence
|
||||
{
|
||||
ID3D12Fence* Handle;
|
||||
HANDLE Event; // used for blocking
|
||||
int32 ReferenceCount; // TODO : Atomic
|
||||
};
|
||||
|
||||
extern bool WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver);
|
||||
extern bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences,
|
||||
uint32 numFences JULIET_DEBUG_PARAM(String querier));
|
||||
extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
||||
extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier));
|
||||
|
||||
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 JULIET_DEBUG_PARAM(String querier));
|
||||
extern void DestroyFence(NonNullPtr<D3D12Fence> fence);
|
||||
} // namespace Internal
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,579 +0,0 @@
|
||||
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12CommandList.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Synchronization.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
DXGI_FORMAT JulietToD3D12_TextureFormat[] = {
|
||||
DXGI_FORMAT_UNKNOWN, // INVALID
|
||||
DXGI_FORMAT_A8_UNORM, // A8_UNORM
|
||||
DXGI_FORMAT_R8_UNORM, // R8_UNORM
|
||||
DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM
|
||||
DXGI_FORMAT_R16_UNORM, // R16_UNORM
|
||||
DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM
|
||||
DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM
|
||||
DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM
|
||||
DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM
|
||||
DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM
|
||||
DXGI_FORMAT_BC1_UNORM, // BC1_UNORM
|
||||
DXGI_FORMAT_BC2_UNORM, // BC2_UNORM
|
||||
DXGI_FORMAT_BC3_UNORM, // BC3_UNORM
|
||||
DXGI_FORMAT_BC4_UNORM, // BC4_UNORM
|
||||
DXGI_FORMAT_BC5_UNORM, // BC5_UNORM
|
||||
DXGI_FORMAT_BC7_UNORM, // BC7_UNORM
|
||||
DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT
|
||||
DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT
|
||||
DXGI_FORMAT_R8_SNORM, // R8_SNORM
|
||||
DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM
|
||||
DXGI_FORMAT_R16_SNORM, // R16_SNORM
|
||||
DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM
|
||||
DXGI_FORMAT_R16_FLOAT, // R16_FLOAT
|
||||
DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT
|
||||
DXGI_FORMAT_R32_FLOAT, // R32_FLOAT
|
||||
DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT
|
||||
DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT
|
||||
DXGI_FORMAT_R8_UINT, // R8_UINT
|
||||
DXGI_FORMAT_R8G8_UINT, // R8G8_UINT
|
||||
DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT
|
||||
DXGI_FORMAT_R16_UINT, // R16_UINT
|
||||
DXGI_FORMAT_R16G16_UINT, // R16G16_UINT
|
||||
DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT
|
||||
DXGI_FORMAT_R32_UINT, // R32_UINT
|
||||
DXGI_FORMAT_R32G32_UINT, // R32G32_UINT
|
||||
DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT
|
||||
DXGI_FORMAT_R8_SINT, // R8_INT
|
||||
DXGI_FORMAT_R8G8_SINT, // R8G8_INT
|
||||
DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT
|
||||
DXGI_FORMAT_R16_SINT, // R16_INT
|
||||
DXGI_FORMAT_R16G16_SINT, // R16G16_INT
|
||||
DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT
|
||||
DXGI_FORMAT_R32_SINT, // R32_INT
|
||||
DXGI_FORMAT_R32G32_SINT, // R32G32_INT
|
||||
DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB
|
||||
DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB
|
||||
DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB
|
||||
DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB
|
||||
DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB
|
||||
DXGI_FORMAT_R16_TYPELESS, // D16_UNORM
|
||||
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM
|
||||
DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT
|
||||
DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT
|
||||
DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
|
||||
};
|
||||
static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) ==
|
||||
ToUnderlying(TextureFormat::Count));
|
||||
|
||||
DXGI_FORMAT JulietToD3D12_DepthFormat[] = {
|
||||
DXGI_FORMAT_UNKNOWN, // INVALID
|
||||
DXGI_FORMAT_UNKNOWN, // A8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC1_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC2_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC3_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC7_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R8_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM
|
||||
DXGI_FORMAT_UNKNOWN, // R16_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R32_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // R8_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R16_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R32_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // R8_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R16_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R32_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT
|
||||
DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB
|
||||
DXGI_FORMAT_D16_UNORM, // D16_UNORM
|
||||
DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM
|
||||
DXGI_FORMAT_D32_FLOAT, // D32_FLOAT
|
||||
DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT
|
||||
DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
|
||||
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
|
||||
};
|
||||
static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count));
|
||||
|
||||
uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels)
|
||||
{
|
||||
return mipLevel + (layer * numLevels);
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_STATES GetDefaultTextureResourceState(TextureUsageFlag usageFlags)
|
||||
{
|
||||
if ((usageFlags & TextureUsageFlag::Sampler) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::GraphicsStorageRead) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::ComputeStorageRead) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
}
|
||||
if ((usageFlags & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None)
|
||||
{
|
||||
return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
}
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Texture has no default usage mode!");
|
||||
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList,
|
||||
NonNullPtr<D3D12TextureContainer> container,
|
||||
uint32 layer, uint32 level, bool shouldCycle,
|
||||
D3D12_RESOURCE_STATES newTextureUsage)
|
||||
{
|
||||
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level);
|
||||
if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0)
|
||||
{
|
||||
// TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective)
|
||||
// CycleActiveTexture(commandList->Driver, container);
|
||||
|
||||
subresource = Internal::FetchTextureSubresource(container, layer, level);
|
||||
}
|
||||
|
||||
Internal::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);
|
||||
Internal::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);
|
||||
}
|
||||
}
|
||||
|
||||
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)];
|
||||
}
|
||||
|
||||
DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format)
|
||||
{
|
||||
return JulietToD3D12_DepthFormat[ToUnderlying(format)];
|
||||
}
|
||||
|
||||
uint32 JulietToD3D12_SampleCount[] = {
|
||||
1, // MSAA 1x
|
||||
2, // MSAA 2x
|
||||
4, // MSAA 4x
|
||||
8, // MSAA 8x
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
Texture* CreateTexture(NonNullPtr<GPUDriver> driver, const TextureCreateInfo& createInfo)
|
||||
{
|
||||
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
switch (createInfo.Type)
|
||||
{
|
||||
case TextureType::Texture_2D:
|
||||
case TextureType::Texture_2DArray:
|
||||
case TextureType::Texture_Cube:
|
||||
case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break;
|
||||
case TextureType::Texture_3D:
|
||||
case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break;
|
||||
}
|
||||
|
||||
desc.Alignment = 0;
|
||||
desc.Width = createInfo.Width;
|
||||
desc.Height = createInfo.Height;
|
||||
desc.DepthOrArraySize = static_cast<uint16>(createInfo.LayerCount);
|
||||
desc.MipLevels = static_cast<uint16>(createInfo.MipLevelCount);
|
||||
desc.Format = Internal::ConvertToD3D12TextureFormat(createInfo.Format);
|
||||
desc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)];
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||
}
|
||||
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
}
|
||||
if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None)
|
||||
{
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation
|
||||
heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation
|
||||
|
||||
ID3D12Resource* resource = nullptr;
|
||||
D3D12_CLEAR_VALUE clearValue = {};
|
||||
D3D12_CLEAR_VALUE* pClearValue = nullptr;
|
||||
|
||||
if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
|
||||
{
|
||||
clearValue.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format);
|
||||
clearValue.DepthStencil.Depth = 1.0f;
|
||||
clearValue.DepthStencil.Stencil = 0;
|
||||
pClearValue = &clearValue;
|
||||
}
|
||||
else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
|
||||
{
|
||||
clearValue.Format = desc.Format;
|
||||
clearValue.Color[0] = 0.0f;
|
||||
clearValue.Color[1] = 0.0f;
|
||||
clearValue.Color[2] = 0.0f;
|
||||
clearValue.Color[3] = 0.0f;
|
||||
pClearValue = &clearValue;
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags);
|
||||
HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc,
|
||||
initialState, pClearValue, IID_ID3D12Resource,
|
||||
reinterpret_cast<void**>(&resource));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* textureContainer = static_cast<D3D12TextureContainer*>(Calloc(1, sizeof(D3D12TextureContainer)));
|
||||
auto* texture = static_cast<D3D12Texture*>(Calloc(1, sizeof(D3D12Texture)));
|
||||
|
||||
textureContainer->Header.CreateInfo = createInfo;
|
||||
textureContainer->ActiveTexture = texture;
|
||||
textureContainer->Textures = static_cast<D3D12Texture**>(Malloc(sizeof(D3D12Texture*)));
|
||||
textureContainer->Textures[0] = texture;
|
||||
textureContainer->Capacity = 1;
|
||||
textureContainer->Count = 1;
|
||||
textureContainer->CanBeCycled = true;
|
||||
|
||||
texture->Container = textureContainer;
|
||||
texture->Resource = resource;
|
||||
texture->ReferenceCount = 1;
|
||||
|
||||
uint32 numLayers = std::max<uint32>(1, createInfo.LayerCount);
|
||||
uint32 numMips = std::max<uint32>(1, createInfo.MipLevelCount);
|
||||
texture->SubresourceCount = numLayers * numMips;
|
||||
texture->Subresources =
|
||||
static_cast<D3D12TextureSubresource*>(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource)));
|
||||
|
||||
for (uint32 layer = 0; layer < numLayers; ++layer)
|
||||
{
|
||||
for (uint32 mip = 0; mip < numMips; ++mip)
|
||||
{
|
||||
uint32 index = mip + (layer * numMips);
|
||||
auto& sub = texture->Subresources[index];
|
||||
sub.Parent = texture;
|
||||
sub.Layer = layer;
|
||||
sub.Level = mip;
|
||||
sub.Index = index;
|
||||
sub.Depth = 1; // 3D texture depth handling would go here
|
||||
|
||||
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
sub.RTVHandles = static_cast<D3D12StagingDescriptor*>(Calloc(1, sizeof(D3D12StagingDescriptor)));
|
||||
Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]);
|
||||
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||
rtvDesc.Format = desc.Format;
|
||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
rtvDesc.Texture2D.MipSlice = mip;
|
||||
d3d12Driver->D3D12Device->CreateRenderTargetView(resource, &rtvDesc, sub.RTVHandles[0].CpuHandle);
|
||||
}
|
||||
|
||||
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
|
||||
{
|
||||
Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle);
|
||||
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
||||
dsvDesc.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format);
|
||||
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||
dsvDesc.Texture2D.MipSlice = mip;
|
||||
d3d12Driver->D3D12Device->CreateDepthStencilView(resource, &dsvDesc, sub.DSVHandle.CpuHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create SRV for sampled/readable textures (bindless access)
|
||||
// Assign to the bindless CBV_SRV_UAV heap
|
||||
{
|
||||
Internal::D3D12Descriptor descriptor;
|
||||
if (Internal::AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor))
|
||||
{
|
||||
texture->SRVHandle = D3D12StagingDescriptor{};
|
||||
texture->SRVHandle.CpuHandleIndex = descriptor.Index;
|
||||
texture->SRVHandle.CpuHandle = descriptor.CpuHandle;
|
||||
texture->SRVHandle.Heap = descriptor.Heap;
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = desc.Format;
|
||||
|
||||
// Fix SRV format for Depth Buffers (TypeLess -> Typed)
|
||||
if (createInfo.Format == TextureFormat::D32_FLOAT)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
||||
}
|
||||
else if (createInfo.Format == TextureFormat::D16_UNORM)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R16_UNORM;
|
||||
}
|
||||
else if (createInfo.Format == TextureFormat::D24_UNORM_S8_UINT)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
}
|
||||
else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
}
|
||||
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
srvDesc.Texture2D.MipLevels = numMips;
|
||||
srvDesc.Texture2D.PlaneSlice = 0;
|
||||
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
||||
|
||||
d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return reinterpret_cast<Texture*>(textureContainer);
|
||||
}
|
||||
|
||||
void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture)
|
||||
{
|
||||
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
|
||||
auto* textureContainer = reinterpret_cast<D3D12TextureContainer*>(texture.Get());
|
||||
|
||||
for (uint32 i = 0; i < textureContainer->Count; ++i)
|
||||
{
|
||||
D3D12Texture* d3d12Texture = textureContainer->Textures[i];
|
||||
for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j)
|
||||
{
|
||||
D3D12TextureSubresource& sub = d3d12Texture->Subresources[j];
|
||||
if (sub.RTVHandles)
|
||||
{
|
||||
Internal::ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]);
|
||||
Free(sub.RTVHandles);
|
||||
}
|
||||
if (sub.DSVHandle.Heap)
|
||||
{
|
||||
Internal::ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle);
|
||||
}
|
||||
}
|
||||
d3d12Texture->Resource->Release();
|
||||
Free(d3d12Texture->Subresources);
|
||||
Free(d3d12Texture);
|
||||
}
|
||||
|
||||
Free(textureContainer->Textures);
|
||||
Free(textureContainer);
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
struct ID3D12Resource;
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
// Forward Declare
|
||||
struct D3D12Texture;
|
||||
struct D3D12ResourceHeap;
|
||||
struct D3D12CommandList;
|
||||
|
||||
struct D3D12TextureContainer
|
||||
{
|
||||
TextureHeader Header;
|
||||
|
||||
D3D12Texture* ActiveTexture;
|
||||
D3D12Texture** Textures;
|
||||
uint32 Capacity;
|
||||
uint32 Count;
|
||||
|
||||
// Note: Swapchain images cannot be cycled
|
||||
bool CanBeCycled;
|
||||
|
||||
#if JULIET_DEBUG
|
||||
char* DebugName;
|
||||
#endif
|
||||
};
|
||||
|
||||
// D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..)
|
||||
struct D3D12TextureSubresource
|
||||
{
|
||||
D3D12Texture* Parent;
|
||||
uint32 Layer;
|
||||
uint32 Level;
|
||||
uint32 Depth;
|
||||
uint32 Index;
|
||||
|
||||
// One per depth slice
|
||||
D3D12StagingDescriptor* RTVHandles; // NULL if not a color target
|
||||
|
||||
D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture
|
||||
D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target
|
||||
};
|
||||
|
||||
struct D3D12Texture
|
||||
{
|
||||
D3D12TextureContainer* Container;
|
||||
uint32 IndexInContainer;
|
||||
|
||||
ID3D12Resource* Resource;
|
||||
|
||||
D3D12TextureSubresource* Subresources;
|
||||
uint32 SubresourceCount; // Layer Count * number of Levels
|
||||
|
||||
D3D12StagingDescriptor SRVHandle;
|
||||
|
||||
// TODO: Should be atomic to support multithreading
|
||||
int32 ReferenceCount;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
// Utils
|
||||
extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format);
|
||||
extern DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format);
|
||||
extern uint32 JulietToD3D12_SampleCount[];
|
||||
} // namespace Internal
|
||||
|
||||
extern Texture* CreateTexture(NonNullPtr<GPUDriver> driver, const TextureCreateInfo& createInfo);
|
||||
extern void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture);
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,71 +0,0 @@
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/D3D12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
// From SDLGPU
|
||||
// TODO Do my own version.
|
||||
extern void LogError(NonNullPtr<ID3D12Device5> D3D12Device, const char* errorMessage, HRESULT result)
|
||||
{
|
||||
#define MAX_ERROR_LEN 1024 // FIXME: Arbitrary!
|
||||
|
||||
// Buffer for text, ensure space for \0 terminator after buffer
|
||||
char wszMsgBuff[MAX_ERROR_LEN + 1];
|
||||
// Number of chars returned.
|
||||
|
||||
if (result == DXGI_ERROR_DEVICE_REMOVED)
|
||||
{
|
||||
result = D3D12Device->GetDeviceRemovedReason();
|
||||
}
|
||||
|
||||
// Try to get the message from the system errors.
|
||||
DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
|
||||
static_cast<DWORD>(result), 0, wszMsgBuff, MAX_ERROR_LEN, nullptr);
|
||||
|
||||
// No message? Screw it, just post the code.
|
||||
if (dwChars == 0)
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: " HRESULT_FMT, errorMessage, result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure valid range
|
||||
dwChars = Min<DWORD>(dwChars, MAX_ERROR_LEN);
|
||||
|
||||
// Trim whitespace from tail of message
|
||||
while (dwChars > 0)
|
||||
{
|
||||
if (wszMsgBuff[dwChars - 1] <= ' ')
|
||||
{
|
||||
dwChars--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure null-terminated string
|
||||
wszMsgBuff[dwChars] = '\0';
|
||||
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: %s" HRESULT_FMT, errorMessage, wszMsgBuff, result);
|
||||
}
|
||||
|
||||
#if JULIET_DEBUG
|
||||
String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV");
|
||||
case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER");
|
||||
case D3D12_DESCRIPTOR_HEAP_TYPE_RTV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_RTV");
|
||||
case D3D12_DESCRIPTOR_HEAP_TYPE_DSV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_DSV");
|
||||
case D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES: return WrapString("Invalid");
|
||||
}
|
||||
return WrapString("Invalid");
|
||||
}
|
||||
#endif
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define HRESULT_FMT "(0x%08lX)"
|
||||
#else
|
||||
#define HRESULT_FMT "(0x%08X)"
|
||||
#endif
|
||||
|
||||
#define TOD3D12FuncPtr(type, ptr) reinterpret_cast<type>(reinterpret_cast<void*>(ptr))
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Driver;
|
||||
|
||||
extern void LogError(NonNullPtr<ID3D12Device5> D3D12Device, const char* errorMessage, HRESULT result);
|
||||
|
||||
#if JULIET_DEBUG
|
||||
String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type);
|
||||
#endif
|
||||
} // namespace Juliet::D3D12
|
||||
Reference in New Issue
Block a user