diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj
index b977a4e..2cc8c2e 100644
--- a/Juliet/Juliet.vcxproj
+++ b/Juliet/Juliet.vcxproj
@@ -70,7 +70,7 @@
true
- ws2_32.lib;dxguid.lib;d3d12.lib;dxgi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+ ws2_32.lib;d3d12.lib;dxgi.lib;dxguid.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
@@ -98,7 +98,7 @@
true
true
true
- ws2_32.lib;dxguid.lib;d3d12.lib;dxgi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+ ws2_32.lib;d3d12.lib;dxgi.lib;dxguid.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
diff --git a/Juliet/src/Core/HAL/Win32.h b/Juliet/src/Core/HAL/Win32.h
index 6b417cc..28b3cc4 100644
--- a/Juliet/src/Core/HAL/Win32.h
+++ b/Juliet/src/Core/HAL/Win32.h
@@ -14,6 +14,12 @@
#define UNICODE
#endif
+// Only Supports Win10 and greater
+#undef WINVER
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0A00
+#define WINVER _WIN32_WINNT
+
#define NOIME
#define NOWINRES
#define NOGDICAPMASKS
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
index 6acaa04..b46048a 100644
--- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
@@ -1,27 +1,43 @@
#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
{
- // 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
+ struct D3D12Renderer : GPURenderer
+ {
+ IDXGIFactory4* DXGIFactory;
+ IDXGIAdapter1* DXGIAdapter;
+
+ HMODULE DXGIDebug_DLL;
+ IDXGIDebug* DXGIDebug;
+#ifdef IDXGIINFOQUEUE_SUPPORTED
+ IDXGIInfoQueue* DXGIInfoQueue;
+#endif
+
+ bool IsTearingSupported : 1;
+ };
+
namespace
{
+ // Note: This is the highest my Gfx Card supports (5700XT)
+ // https://en.wikipedia.org/wiki/Feature_levels_in_Direct3D#Direct3D_12
+ // 12_2 Adds RayTracing and others feature supported by RDNA2 and greater and Gefore 20xx and greater
+ constexpr D3D_FEATURE_LEVEL kD3DFeatureLevel = D3D_FEATURE_LEVEL_12_1;
+ constexpr auto kD3DFeatureLevelStr = "12_1";
+
bool CheckDriver()
{
- HRESULT result;
- // ID3D12Device *device;
- IDXGIFactory4* factory4;
- IDXGIFactory6* factory6;
- IDXGIAdapter1* adapter;
-
- ID3D12Object* test;
// Can create DXGI factory ?
IDXGIFactory1* factory1 = nullptr;
- result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1));
+ HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1));
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Cannot create DXGIFactory1");
@@ -29,6 +45,7 @@ namespace Juliet
}
// Can query the 1.4 factory ?
+ IDXGIFactory4* factory4 = nullptr;
result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory4, reinterpret_cast(&factory4));
if (FAILED(result))
{
@@ -37,14 +54,192 @@ namespace Juliet
return false;
}
IDXGIFactory4_Release(factory4);
+
+ // Check for 1.6. (It's not mandatory).
+ IDXGIAdapter1* adapter = nullptr;
+ IDXGIFactory6* factory6 = nullptr;
+ result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory6, reinterpret_cast(&factory6));
+ if (SUCCEEDED(result))
+ {
+ result = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
+ IID_IDXGIAdapter1, reinterpret_cast(&adapter));
+ IDXGIFactory6_Release(factory6);
+ }
+ else
+ {
+ result = IDXGIFactory1_EnumAdapters1(factory1, 0, &adapter);
+ }
+
+ if (FAILED(result))
+ {
+ Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to find an adapter for D3D12.");
+
+ IDXGIFactory1_Release(factory1);
+ return false;
+ }
+
+ ID3D12Device* device = nullptr;
+ result = D3D12CreateDevice(reinterpret_cast(adapter), kD3DFeatureLevel, IID_ID3D12Device,
+ reinterpret_cast(&device));
+
+ if (SUCCEEDED(result))
+ {
+ ID3D12Device_Release(device);
+ }
+ IDXGIAdapter1_Release(adapter);
IDXGIFactory1_Release(factory1);
- return false;
+ if (FAILED(result))
+ {
+ Log(LogLevel::Warning, LogCategory::Graphics,
+ "DX12: Failed to create a D3D12Device with feature level %s.", kD3DFeatureLevelStr);
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+#ifdef IDXGIINFOQUEUE_SUPPORTED
+ void InitializeDebugLayer(NonNullPtr renderer)
+ {
+ // 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->DXGIDebug_DLL = LoadLibraryEx(L"dxgidebug.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (renderer->DXGIDebug_DLL)
+ {
+ auto dxgiGetDebugInterface = reinterpret_cast(
+ reinterpret_cast(GetProcAddress(renderer->DXGIDebug_DLL, "DXGIGetDebugInterface")));
+
+ HRESULT result = DXGIGetDebugInterface1(0, IID_IDXGIDebug, (void**)&renderer->DXGIDebug);
+ if (FAILED(result))
+ {
+ Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface");
+ }
+
+ result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&renderer->DXGIInfoQueue);
+ if (FAILED(result))
+ {
+ Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface");
+ }
+ else
+ {
+ IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
+ IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
+ IDXGIInfoQueue_SetBreakOnSeverity(renderer->DXGIInfoQueue, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE);
+ }
+ }
+ }
+
+ void ShutdownDebugLayer(NonNullPtr renderer)
+ {
+ if (renderer->DXGIDebug)
+ {
+ IDXGIDebug_ReportLiveObjects(renderer->DXGIDebug, DXGI_DEBUG_ALL,
+ static_cast(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL));
+ IDXGIDebug_Release(renderer->DXGIDebug);
+ renderer->DXGIDebug = nullptr;
+ }
+
+ if (renderer->DXGIDebug_DLL) {
+ FreeLibrary(renderer->DXGIDebug_DLL);
+ renderer->DXGIDebug_DLL = nullptr;
+ }
+ }
+#endif
+
+ void DestroyRenderer_Internal(NonNullPtr renderer)
+ {
+ ShutdownDebugLayer(renderer);
+ Free(renderer.Get());
+ }
+
+ void DestroyGraphicsDevice(NonNullPtr device)
+ {
+ auto* renderer = reinterpret_cast(device.Get());
+ DestroyRenderer_Internal(renderer);
+ Free(device.Get());
}
GraphicsDevice* CreateGraphicsDevice()
{
- return nullptr;
+ auto renderer = static_cast(Calloc(1, sizeof(D3D12Renderer)));
+
+#ifdef IDXGIINFOQUEUE_SUPPORTED
+ static const bool kDebug = true;
+ if (kDebug)
+ {
+ InitializeDebugLayer(renderer);
+ }
+#endif
+
+ IDXGIFactory1* factory1 = nullptr;
+ HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1));
+ if (FAILED(result))
+ {
+ DestroyRenderer_Internal(renderer);
+ Assert(false && "DX12: Cannot create DXGIFactory1");
+ return nullptr;
+ }
+
+ result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory4, reinterpret_cast(&renderer->DXGIFactory));
+ if (FAILED(result))
+ {
+ DestroyRenderer_Internal(renderer);
+ Assert(false && "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been "
+ "checked in CheckDriver");
+ return nullptr;
+ }
+ IDXGIFactory1_Release(factory1);
+
+ // Query DXGI1.5 and check for monitor Tearing support
+ IDXGIFactory5* factory5 = nullptr;
+ result = IDXGIFactory4_QueryInterface(renderer->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;
+ if (FAILED(result))
+ {
+ renderer->IsTearingSupported = false;
+ }
+ IDXGIFactory1_Release(factory5);
+ }
+
+ IDXGIFactory6* factory6 = nullptr;
+ result = IDXGIFactory4_QueryInterface(renderer->DXGIFactory, IID_IDXGIFactory6, (void**)&factory6);
+ if (SUCCEEDED(result))
+ {
+ // TODO: Put into the config
+ const static bool useHighPerfFirst = true;
+ result = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0,
+ useHighPerfFirst ? DXGI_GPU_PREFERENCE_MINIMUM_POWER
+ : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
+ IID_IDXGIAdapter1, (void**)&renderer->DXGIAdapter);
+ IDXGIFactory6_Release(factory6);
+ }
+ else
+ {
+ result = IDXGIFactory4_EnumAdapters1(renderer->DXGIFactory, 0, &renderer->DXGIAdapter);
+ }
+
+ if (FAILED(result))
+ {
+ DestroyRenderer_Internal(renderer);
+ Assert(false && "Could not find adapter for D3D12Device");
+ return nullptr;
+ }
+
+ auto device = static_cast(Calloc(1, sizeof(GraphicsDevice)));
+ device->DestroyDevice = DestroyGraphicsDevice;
+ device->Renderer = renderer;
+
+ return device;
}
} // namespace
diff --git a/Juliet/src/Graphics/D3D12/DX12Includes.h b/Juliet/src/Graphics/D3D12/DX12Includes.h
index f9292ef..99d2398 100644
--- a/Juliet/src/Graphics/D3D12/DX12Includes.h
+++ b/Juliet/src/Graphics/D3D12/DX12Includes.h
@@ -14,6 +14,7 @@
#include
#include "d3d12.h"
#include
+#include
#include
#ifdef _DEBUG
@@ -21,3 +22,7 @@
#endif
#include
+
+#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
+#define IDXGIINFOQUEUE_SUPPORTED
+#endif
diff --git a/Juliet/src/Graphics/D3D12/DX12Utils.h b/Juliet/src/Graphics/D3D12/DX12Utils.h
index b1decea..493f748 100644
--- a/Juliet/src/Graphics/D3D12/DX12Utils.h
+++ b/Juliet/src/Graphics/D3D12/DX12Utils.h
@@ -8,4 +8,12 @@ namespace Juliet
{
Assert(!!FAILED(hr));
}
+
+ inline void CheckFailure(HRESULT hr)
+ {
+ switch (hr)
+ {
+ case E_POINTER: Assert(false && "Invalid Pointer");
+ }
+ }
} // namespace Juliet::RHI::DX12
diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h
index 0302b4b..5b1c276 100644
--- a/Juliet/src/Graphics/GraphicsDevice.h
+++ b/Juliet/src/Graphics/GraphicsDevice.h
@@ -1,20 +1,29 @@
#pragma once
+
#include
+#include
namespace Juliet
{
+ struct GPURenderer
+ {
+ };
+
struct GraphicsDevice
{
- const char* Name = "Unknown";
+ void (*DestroyDevice)(NonNullPtr self);
+
+ const char* Name = "Unknown";
+ GPURenderer* Renderer = nullptr;
};
struct GraphicsDeviceFactory
{
- const char* Name = "Unknown";
+ const char* Name = "Unknown";
RendererType Type = RendererType::Any;
bool (*CheckDriver)(void);
GraphicsDevice* (*CreateGraphicsDevice)(void);
};
extern GraphicsDeviceFactory DX12DeviceFactory;
-}
\ No newline at end of file
+} // namespace Juliet