Progress on creating the d3d12 renderer
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user