283 lines
10 KiB
C++
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};
|
|
}
|
|
} |