rtengine/src/renderer/dx11/init.cpp
Kevin Trogant 4d575dc229 pipelines
2024-04-04 20:01:37 +02:00

283 lines
10 KiB
C++

#ifndef _WIN32
#pragma warning Building DX11 on non - windows is probably a mistake
#endif
#include <d3d11.h>
#include <dxgi1_3.h>
#include <wrl.h>
#include "gfx/renderer_api.h"
#include "runtime/config.h"
#define DONT_DEFINE_RENDERER_GLOBAL
#include "gpu.hpp"
RT_CVAR_S(
rt_Dx11AdapterName,
"Name of the adapter that should be used for device creation. Default: \"\" (Use default)",
"");
RT_CVAR_I(rt_Dx11VSync, "Enable vsync. Default: 1", 1);
RT_CVAR_I(rt_Dx11MaxSubmittedCommandBuffers,
"Maximum number of submitted command buffers per frame. Default: 1024",
1024);
extern rt_cvar rt_Dx11MaxCommandBuffers;
rt_gpu g_gpu;
extern "C" void RT_RENDERER_API_FN(RegisterCVars)(void) {
rtRegisterCVAR(&rt_Dx11AdapterName);
rtRegisterCVAR(&rt_Dx11VSync);
rtRegisterCVAR(&rt_Dx11MaxCommandBuffers);
}
static rt_swap_chain CreateSwapChain(HWND hwnd) {
rt_swap_chain swc;
DXGI_SWAP_CHAIN_DESC1 desc;
desc.Width = 0; // use window width
desc.Height = 0; // use window height
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // can't specify _SRGB here when using
// DXGI_SWAP_EFFECT_FLIP_* ...;
desc.Stereo = FALSE;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
desc.Flags = 0;
if (FAILED(g_gpu.dxgi_factory->CreateSwapChainForHwnd(g_gpu.device.Get(),
hwnd,
&desc,
nullptr,
nullptr,
&swc.swap_chain))) {
rtReportError("dx11", "Failed to create the swap chain.");
return swc;
}
ID3D11Texture2D *frame_buffer;
if (FAILED(swc.swap_chain->GetBuffer(0, IID_PPV_ARGS(&frame_buffer)))) {
rtReportError("dx11", "Failed to retrieve the backbuffer.");
swc.swap_chain.Reset();
return swc;
}
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
rtv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
if (FAILED(g_gpu.device->CreateRenderTargetView(frame_buffer, &rtv_desc, &swc.rtv))) {
rtReportError("dx11", "Failed to create the render target view for the backbuffer.");
swc.swap_chain.Reset();
return swc;
}
return swc;
}
static IDXGIAdapter *RetrieveSelectedAdapter(void) {
ComPtr<IDXGIFactory2> factory;
if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)))) {
return NULL;
}
UINT i = 0;
IDXGIAdapter *adapter;
while (factory->EnumAdapters(i, &adapter) == S_OK) {
++i;
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
char utf8_desc[256];
rtWStrToUTF8(desc.Description, utf8_desc, 256);
if (strncmp(utf8_desc, rt_Dx11AdapterName.s, 256) == 0)
return adapter;
}
return NULL;
}
extern rt_result InitCommandBufferManagement();
extern void ShutdownCommandBufferManagement();
extern rt_result InitRenderTargetManagement();
extern void ShutdownRenderTargetManagement();
extern rt_result InitBufferManagement();
extern void ShutdownBufferManagement();
extern "C" rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
constexpr D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0};
UINT device_flags = 0;
#ifdef RT_DEBUG
device_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
IDXGIAdapter *selected_adapter = RetrieveSelectedAdapter();
ID3D11Device *base_device;
ID3D11DeviceContext *base_context;
if (FAILED(D3D11CreateDevice(selected_adapter,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
device_flags,
feature_levels,
RT_ARRAY_COUNT(feature_levels),
D3D11_SDK_VERSION,
&base_device,
&g_gpu.feature_level,
&base_context))) {
rtLog("dx11", "Feature level 11.1 creation failed, retrying with feature level 11.0");
if (FAILED(D3D11CreateDevice(selected_adapter,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
device_flags,
&feature_levels[1],
RT_ARRAY_COUNT(feature_levels) - 1,
D3D11_SDK_VERSION,
&base_device,
&g_gpu.feature_level,
&base_context))) {
rtReportError("dx11", "Failed to create the d3d11 device.");
return RT_UNKNOWN_ERROR;
}
}
if (FAILED(base_device->QueryInterface(IID_PPV_ARGS(&g_gpu.device)))) {
rtReportError("dx11", "Failed to query the D3D11Device1 interface.");
return RT_UNKNOWN_ERROR;
}
if (FAILED(base_context->QueryInterface(IID_PPV_ARGS(&g_gpu.device_context)))) {
rtReportError("dx11", "Failed to query the D3D11DeviceContext1 interface.");
return RT_UNKNOWN_ERROR;
}
IDXGIDevice1 *dxgi_device;
if (FAILED(g_gpu.device->QueryInterface(&dxgi_device))) {
rtReportError("dx11", "Failed to query the DXGIDevice1 interface.");
return RT_UNKNOWN_ERROR;
}
IDXGIAdapter *adapter;
if (FAILED(dxgi_device->GetAdapter(&adapter))) {
rtReportError("dx11", "Failed to retrieve the dxgi adapter.");
return RT_UNKNOWN_ERROR;
}
if (FAILED(adapter->GetParent(IID_PPV_ARGS(&g_gpu.dxgi_factory)))) {
rtReportError("dx11", "Failed to retrieve the dxgi factory.");
return RT_UNKNOWN_ERROR;
}
g_gpu.device->CheckFeatureSupport(D3D11_FEATURE_THREADING,
&g_gpu.threading_support,
sizeof(g_gpu.threading_support));
g_gpu.swap_chain = CreateSwapChain(info->hWnd);
g_gpu.context_lock = rtCreateMutex();
rt_result res = InitCommandBufferManagement();
if (res != RT_SUCCESS)
return res;
res = InitRenderTargetManagement();
if (res != RT_SUCCESS)
return res;
res = InitBufferManagement();
if (res != RT_SUCCESS)
return res;
return RT_SUCCESS;
}
extern "C" void RT_RENDERER_API_FN(Shutdown)(void) {
ShutdownBufferManagement();
ShutdownRenderTargetManagement();
ShutdownCommandBufferManagement();
rtDestroyMutex(g_gpu.context_lock);
g_gpu.swap_chain.rtv.Reset();
g_gpu.swap_chain.swap_chain.Reset();
g_gpu.dxgi_factory.Reset();
g_gpu.device.Reset();
}
extern "C" unsigned int RT_RENDERER_API_FN(GetMaxFramesInFlight)(void) {
// TODO: Verify this.
return 1;
}
extern "C" void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) {
RT_UNUSED(frame_id);
FLOAT clear_color[4] = {
0,
0,
0,
0,
};
rtLockMutex(g_gpu.context_lock);
g_gpu.device_context->ClearRenderTargetView(g_gpu.swap_chain.rtv.Get(), clear_color);
rtUnlockMutex(g_gpu.context_lock);
}
extern "C" void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
RT_UNUSED(frame_id);
rtLockMutex(g_gpu.context_lock);
UINT sync_interval = rt_Dx11VSync.i ? 1 : 0;
g_gpu.swap_chain.swap_chain->Present(sync_interval, 0);
rtUnlockMutex(g_gpu.context_lock);
}
// Copied from null. Delete once no longer needed
extern "C" {
#define RETURN_HANDLE_STUB2(type, initial) \
static unsigned int s_next = (initial); \
s_next = (s_next + 1) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \
type h = { \
1, \
s_next, \
}; \
return h;
#define RETURN_HANDLE_STUB(type) RETURN_HANDLE_STUB2(type, 1)
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
static unsigned int s_next = (initial); \
for (uint32_t i = 0; i < (count); ++i) { \
(out)[i].index = (s_next++) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \
(out)[i].version = 1; \
}
#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1)
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
const rt_gpu_semaphore_info *info,
rt_gpu_semaphore_handle *p_semaphores) {
RT_UNUSED(info);
RETURN_HANDLE_ARRAY_STUB2(p_semaphores, count, 3)
return RT_SUCCESS;
}
void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_handle *semaphores) {
RT_UNUSED(count);
RT_UNUSED(semaphores);
}
/* NOTE(Kevin): It might become necessary to actually track the value, to correctly simulate gpu
* behaviour */
uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle sem) {
RT_UNUSED(sem);
return 0;
}
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void) {
return {1, 1};
}
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) {
return {1, 2};
}
}