Progress on creating the d3d12 renderer

This commit is contained in:
2025-01-11 23:33:09 -05:00
parent 836d0fa185
commit 434f15a9d4
6 changed files with 241 additions and 18 deletions

View File

@@ -70,7 +70,7 @@
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;dxguid.lib;d3d12.lib;dxgi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;d3d12.lib;dxgi.lib;dxguid.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>
@@ -98,7 +98,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;dxguid.lib;d3d12.lib;dxgi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;d3d12.lib;dxgi.lib;dxguid.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>

View File

@@ -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

View File

@@ -1,27 +1,43 @@
#include <pch.h>
#include <core/Common/NonNullPtr.h>
#include <Core/Memory/Allocator.h>
#include <DX12Utils.h>
#include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/GraphicsDevice.h>
// 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<void**>(&factory1));
HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast<void**>(&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<void**>(&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<void**>(&factory6));
if (SUCCEEDED(result))
{
result = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
IID_IDXGIAdapter1, reinterpret_cast<void**>(&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<IUnknown*>(adapter), kD3DFeatureLevel, IID_ID3D12Device,
reinterpret_cast<void**>(&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<D3D12Renderer> 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<LPDXGIGETDEBUGINTERFACE>(
reinterpret_cast<void*>(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<D3D12Renderer> renderer)
{
if (renderer->DXGIDebug)
{
IDXGIDebug_ReportLiveObjects(renderer->DXGIDebug, DXGI_DEBUG_ALL,
static_cast<DXGI_DEBUG_RLO_FLAGS>(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<D3D12Renderer> renderer)
{
ShutdownDebugLayer(renderer);
Free(renderer.Get());
}
void DestroyGraphicsDevice(NonNullPtr<GraphicsDevice> device)
{
auto* renderer = reinterpret_cast<D3D12Renderer*>(device.Get());
DestroyRenderer_Internal(renderer);
Free(device.Get());
}
GraphicsDevice* CreateGraphicsDevice()
{
return nullptr;
auto renderer = static_cast<D3D12Renderer*>(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<void**>(&factory1));
if (FAILED(result))
{
DestroyRenderer_Internal(renderer);
Assert(false && "DX12: Cannot create DXGIFactory1");
return nullptr;
}
result = IDXGIFactory1_QueryInterface(factory1, IID_IDXGIFactory4, reinterpret_cast<void**>(&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<void**>(&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<GraphicsDevice*>(Calloc(1, sizeof(GraphicsDevice)));
device->DestroyDevice = DestroyGraphicsDevice;
device->Renderer = renderer;
return device;
}
} // namespace

View File

@@ -14,6 +14,7 @@
#include <d3dcompiler.h>
#include "d3d12.h"
#include <DirectXMath.h>
#include <dxgi1_5.h>
#include <dxgi1_6.h>
#ifdef _DEBUG
@@ -21,3 +22,7 @@
#endif
#include <dxgi.h>
#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
#define IDXGIINFOQUEUE_SUPPORTED
#endif

View File

@@ -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

View File

@@ -1,20 +1,29 @@
#pragma once
#include <Graphics/GraphicsConfig.h>
#include <Core/Common/NonNullPtr.h>
namespace Juliet
{
struct GPURenderer
{
};
struct GraphicsDevice
{
const char* Name = "Unknown";
void (*DestroyDevice)(NonNullPtr<GraphicsDevice> 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;
}
} // namespace Juliet