Compare commits

...
2 Commits
Author SHA1 Message Date
Patedam ab158e8b3d Merged all d3d12 files into one file 2026-08-08 23:06:29 -04:00
Patedam 403e70b14d fixing random build issue 2026-08-08 18:39:17 -04:00
29 changed files with 4560 additions and 5064 deletions
-1
View File
@@ -1,7 +1,6 @@
#pragma once
#include <Core/Common/CoreTypes.h>
#include <Graphics/D3D12/D3D12Buffer.h>
#include <Juliet.h>
namespace Juliet
+1 -3
View File
@@ -1,10 +1,8 @@
#include <Core/Common/CoreUtils.h>
#include <Core/Common/EnumUtils.h>
#include <Core/HAL/Display/Display_Private.h>
#include <Core/HAL/Filesystem/Filesystem_Private.h>
#include <Core/HAL/Display/Display_cpp.h>
#include <Core/JulietInit.h>
#include <Core/Logging/LogManager.h>
#include <Core/Memory/MemoryArena.h>
namespace Juliet
{
-357
View File
@@ -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
-42
View File
@@ -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
-122
View File
@@ -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
-51
View File
@@ -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
-48
View File
@@ -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
-22
View File
@@ -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
-579
View File
@@ -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
-97
View File
@@ -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
-71
View File
@@ -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
-22
View File
@@ -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
+4 -4
View File
@@ -1094,10 +1094,10 @@ static void GenerateProject(const char* projectName, const char* projectDir, con
const char* cfg = configs[i];
offset += sprintf_s(buf + offset, (4 * 1024 * 1024) - offset,
" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='%s|x64'\">\n"
" <NMakeBuildCommandLine>cd $(SolutionDir) &amp; misc\\build.bat %s $(SolutionName)</NMakeBuildCommandLine>\n"
" <NMakeReBuildCommandLine>cd $(SolutionDir) &amp; misc\\build.bat -clean %s $(SolutionName)</NMakeReBuildCommandLine>\n"
" <NMakeCleanCommandLine>cd $(SolutionDir) &amp; misc\\build.bat -clean %s $(SolutionName)</NMakeCleanCommandLine>\n"
" <NMakeOutput>$(SolutionDir)bin\\x64-%s\\%s.exe</NMakeOutput>\n"
" <NMakeBuildCommandLine>cd $(SolutionDir)..\\ &amp; misc\\build.bat %s $(SolutionName)</NMakeBuildCommandLine>\n"
" <NMakeReBuildCommandLine>cd $(SolutionDir)..\\ &amp; misc\\build.bat -clean %s $(SolutionName)</NMakeReBuildCommandLine>\n"
" <NMakeCleanCommandLine>cd $(SolutionDir)..\\ &amp; misc\\build.bat -clean %s $(SolutionName)</NMakeCleanCommandLine>\n"
" <NMakeOutput>$(SolutionDir)..\\bin\\x64-%s\\%s.exe</NMakeOutput>\n"
" <NMakeIncludeSearchPath>%s$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\n"
" <IncludePath>%s$(IncludePath)</IncludePath>\n",
cfg, cfg, cfg, cfg, cfg, projectName, includeSearchPath, includeSearchPath);