diff --git a/include/fast/backends/gfx_dxgi.h b/include/fast/backends/gfx_dxgi.h index fb720c0ca..2d959f2f8 100644 --- a/include/fast/backends/gfx_dxgi.h +++ b/include/fast/backends/gfx_dxgi.h @@ -51,8 +51,7 @@ class GfxWindowBackendDXGI final : public GfxWindowBackend { // These need to be public to be accessible in the window callback void CreateSwapChain(IUnknown* mDevice, std::function&& before_destroy_fn); void CreateFactoryAndDevice(bool debug, int d3d_version, class GfxRenderingAPIDX11* self, - bool (*createFunc)(class GfxRenderingAPIDX11* self, IDXGIAdapter1* adapter, - bool test_only)); + bool (*createFunc)(class GfxRenderingAPIDX11* self, bool SoftwareRenderer)); void OnKeydown(WPARAM wParam, LPARAM lParam); void OnKeyup(WPARAM wParam, LPARAM lParam); void OnMouseButtonDown(int btn); diff --git a/src/fast/backends/gfx_direct3d11.cpp b/src/fast/backends/gfx_direct3d11.cpp index 1077d2a42..a84c949fb 100644 --- a/src/fast/backends/gfx_direct3d11.cpp +++ b/src/fast/backends/gfx_direct3d11.cpp @@ -97,26 +97,96 @@ void GfxRenderingAPIDX11::CreateDepthStencilObjects(uint32_t width, uint32_t hei ThrowIfFailed(mDevice->CreateShaderResourceView(texture.Get(), &srv_desc, srv)); } } -static bool CreateDeviceFunc(class GfxRenderingAPIDX11* self, IDXGIAdapter1* adapter, bool test_only) { +static bool CreateDeviceFunc(class GfxRenderingAPIDX11* self, bool SoftwareRenderer) { #if DEBUG_D3D UINT device_creation_flags = D3D11_CREATE_DEVICE_DEBUG; #else UINT device_creation_flags = 0; #endif - D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 }; + bool CreationFailed = false; + const char HardwareText[320] = "\nUsing software renderer. Performance issues are to be expected.\n\n" + "Please check your preferred GPU in Windows graphics or GPU driver settings and " + "make sure you have the correct GPU drivers installed.\n\n" + "You can also try to change the graphic backend of the port in its config file.\n" + "Window->Backend->Id\n" + "0 = DX11, 1 = OpenGL"; + const char SoftwareText[33] = "\nUsing software renderer failed."; + + if (SoftwareRenderer) { + SPDLOG_INFO("Using software renderer."); + } + + HRESULT res = self->mDX11CreateDevice( + NULL, SoftwareRenderer ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_HARDWARE, nullptr, device_creation_flags, NULL, + NULL, D3D11_SDK_VERSION, self->mDevice.GetAddressOf(), &self->mFeatureLevel, self->mContext.GetAddressOf()); + + // Get and log name of adapter + IDXGIDevice* DXGIDevice = nullptr; + IDXGIAdapter* Adapter = nullptr; + DXGI_ADAPTER_DESC adapterDesc; + std::wstring adapterName; + char adapterNameCStr[128] = ""; + char error_message[512]; + HRESULT res2; + + res2 = self->mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&DXGIDevice); + if (SUCCEEDED(res2)) { + res2 = DXGIDevice->GetAdapter(&Adapter); + if (SUCCEEDED(res2)) { + res2 = Adapter->GetDesc(&adapterDesc); + if (SUCCEEDED(res2)) { + adapterName = adapterDesc.Description; + wcstombs(adapterNameCStr, adapterName.c_str(), 128); + } + Adapter->Release(); + } + DXGIDevice->Release(); + } + SPDLOG_INFO("Using D3D adapter: {0}", adapterNameCStr); + + if (FAILED(res)) { + CreationFailed = true; + SPDLOG_WARN("Failed to create a D3D device. HRESULT: 0x{0:08x}", res); + sprintf(error_message, "Failed to create a D3D device on %s\nHRESULT: 0x%08X%s", adapterNameCStr, res, + SoftwareRenderer ? SoftwareText : HardwareText); + } - HRESULT res = self->mDX11CreateDevice(adapter, - D3D_DRIVER_TYPE_UNKNOWN, // since we use a specific adapter - nullptr, device_creation_flags, FeatureLevels, ARRAYSIZE(FeatureLevels), - D3D11_SDK_VERSION, test_only ? nullptr : self->mDevice.GetAddressOf(), - &self->mFeatureLevel, test_only ? nullptr : self->mContext.GetAddressOf()); + else if (self->mFeatureLevel < D3D_FEATURE_LEVEL_10_0) { + CreationFailed = true; + SPDLOG_WARN("D3D adapter doesn't support D3D feature level 10_0 or greater."); + sprintf(error_message, "%s doesn't support D3D feature level 10_0 or greater.%s", adapterNameCStr, + SoftwareRenderer ? SoftwareText : HardwareText); + } + + else if (self->mFeatureLevel < D3D_FEATURE_LEVEL_10_1) { + SPDLOG_WARN("D3D adapter doesn't support D3D feature level 10_1 or greater. MSAA setting will be ignored."); - if (test_only) { - return SUCCEEDED(res); } else { - ThrowIfFailed(res, self->mWindowBackend->GetWindowHandle(), "Failed to create D3D11 device."); - return true; + // Check for Compute Shader support + if (self->mDevice != NULL) { + D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS features; + self->mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &features, + sizeof(D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS)); + if (features.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x == false) { + CreationFailed = true; + SPDLOG_WARN("D3D adapter doesn't support compute shaders."); + sprintf(error_message, "%s doesn't support compute shaders.%s", adapterNameCStr, + SoftwareRenderer ? SoftwareText : HardwareText); + } + } + } + + if (CreationFailed) { + if (self->mContext) { + self->mContext->Release(); + } + if (self->mDevice) { + self->mDevice->Release(); + } + MessageBoxA(self->mWindowBackend->GetWindowHandle(), error_message, "Warning", MB_OK | MB_ICONWARNING); + return false; } + return true; }; void GfxRenderingAPIDX11::Init() { @@ -752,7 +822,7 @@ void GfxRenderingAPIDX11::UpdateFramebufferParameters(int fb_id, uint32_t width, width = ((width) > (1U) ? (width) : (1U)); height = ((height) > (1U) ? (height) : (1U)); - // We can't use MSAA the way we are using it on Feature Level 10.0 Hardware, so disable it altogether. + // We can't use MSAA the way we are using it on feature level 10_0 hardware, so disable it altogether. msaa_level = mFeatureLevel < D3D_FEATURE_LEVEL_10_1 ? 1 : msaa_level; while (msaa_level > 1 && mMsaaNumQualityLevels[msaa_level - 1] == 0) { --msaa_level; diff --git a/src/fast/backends/gfx_dxgi.cpp b/src/fast/backends/gfx_dxgi.cpp index ac45102ba..7faaf1881 100644 --- a/src/fast/backends/gfx_dxgi.cpp +++ b/src/fast/backends/gfx_dxgi.cpp @@ -976,7 +976,7 @@ void GfxWindowBackendDXGI::SetMaxFrameLatency(int latency) { void GfxWindowBackendDXGI::CreateFactoryAndDevice(bool debug, int d3d_version, class GfxRenderingAPIDX11* self, bool (*createFunc)(class GfxRenderingAPIDX11* self, - IDXGIAdapter1* adapter, bool test_only)) { + bool SoftwareRenderer)) { if (CreateDXGIFactory2 != nullptr) { ThrowIfFailed(CreateDXGIFactory2(debug ? DXGI_CREATE_FACTORY_DEBUG : 0, __uuidof(IDXGIFactory2), &mFactory)); } else { @@ -996,19 +996,14 @@ void GfxWindowBackendDXGI::CreateFactoryAndDevice(bool debug, int d3d_version, c mTearingSupport = SUCCEEDED(hr) && allowTearing; } - - ComPtr adapter; - for (UINT i = 0; mFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) { - DXGI_ADAPTER_DESC1 desc; - adapter->GetDesc1(&desc); - if (desc.Flags & 2 /*DXGI_ADAPTER_FLAG_SOFTWARE*/) { // declaration missing in mingw headers - continue; - } - if (createFunc(self, adapter.Get(), true)) { - break; - } + // Try preferred hardware adapter and then try software adapter (WARP), if that fails. + // Maybe we can try a different renderer (like OpenGL) here first before software? + if (!createFunc(self, false) && !createFunc(self, true)) { + SPDLOG_CRITICAL("Creating D3D renderer failed. Exiting"); + MessageBoxA(self->mWindowBackend->GetWindowHandle(), "Creating D3D renderer failed. Exiting", "Error", + MB_OK | MB_ICONERROR); + throw; } - createFunc(self, adapter.Get(), false); } void GfxWindowBackendDXGI::CreateSwapChain(IUnknown* mDevice, std::function&& before_destroy_fn) {