#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 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 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 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 device; ComPtr 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; }