196 lines
7.6 KiB
C++
196 lines
7.6 KiB
C++
#include "device.hpp"
|
|
|
|
#include "runtime/config.h"
|
|
|
|
static RT_CVAR_S(rt_Dx11AdapterName, "Name of the desired adapter (GPU). Default: Empty.", "");
|
|
|
|
rt_dx11_device::rt_dx11_device() : m_is_initialized(false) {
|
|
}
|
|
|
|
rt_dx11_device::~rt_dx11_device() {
|
|
}
|
|
|
|
rt_result rt_dx11_device::Initialize(const rt_renderer_window_info *info *info) {
|
|
// Create the necessary objects (Device, SwapChain, Immediate Context)
|
|
HRESULT hr = S_OK;
|
|
ComPtr<IDXGIFactory1> factory;
|
|
if (FAILED(hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) {
|
|
rtReportError("DX11", "CreateDXGIFactory1 failed with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
if (FAILED(hr = factory.As(&m_dxgi_factory))) {
|
|
rtReportError("DX11", "Failed to retrieve IDXGIFactory4 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
// Retrieve the selected adapter
|
|
{
|
|
ComPtr<IDXGIAdapter1> adapter = nullptr;
|
|
WCHAR w_name[128];
|
|
memset(w_name, 0, sizeof(w_name));
|
|
if (rtUTF8ToWStr(rt_Dx11AdapterName.s, w_name, RT_ARRAY_COUNT(w_name)) != RT_SUCCESS) {
|
|
rtLog("DX11",
|
|
"The provided adapter name does not fit into the statically sized array.");
|
|
|
|
if (FAILED(m_dxgi_factory->EnumAdapters1(0, &adapter))) {
|
|
rtReportError("DX11", "Failed to retrieve the default adapter.");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
if (FAILED(hr = adapter.As(&m_adapter))) {
|
|
rtReportError("DX11", "Failed to retrieve IDXGIAdapter3 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
|
|
UINT i = 0;
|
|
|
|
while (m_dxgi_factory->EnumAdapters1(i, &adapter) == S_OK) {
|
|
DXGI_ADAPTER_DESC1 desc;
|
|
if (FAILED(adapter->GetDesc1(&desc))) {
|
|
++i;
|
|
adapter->Release();
|
|
continue;
|
|
}
|
|
|
|
if (memcmp(desc.Description, w_name, sizeof(w_name)) == 0) {
|
|
if (FAILED(hr = adapter.As(&m_adapter))) {
|
|
rtReportError("DX11", "Failed to retrieve IDXGIAdapter3 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
if (!m_adapter.Get()) {
|
|
if (FAILED(m_dxgi_factory->EnumAdapters1(0, &adapter))) {
|
|
rtReportError("DX11", "Failed to retrieve the default adapter.");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
if (FAILED(hr = adapter.As(&m_adapter))) {
|
|
rtReportError("DX11", "Failed to retrieve IDXGIAdapter3 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// Get monitor properties
|
|
ComPtr<IDXGIOutput> output;
|
|
|
|
HMONITOR wnd_mon = MonitorFromWindow(info->hWnd, MONITOR_DEFAULTTOPRIMARY);
|
|
if (wnd_mon) {
|
|
UINT i = 0;
|
|
while (m_adapter->EnumOutputs(i, &output) == S_OK) {
|
|
DXGI_OUTPUT_DESC desc = {};
|
|
output->GetDesc(&desc);
|
|
if (desc.Monitor == wnd_mon) {
|
|
GetDisplayInfo(output.Get());
|
|
break;
|
|
}
|
|
++i;
|
|
}
|
|
} else {
|
|
rtLog("DX11", "MonitorFromWindow returned a non-valid monitor.");
|
|
if (!FAILED(m_adapter->EnumOutputs(0, &output))) {
|
|
GetDisplayInfo(output.Get());
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
|
#ifdef RT_DEBUG
|
|
device_flags |= D3D11_CREATE_DEVICE_DEBUGGABLE | D3D11_CREATE_DEVICE_DEBUG;
|
|
#endif
|
|
|
|
// Check for tearing support, which is a requirement for variable refresh displays
|
|
if (FAILED(m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
|
&m_tearing_supported,
|
|
sizeof(m_tearing_supported))))
|
|
m_tearing_supported = false;
|
|
|
|
D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1};
|
|
|
|
ComPtr<ID3D11Device> device;
|
|
ComPtr<ID3D11DeviceContext> context;
|
|
if (FAILED(hr = D3D11CreateDevice(m_adapter.Get(),
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
NULL,
|
|
device_flags,
|
|
feature_levels,
|
|
RT_ARRAY_COUNT(feature_levels),
|
|
D3D11_SDK_VERSION,
|
|
&device,
|
|
nullptr,
|
|
&context))) {
|
|
rtLog("DX11", "D3D11CreateDevice failed with %d. Retrying without DEBUGGABLE flag...");
|
|
device_flags &= ~D3D11_CREATE_DEVICE_DEBUGGABLE;
|
|
if (FAILED(hr = D3D11CreateDevice(nullptr, // Use the default adapter TODO: Select
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
NULL,
|
|
device_flags,
|
|
feature_levels,
|
|
RT_ARRAY_COUNT(feature_levels),
|
|
D3D11_SDK_VERSION,
|
|
&device,
|
|
nullptr,
|
|
&context))) {
|
|
rtReportError("DX11", "D3D11CreateDevice failed with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
if (FAILED(hr = device.As(&m_device))) {
|
|
rtReportError("DX11", "Failed to retrieve ID3D11Device5 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
if (FAILED(hr = context.As(&m_context))) {
|
|
rtReportError("DX11", "Failed to retrieve ID3D11DeviceContext3 with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (info->is_fullscreen) {
|
|
// Don't allow Alt+Enter to switch the window to fullscreen exclusive
|
|
m_dxgi_factory->MakeWindowAssociation(info->hWnd, DXGI_MWA_NO_ALT_ENTER);
|
|
}
|
|
|
|
UINT swap_chain_flags = 0;
|
|
if (m_tearing_supported)
|
|
swap_chain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
|
|
|
// TODO(Kevin): HDR Support
|
|
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
|
|
swap_chain_desc.Width = info->width;
|
|
swap_chain_desc.Height = info->height;
|
|
swap_chain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
swap_chain_desc.Stereo = FALSE;
|
|
swap_chain_desc.SampleDesc.Count = 1;
|
|
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
swap_chain_desc.BufferCount = 2;
|
|
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
|
|
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
|
swap_chain_desc.Flags = swap_chain_flags;
|
|
|
|
if (FAILED(hr = m_dxgi_factory->CreateSwapChainForHwnd(m_device.Get(),
|
|
info->hWnd,
|
|
&swap_chain_desc,
|
|
nullptr,
|
|
nullptr,
|
|
&m_swap_chain))) {
|
|
rtReportError("DX11", "CreateSwapChainForHwnd failed with %d", hr);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
m_is_initialized = true;
|
|
return RT_SUCCESS;
|
|
}
|
|
|
|
void rt_dx11_device::Shutdown(void) {
|
|
m_device.Reset();
|
|
m_is_initialized = false;
|
|
}
|
|
|
|
void rt_dx11_device::GetDisplayInfo(IDXGIOutput *output) {
|
|
// TODO Not implemented yet
|
|
m_monitor_refresh_rate = 1.f / 60.f;
|
|
} |