diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj
index a018e53..354d512 100644
--- a/Juliet/Juliet.vcxproj
+++ b/Juliet/Juliet.vcxproj
@@ -151,7 +151,8 @@
-
+
+
@@ -231,7 +232,7 @@
-
+
MultiThreadedDebugDll
diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h
index 0bdf79f..48ab593 100644
--- a/Juliet/include/Graphics/Graphics.h
+++ b/Juliet/include/Graphics/Graphics.h
@@ -21,14 +21,14 @@ namespace Juliet
// Parameters of an INDEXED indirect draw command
struct IndexedIndirectDrawCommand
{
- uint32 VertexCount; // Number of vertices to draw
- uint32 InstanceCount; // Number of instanced to draw
+ uint32 VertexCount; // Number of vertices to draw
+ uint32 InstanceCount; // Number of instanced to draw
uint32 FirstIndex; // Base Index within the index buffer
- int32 VertexOffset; // Offset the vertex index into the buffer
+ int32 VertexOffset; // Offset the vertex index into the buffer
uint32 FirstInstance; // ID of the first instance to draw
};
-// Parameters of an INDEXED Indirect Dispatch Command
+ // Parameters of an INDEXED Indirect Dispatch Command
struct IndirectDispatchCommand
{
uint32 X_WorkGroupCount; // Number of Workgroup to dispatch on dimension X
@@ -36,6 +36,20 @@ namespace Juliet
uint32 Z_WorkGroupCount; // Number of Workgroup to dispatch on dimension Z
};
+ enum class QueueType : uint8
+ {
+ Graphics = 0,
+ Compute,
+ Copy,
+ Count
+ };
+
+ // Opaque types
+ struct CommandList {};
+
extern JULIET_API GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config);
- extern JULIET_API void DestroyGraphicsDevice(NonNullPtr device);
+ extern JULIET_API void DestroyGraphicsDevice(NonNullPtr device);
+
+ extern JULIET_API CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType = QueueType::Graphics);
+ extern JULIET_API void SubmitCommandLists(NonNullPtr device);
} // namespace Juliet
diff --git a/Juliet/include/Graphics/GraphicsConfig.h b/Juliet/include/Graphics/GraphicsConfig.h
index 4838eac..d3a2311 100644
--- a/Juliet/include/Graphics/GraphicsConfig.h
+++ b/Juliet/include/Graphics/GraphicsConfig.h
@@ -2,7 +2,7 @@
namespace Juliet
{
- enum class RendererType : uint8
+ enum class DriverType : uint8
{
Any = 0,
DX12 = 1,
@@ -10,6 +10,6 @@ namespace Juliet
struct GraphicsConfig
{
- RendererType PreferredRenderer = RendererType::DX12;
+ DriverType PreferredDriver = DriverType::DX12;
};
} // namespace Juliet
diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp
new file mode 100644
index 0000000..4653ccd
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp
@@ -0,0 +1,129 @@
+#include
+
+#include
+#include
+#include
+
+namespace Juliet::D3D12
+{
+ namespace
+ {
+ bool HasD3D12CommandList(NonNullPtr commandList, QueueType queueType)
+ {
+ return commandList->CommandLists[ToUnderlying(queueType)] != nullptr;
+ }
+
+ bool CreateD3D12CommandList(NonNullPtr driver, NonNullPtr commandList, QueueType queueType)
+ {
+ HRESULT res = 0;
+ auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)];
+ for (auto& buffer : commandList->CommandAllocator)
+ {
+ res = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
+ reinterpret_cast(&buffer[ToUnderlying(queueType)]));
+
+ if (FAILED(res))
+ {
+ Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator");
+ return false;
+ }
+ }
+
+ auto& commandListSlot = commandList->CommandLists[ToUnderlying(queueType)];
+ if (queueType == QueueType::Graphics || queueType == QueueType::Compute)
+ {
+ ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
+ res = ID3D12Device5_CreateCommandList1(driver->D3D12Device, queueDesc.NodeMask, queueDesc.Type,
+ D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
+ reinterpret_cast(&d3d12GraphicsCommandList));
+ if (FAILED(res))
+ {
+ Assert(false && "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or "
+ "compute command list");
+ return false;
+ }
+ commandListSlot = reinterpret_cast(d3d12GraphicsCommandList);
+ }
+ else if (queueType == QueueType::Copy)
+ {
+ ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr;
+ res = ID3D12Device5_CreateCommandList1(driver->D3D12Device, queueDesc.NodeMask, queueDesc.Type,
+ D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
+ reinterpret_cast(&d3d12CopyCommandList));
+ if (FAILED(res))
+ {
+ Assert(false &&
+ "Error not implemented: cannot create ID3D12GraphicsCommandList (copy command list)");
+ return false;
+ }
+ commandListSlot = reinterpret_cast(d3d12CopyCommandList);
+ }
+
+ // TODO: String library
+ std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID);
+ ID3D12GraphicsCommandList_SetName(commandListSlot, wide_str.c_str());
+
+ return true;
+ }
+
+ bool AllocateCommandList(NonNullPtr driver, QueueType queueType)
+ {
+ auto* commandList = static_cast(Calloc(1, sizeof(D3D12CommandList)));
+ if (!commandList)
+ {
+ Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory");
+ return false;
+ }
+
+ auto resizedArray = static_cast(
+ Realloc(driver->AvailableCommandLists, sizeof(D3D12CommandList*) * (driver->AvailableCommandListCapacity + 1)));
+
+ if (!resizedArray)
+ {
+ Assert(false &&
+ "Error not implemented, out of memory, handle that by deallocating stuff and returning false");
+ return false;
+ }
+
+ driver->AvailableCommandLists = resizedArray;
+ driver->AvailableCommandLists[driver->AvailableCommandListCapacity] = commandList;
+ commandList->ID = driver->AvailableCommandListCapacity;
+ driver->AvailableCommandListCapacity += 1;
+
+ return true;
+ }
+ } // namespace
+
+ CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType)
+ {
+ auto* d3d12Driver = static_cast(driver.Get());
+
+ uint8 currentCommandListIndex = d3d12Driver->CommandListCount;
+ if (currentCommandListIndex >= d3d12Driver->AvailableCommandListCapacity)
+ {
+ if (!AllocateCommandList(d3d12Driver, queueType))
+ {
+ return nullptr;
+ }
+ }
+
+ D3D12CommandList* commandList = d3d12Driver->AvailableCommandLists[currentCommandListIndex];
+ if (!HasD3D12CommandList(commandList, queueType))
+ {
+ if (!CreateD3D12CommandList(d3d12Driver, commandList, queueType))
+ {
+ // TODO Shoud destroy the command list here
+ return nullptr;
+ }
+ }
+
+ return reinterpret_cast(commandList);
+ }
+
+ void SubmitCommandLists(NonNullPtr driver)
+ {
+ auto* d3d12Driver = static_cast(driver.Get());
+ uint8 commandLastIndex = d3d12Driver->CommandListCount;
+ }
+
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.h b/Juliet/src/Graphics/D3D12/DX12CommandList.h
new file mode 100644
index 0000000..7d227c4
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/DX12CommandList.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace Juliet::D3D12
+{
+ struct D3D12Driver;
+
+ struct D3D12CommandList
+ {
+ D3D12Driver* Driver;
+
+ uint64 ID;
+
+ // We create kResourceBufferCount allocator per queue to allow reusing the command list every N frames
+ ID3D12CommandAllocator* CommandAllocator[GPUDriver::kResourceBufferCount][ToUnderlying(QueueType::Count)];
+ ID3D12CommandList* CommandLists[ToUnderlying(QueueType::Count)];
+ };
+
+ extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType);
+ extern void SubmitCommandLists(NonNullPtr driver);
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
index 0e17e5f..887e911 100644
--- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
@@ -3,55 +3,23 @@
#include
#include
#include
-#include
+#include
+#include
#include
#include
#include
-// TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason
-// + Will load the dll when needed
-// This will prevent us from using IID_ variables as they are defined in dxguid.lib
-namespace Juliet
-{
#define D3D12_DLL "d3d12.dll"
#define D3D12_CREATEDEVICE_FUNC "D3D12CreateDevice"
#define D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC "D3D12SerializeRootSignature"
#define DXGIDEBUG_DLL "dxgidebug.dll"
#define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface"
- struct D3D12Renderer : GPURenderer
- {
- GraphicsDevice* GraphicsDevice;
-
- // D3D12
- DynamicLibrary* D3D12DLL;
- ID3D12Device* D3D12Device;
- PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFct;
- ID3D12CommandQueue* CommandQueue;
-
- // Indirect commands signature
- ID3D12CommandSignature* IndirectDrawCommandSignature;
- ID3D12CommandSignature* IndirectIndexedDrawCommandSignature;
- ID3D12CommandSignature* IndirectDispatchCommandSignature;
-
- // DXGI
- IDXGIFactory4* DXGIFactory;
- IDXGIAdapter1* DXGIAdapter;
- DynamicLibrary* DXGIDebugDLL;
- IDXGIDebug* DXGIDebug;
-#ifdef IDXGIINFOQUEUE_SUPPORTED
- IDXGIInfoQueue* DXGIInfoQueue;
-#endif
-
- bool IsTearingSupported : 1;
-
- // UMA
- bool IsUMAAvailable : 1;
- bool IsUMACacheCoherent : 1;
-
- bool GPUUploadHeapSupported : 1;
- };
-
+// TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason
+// + Will load the dll when needed
+// This will prevent us from using IID_ variables as they are defined in dxguid.lib
+namespace Juliet::D3D12
+{
namespace
{
// Note: This is the highest my Gfx Card supports (5700XT)
@@ -128,7 +96,7 @@ namespace Juliet
if (SUCCEEDED(result))
{
- ID3D12Device_Release(device);
+ ID3D12Device5_Release(device);
}
IDXGIAdapter1_Release(adapter);
IDXGIFactory1_Release(factory1);
@@ -144,129 +112,130 @@ namespace Juliet
}
#ifdef IDXGIINFOQUEUE_SUPPORTED
- void InitializeDXGIDebug(NonNullPtr renderer)
+ void InitializeDXGIDebug(NonNullPtr driver)
{
// See https://github.com/microsoft/DirectX-Graphics-Samples/blob/7aa24663f26e547a5bc437db028dfcfdb4b3c8f3/TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp#L957
// For win10 only we can just use dxgiGetDebugInterface1
using LPDXGIGETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID, void**);
- renderer->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL);
- if (renderer->DXGIDebugDLL)
+ driver->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL);
+ if (driver->DXGIDebugDLL)
{
- auto dxgiGetDebugInterface = reinterpret_cast(
- LoadFunction(renderer->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC));
- HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&renderer->DXGIDebug);
+ auto dxgiGetDebugInterface =
+ reinterpret_cast(LoadFunction(driver->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC));
+ HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&driver->DXGIDebug);
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface");
}
- result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&renderer->DXGIInfoQueue);
+ result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&driver->DXGIInfoQueue);
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface");
}
else
{
- IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL,
+ IDXGIInfoQueue_SetBreakOnSeverity(driver->DXGIInfoQueue, DXGI_DEBUG_ALL,
DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
- IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL,
+ IDXGIInfoQueue_SetBreakOnSeverity(driver->DXGIInfoQueue, DXGI_DEBUG_ALL,
DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
- IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL,
+ IDXGIInfoQueue_SetBreakOnSeverity(driver->DXGIInfoQueue, DXGI_DEBUG_ALL,
DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE);
}
}
}
- void ShutdownDXGIDebug(NonNullPtr renderer)
+ void ShutdownDXGIDebug(NonNullPtr driver)
{
- if (renderer->DXGIDebug)
+ if (driver->DXGIDebug)
{
- IDXGIDebug_ReportLiveObjects(renderer->DXGIDebug, DXGI_DEBUG_ALL,
+ IDXGIDebug_ReportLiveObjects(driver->DXGIDebug, DXGI_DEBUG_ALL,
static_cast(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL));
- IDXGIDebug_Release(renderer->DXGIDebug);
- renderer->DXGIDebug = nullptr;
+ IDXGIDebug_Release(driver->DXGIDebug);
+ driver->DXGIDebug = nullptr;
}
- if (renderer->DXGIDebugDLL)
+ if (driver->DXGIDebugDLL)
{
- UnloadDynamicLibrary(renderer->DXGIDebugDLL);
- renderer->DXGIDebugDLL = nullptr;
+ UnloadDynamicLibrary(driver->DXGIDebugDLL);
+ driver->DXGIDebugDLL = nullptr;
}
}
#endif
- void DestroyRenderer_Internal(NonNullPtr renderer)
+ void DestroyDriver_Internal(NonNullPtr driver)
{
- if (renderer->IndirectDrawCommandSignature)
+ if (driver->IndirectDrawCommandSignature)
{
- ID3D12CommandSignature_Release(renderer->IndirectDrawCommandSignature);
- renderer->IndirectDrawCommandSignature = nullptr;
+ ID3D12CommandSignature_Release(driver->IndirectDrawCommandSignature);
+ driver->IndirectDrawCommandSignature = nullptr;
}
- if (renderer->IndirectIndexedDrawCommandSignature)
+ if (driver->IndirectIndexedDrawCommandSignature)
{
- ID3D12CommandSignature_Release(renderer->IndirectIndexedDrawCommandSignature);
- renderer->IndirectIndexedDrawCommandSignature = nullptr;
+ ID3D12CommandSignature_Release(driver->IndirectIndexedDrawCommandSignature);
+ driver->IndirectIndexedDrawCommandSignature = nullptr;
}
- if (renderer->IndirectDispatchCommandSignature)
+ if (driver->IndirectDispatchCommandSignature)
{
- ID3D12CommandSignature_Release(renderer->IndirectDispatchCommandSignature);
- renderer->IndirectDispatchCommandSignature = nullptr;
+ ID3D12CommandSignature_Release(driver->IndirectDispatchCommandSignature);
+ driver->IndirectDispatchCommandSignature = nullptr;
}
- if (renderer->CommandQueue)
+ if (driver->GraphicsQueue)
{
- ID3D12CommandQueue_Release(renderer->CommandQueue);
- renderer->CommandQueue = nullptr;
+ ID3D12CommandQueue_Release(driver->GraphicsQueue);
+ driver->GraphicsQueue = nullptr;
}
- if (renderer->D3D12Device)
+ if (driver->D3D12Device)
{
- ID3D12Device_Release(renderer->D3D12Device);
- renderer->D3D12Device = nullptr;
+ ID3D12Device5_Release(driver->D3D12Device);
+ driver->D3D12Device = nullptr;
}
- if (renderer->DXGIAdapter)
+ if (driver->DXGIAdapter)
{
- IDXGIAdapter1_Release(renderer->DXGIAdapter);
- renderer->DXGIAdapter = nullptr;
+ IDXGIAdapter1_Release(driver->DXGIAdapter);
+ driver->DXGIAdapter = nullptr;
}
- if (renderer->DXGIFactory)
+ if (driver->DXGIFactory)
{
- IDXGIFactory4_Release(renderer->DXGIFactory);
- renderer->DXGIFactory = nullptr;
+ IDXGIFactory4_Release(driver->DXGIFactory);
+ driver->DXGIFactory = nullptr;
}
- ShutdownDXGIDebug(renderer);
+ ShutdownDXGIDebug(driver);
- if (renderer->D3D12DLL)
+ if (driver->D3D12DLL)
{
- UnloadDynamicLibrary(renderer->D3D12DLL);
- renderer->D3D12DLL = nullptr;
+ UnloadDynamicLibrary(driver->D3D12DLL);
+ driver->D3D12DLL = nullptr;
}
- renderer->D3D12SerializeRootSignatureFct = nullptr;
+ driver->D3D12SerializeRootSignatureFct = nullptr;
- Free(renderer.Get());
+ Free(driver.Get());
}
void DestroyGraphicsDevice(NonNullPtr device)
{
- auto* renderer = static_cast(device->Renderer);
- DestroyRenderer_Internal(renderer);
+ // Note: Its a down cast so clang suggest not to do it but we are totally sure about it.
+ auto* driver = static_cast(device->Driver);
+ DestroyDriver_Internal(driver);
Free(device.Get());
}
GraphicsDevice* CreateGraphicsDevice()
{
- auto renderer = static_cast(Calloc(1, sizeof(D3D12Renderer)));
+ auto driver = static_cast(Calloc(1, sizeof(D3D12Driver)));
#ifdef IDXGIINFOQUEUE_SUPPORTED
static const bool kDebug = true;
if (kDebug)
{
- InitializeDXGIDebug(renderer);
+ InitializeDXGIDebug(driver);
}
#endif
@@ -274,15 +243,15 @@ namespace Juliet
HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Assert(false && "DX12: Cannot create DXGIFactory1");
return nullptr;
}
- result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory4, reinterpret_cast(&renderer->DXGIFactory));
+ result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory4, reinterpret_cast(&driver->DXGIFactory));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Assert(false && "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been "
"checked in CheckDriver");
return nullptr;
@@ -291,16 +260,16 @@ namespace Juliet
// Query DXGI1.5 and check for monitor Tearing support
IDXGIFactory5* factory5 = nullptr;
- result = IDXGIFactory4_QueryInterface(renderer->DXGIFactory, IID_IDXGIFactory5, reinterpret_cast(&factory5));
+ result = IDXGIFactory4_QueryInterface(driver->DXGIFactory, IID_IDXGIFactory5, reinterpret_cast(&factory5));
if (SUCCEEDED(result))
{
bool isTearingSupported = false;
result = IDXGIFactory5_CheckFeatureSupport(factory5, DXGI_FEATURE_PRESENT_ALLOW_TEARING,
&isTearingSupported, sizeof(isTearingSupported));
- renderer->IsTearingSupported = isTearingSupported;
+ driver->IsTearingSupported = isTearingSupported;
if (FAILED(result))
{
- renderer->IsTearingSupported = false;
+ driver->IsTearingSupported = false;
}
IDXGIFactory5_Release(factory5);
}
@@ -309,7 +278,7 @@ namespace Juliet
// 1.6 should be available on most Win10 PC if they didnt their windows update.
// Lets support not having it for now...
IDXGIFactory6* factory6 = nullptr;
- result = IDXGIFactory4_QueryInterface(renderer->DXGIFactory, IID_IDXGIFactory6, (void**)&factory6);
+ result = IDXGIFactory4_QueryInterface(driver->DXGIFactory, IID_IDXGIFactory6, (void**)&factory6);
if (SUCCEEDED(result))
{
// TODO: Put into the config
@@ -318,81 +287,81 @@ namespace Juliet
useLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER
: DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
IID_IDXGIAdapter1,
- reinterpret_cast(&renderer->DXGIAdapter));
+ reinterpret_cast(&driver->DXGIAdapter));
IDXGIFactory6_Release(factory6);
}
else
{
- result = IDXGIFactory4_EnumAdapters1(renderer->DXGIFactory, 0, &renderer->DXGIAdapter);
+ result = IDXGIFactory4_EnumAdapters1(driver->DXGIFactory, 0, &driver->DXGIAdapter);
}
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Assert(false && "Could not find adapter for D3D12Device");
return nullptr;
}
// Adapter is setup, get all the relevant info in the descriptor
DXGI_ADAPTER_DESC1 adapterDesc;
- result = IDXGIAdapter1_GetDesc1(renderer->DXGIAdapter, &adapterDesc);
+ result = IDXGIAdapter1_GetDesc1(driver->DXGIAdapter, &adapterDesc);
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Assert(false && "Could not get DXGIAdapter description");
return nullptr;
}
// Driver version
LARGE_INTEGER umdVersion;
- result = IDXGIAdapter1_CheckInterfaceSupport(renderer->DXGIAdapter, IID_IDXGIDevice, &umdVersion);
+ result = IDXGIAdapter1_CheckInterfaceSupport(driver->DXGIAdapter, IID_IDXGIDevice, &umdVersion);
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Assert(false && "Could not get DXGIAdapter driver version");
return nullptr;
}
- Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Renderer Infos:");
+ Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Infos:");
Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Adapter: %S", adapterDesc.Description);
Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Version: %d.%d.%d.%d", HIWORD(umdVersion.HighPart),
LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart));
- renderer->D3D12DLL = LoadDynamicLibrary(D3D12_DLL);
- if (renderer->D3D12DLL == nullptr)
+ driver->D3D12DLL = LoadDynamicLibrary(D3D12_DLL);
+ if (driver->D3D12DLL == nullptr)
{
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL);
return nullptr;
}
auto* D3D12CreateDeviceFuncPtr =
- reinterpret_cast(LoadFunction(renderer->D3D12DLL, D3D12_CREATEDEVICE_FUNC));
+ reinterpret_cast(LoadFunction(driver->D3D12DLL, D3D12_CREATEDEVICE_FUNC));
if (D3D12CreateDeviceFuncPtr == nullptr)
{
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't Load function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL);
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
return nullptr;
}
- renderer->D3D12SerializeRootSignatureFct = reinterpret_cast(
- LoadFunction(renderer->D3D12DLL, D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC));
- if (renderer->D3D12SerializeRootSignatureFct == nullptr)
+ driver->D3D12SerializeRootSignatureFct = reinterpret_cast(
+ LoadFunction(driver->D3D12DLL, D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC));
+ if (driver->D3D12SerializeRootSignatureFct == nullptr)
{
Log(LogLevel::Error, LogCategory::Graphics,
"DX12: Couldn't Load function " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC " in " D3D12_DLL);
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
return nullptr;
}
// TODO : D3D12 Debug Layer here
// InitializeD3D12DebugLayer()
- result = D3D12CreateDeviceFuncPtr(reinterpret_cast(renderer->DXGIAdapter), kD3DFeatureLevel,
- IID_ID3D12Device, reinterpret_cast(&renderer->D3D12Device));
+ result = D3D12CreateDeviceFuncPtr(reinterpret_cast(driver->DXGIAdapter), kD3DFeatureLevel,
+ IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
- Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device");
+ DestroyDriver_Internal(driver);
+ Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device5");
return nullptr;
}
@@ -402,16 +371,16 @@ namespace Juliet
// Check if UMA (unified memory architecture) is available. Used on APU i think ??
D3D12_FEATURE_DATA_ARCHITECTURE architecture;
architecture.NodeIndex = 0;
- result = ID3D12Device_CheckFeatureSupport(renderer->D3D12Device, D3D12_FEATURE_ARCHITECTURE, &architecture,
- sizeof(D3D12_FEATURE_DATA_ARCHITECTURE));
+ result = ID3D12Device5_CheckFeatureSupport(driver->D3D12Device, D3D12_FEATURE_ARCHITECTURE, &architecture,
+ sizeof(D3D12_FEATURE_DATA_ARCHITECTURE));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not get the device architecture");
return nullptr;
}
- renderer->IsUMAAvailable = architecture.UMA;
- renderer->IsUMACacheCoherent = architecture.CacheCoherentUMA;
+ driver->IsUMAAvailable = architecture.UMA;
+ driver->IsUMACacheCoherent = architecture.CacheCoherentUMA;
#ifndef E_INVALIDARG
#define E_INVALIDARG (HRESULT)0x80070057L
@@ -419,28 +388,31 @@ namespace Juliet
// Check "GPU Upload Heap" support (for fast uniform buffers. Not supported on my 5700xt
D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16;
- renderer->GPUUploadHeapSupported = false;
- result = ID3D12Device_CheckFeatureSupport(renderer->D3D12Device, D3D12_FEATURE_D3D12_OPTIONS16, &options16,
- sizeof(options16));
+ driver->GPUUploadHeapSupported = false;
+ result = ID3D12Device5_CheckFeatureSupport(driver->D3D12Device, D3D12_FEATURE_D3D12_OPTIONS16, &options16,
+ sizeof(options16));
if (SUCCEEDED(result))
{
- renderer->GPUUploadHeapSupported = options16.GPUUploadHeapSupported;
+ driver->GPUUploadHeapSupported = options16.GPUUploadHeapSupported;
}
- // Command Queue
+ // Command Queues
+ // Graphics Queue only for now
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.NodeMask = 0;
- queueDesc.Priority = 0;
- result = ID3D12Device_CreateCommandQueue(renderer->D3D12Device, &queueDesc, IID_ID3D12CommandQueue,
- reinterpret_cast(&renderer->CommandQueue));
+ queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
+ result = ID3D12Device5_CreateCommandQueue(driver->D3D12Device, &queueDesc, IID_ID3D12CommandQueue,
+ reinterpret_cast(&driver->GraphicsQueue));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
- Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue");
+ DestroyDriver_Internal(driver);
+ Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue: Graphics");
return nullptr;
}
+ ID3D12CommandQueue_SetName(driver->GraphicsQueue, L"GRAPHICS_QUEUE");
+ driver->QueueDesc[ToUnderlying(QueueType::Graphics)] = queueDesc;
// Indirect Commands
D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc;
@@ -452,11 +424,11 @@ namespace Juliet
commandSignatureDesc.ByteStride = sizeof(IndirectDrawCommand);
commandSignatureDesc.NumArgumentDescs = 1;
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
- result = ID3D12Device_CreateCommandSignature(renderer->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
- reinterpret_cast(&renderer->IndirectDrawCommandSignature));
+ result = ID3D12Device5_CreateCommandSignature(driver->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
+ reinterpret_cast(&driver->IndirectDrawCommandSignature));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create indirect draw command signature");
return nullptr;
}
@@ -465,12 +437,12 @@ namespace Juliet
commandSignatureDesc.ByteStride = sizeof(IndexedIndirectDrawCommand);
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
- result = ID3D12Device_CreateCommandSignature(renderer->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
- reinterpret_cast(&renderer->IndirectIndexedDrawCommandSignature));
+ result = ID3D12Device5_CreateCommandSignature(driver->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
+ reinterpret_cast(&driver->IndirectIndexedDrawCommandSignature));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create INDEXED Indirect draw command signature");
return nullptr;
}
@@ -479,11 +451,11 @@ namespace Juliet
commandSignatureDesc.ByteStride = sizeof(IndirectDispatchCommand);
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
- result = ID3D12Device_CreateCommandSignature(renderer->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
- reinterpret_cast(&renderer->IndirectDispatchCommandSignature));
+ result = ID3D12Device5_CreateCommandSignature(driver->D3D12Device, &commandSignatureDesc, NULL, IID_ID3D12CommandSignature,
+ reinterpret_cast(&driver->IndirectDispatchCommandSignature));
if (FAILED(result))
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create Indirect dispatch command signature");
return nullptr;
}
@@ -491,22 +463,30 @@ namespace Juliet
auto device = static_cast(Calloc(1, sizeof(GraphicsDevice)));
if (!device)
{
- DestroyRenderer_Internal(renderer);
+ DestroyDriver_Internal(driver);
return nullptr;
}
- device->DestroyDevice = DestroyGraphicsDevice;
- device->Renderer = renderer;
- renderer->GraphicsDevice = device;
+
+ // Assign Functions to the device
+ device->DestroyDevice = DestroyGraphicsDevice;
+ device->AcquireCommandList = AcquireCommandList;
+ device->SubmitCommandLists = SubmitCommandLists;
+
+ device->Driver = driver;
+ driver->GraphicsDevice = device;
return device;
}
} // namespace
+} // namespace Juliet::D3D12
+namespace Juliet
+{
// clang-format off
GraphicsDeviceFactory DX12DeviceFactory = {
.Name="DirectX12",
- .Type=RendererType::DX12,
- .CheckDriver = CheckDriver,
- .CreateGraphicsDevice = CreateGraphicsDevice };
+ .Type=DriverType::DX12,
+ .CheckDriver = D3D12::CheckDriver,
+ .CreateGraphicsDevice = D3D12::CreateGraphicsDevice };
// clang-format on
} // namespace Juliet
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h
new file mode 100644
index 0000000..3644c65
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include
+#include
+
+namespace Juliet
+{
+ struct DynamicLibrary;
+}
+
+namespace Juliet::D3D12
+{
+ struct D3D12Driver : GPUDriver
+ {
+ GraphicsDevice* GraphicsDevice;
+
+ // D3D12
+ DynamicLibrary* D3D12DLL;
+ ID3D12Device5* D3D12Device;
+ PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFct;
+ ID3D12CommandQueue* GraphicsQueue;
+ D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Copy)];
+
+ // Indirect commands signature
+ ID3D12CommandSignature* IndirectDrawCommandSignature;
+ ID3D12CommandSignature* IndirectIndexedDrawCommandSignature;
+ ID3D12CommandSignature* IndirectDispatchCommandSignature;
+
+ // DXGI
+ IDXGIFactory4* DXGIFactory;
+ IDXGIAdapter1* DXGIAdapter;
+ DynamicLibrary* DXGIDebugDLL;
+ IDXGIDebug* DXGIDebug;
+#ifdef IDXGIINFOQUEUE_SUPPORTED
+ IDXGIInfoQueue* DXGIInfoQueue;
+#endif
+
+ // Resources
+ D3D12CommandList** AvailableCommandLists;
+ uint8 AvailableCommandListCapacity;
+
+ bool IsTearingSupported : 1;
+
+ // UMA
+ bool IsUMAAvailable : 1;
+ bool IsUMACacheCoherent : 1;
+
+ bool GPUUploadHeapSupported : 1;
+ };
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp
index 3b53913..c02df20 100644
--- a/Juliet/src/Graphics/Graphics.cpp
+++ b/Juliet/src/Graphics/Graphics.cpp
@@ -16,12 +16,12 @@ namespace Juliet
GraphicsDeviceFactory* ChooseFactory(GraphicsConfig config)
{
// First try to check the preferred renderer from the config if any.
- if (config.PreferredRenderer != RendererType::Any)
+ if (config.PreferredDriver != DriverType::Any)
{
for (GraphicsDeviceFactory* factory : Factories)
{
// If the config has a preferred renderer, immediately pick it up.
- if (factory->Type == config.PreferredRenderer)
+ if (factory->Type == config.PreferredDriver)
{
if (factory->CheckDriver())
{
@@ -63,4 +63,22 @@ namespace Juliet
device->DestroyDevice(device);
}
+ CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType /* = QueueType::Graphics */)
+ {
+ GPUDriver* driver = device->Driver;
+ CommandList* cmdList = device->AcquireCommandList(driver, queueType);
+
+ driver->CommandListCount += 1;
+
+ return cmdList;
+ }
+
+ void SubmitCommandLists(NonNullPtr device)
+ {
+ GPUDriver* driver = device->Driver;
+ device->SubmitCommandLists(driver);
+
+ driver->CommandListCount = 0;
+ }
+
} // namespace Juliet
diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h
index 5b1c276..5d55146 100644
--- a/Juliet/src/Graphics/GraphicsDevice.h
+++ b/Juliet/src/Graphics/GraphicsDevice.h
@@ -1,26 +1,32 @@
#pragma once
-#include
#include
+#include
+#include
namespace Juliet
{
- struct GPURenderer
+ struct GPUDriver
{
+ uint8 CommandListCount;
+
+ static constexpr uint8 kResourceBufferCount = 2;
};
struct GraphicsDevice
{
void (*DestroyDevice)(NonNullPtr self);
+ CommandList* (*AcquireCommandList)(NonNullPtr driver, QueueType queueType);
+ void (*SubmitCommandLists)(NonNullPtr driver);
- const char* Name = "Unknown";
- GPURenderer* Renderer = nullptr;
+ const char* Name = "Unknown";
+ GPUDriver* Driver = nullptr;
};
struct GraphicsDeviceFactory
{
- const char* Name = "Unknown";
- RendererType Type = RendererType::Any;
+ const char* Name = "Unknown";
+ DriverType Type = DriverType::Any;
bool (*CheckDriver)(void);
GraphicsDevice* (*CreateGraphicsDevice)(void);
};
diff --git a/JulietApp/Editor/EditorMain_win32.cpp b/JulietApp/Editor/EditorMain_win32.cpp
index 98558a0..5181b25 100644
--- a/JulietApp/Editor/EditorMain_win32.cpp
+++ b/JulietApp/Editor/EditorMain_win32.cpp
@@ -71,6 +71,10 @@ void Win32EditorApplication::Update()
// Draw here for now
// 1) Acquire a Command Buffer
+ CommandList* cmdList = AcquireCommandList(GraphicsDevice, QueueType::Graphics);
+
+ // Submit Commands
+ SubmitCommandLists(GraphicsDevice);
}
bool Win32EditorApplication::IsRunning()