From fcbc027abccf7496052d9d96e053a5f0d4bf2783 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 1 Apr 2023 15:47:02 +1000 Subject: [PATCH] GS: Unify D3D device creation paths Also makes Vulkan the device for Intel Arc GPUs. --- common/D3D12/Context.cpp | 42 +-- common/D3D12/Context.h | 5 +- pcsx2/Frontend/D3D11HostDisplay.cpp | 252 ++++++----------- pcsx2/Frontend/D3D11HostDisplay.h | 8 +- pcsx2/Frontend/D3D12HostDisplay.cpp | 179 ++++-------- pcsx2/Frontend/D3D12HostDisplay.h | 8 +- pcsx2/GS/GS.cpp | 20 +- pcsx2/GS/GSUtil.cpp | 17 +- pcsx2/GS/Renderers/DX11/D3D.cpp | 364 +++++++++++++++---------- pcsx2/GS/Renderers/DX11/D3D.h | 44 +-- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 8 +- 11 files changed, 408 insertions(+), 539 deletions(-) diff --git a/common/D3D12/Context.cpp b/common/D3D12/Context.cpp index a34a63e9c4..c3c174aa74 100644 --- a/common/D3D12/Context.cpp +++ b/common/D3D12/Context.cpp @@ -125,7 +125,7 @@ bool Context::SupportsTextureFormat(DXGI_FORMAT format) (support.Support1 & required) == required; } -bool Context::Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer) +bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) { pxAssertRel(!g_d3d12_context, "No context exists"); @@ -133,7 +133,7 @@ bool Context::Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_ return false; g_d3d12_context.reset(new Context()); - if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter_index, enable_debug_layer) || + if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) || !g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() || !g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() || !g_d3d12_context->CreateCommandLists() || !g_d3d12_context->CreateTimestampQuery() || @@ -166,31 +166,9 @@ u32 Context::GetAdapterVendorID() const return desc.VendorId; } -bool Context::CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer) +bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) { - ComPtr adapter; - HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter); - if (FAILED(hr)) - { - Console.Error("Adapter %u not found, using default", adapter_index); - adapter = nullptr; - } - else - { - DXGI_ADAPTER_DESC adapter_desc; - if (SUCCEEDED(adapter->GetDesc(&adapter_desc))) - { - char adapter_name_buffer[128]; - const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, - static_cast(std::wcslen(adapter_desc.Description)), - adapter_name_buffer, std::size(adapter_name_buffer), 0, nullptr); - if (name_length >= 0) - { - adapter_name_buffer[name_length] = 0; - Console.WriteLn("D3D Adapter: %s", adapter_name_buffer); - } - } - } + HRESULT hr; // Enabling the debug layer will fail if the Graphics Tools feature is not installed. if (enable_debug_layer) @@ -208,18 +186,14 @@ bool Context::CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool e } // Create the actual device. - hr = s_d3d12_create_device(adapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); + hr = s_d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); if (FAILED(hr)) return false; // get adapter - ComPtr dxgi_factory4; - if (SUCCEEDED(dxgi_factory->QueryInterface(dxgi_factory4.put()))) - { - const LUID luid(m_device->GetAdapterLuid()); - if (FAILED(dxgi_factory4->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put())))) - Console.Error("Failed to get lookup adapter by device LUID"); - } + const LUID luid(m_device->GetAdapterLuid()); + if (FAILED(dxgi_factory->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put())))) + Console.Error("Failed to get lookup adapter by device LUID"); if (enable_debug_layer) { diff --git a/common/D3D12/Context.h b/common/D3D12/Context.h index 1654840798..869ae0605b 100644 --- a/common/D3D12/Context.h +++ b/common/D3D12/Context.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -60,7 +61,7 @@ namespace D3D12 ~Context(); /// Creates new device and context. - static bool Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer); + static bool Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); /// Destroys active context. static void Destroy(); @@ -167,7 +168,7 @@ namespace D3D12 Context(); - bool CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer); + bool CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); bool CreateCommandQueue(); bool CreateAllocator(); bool CreateFence(); diff --git a/pcsx2/Frontend/D3D11HostDisplay.cpp b/pcsx2/Frontend/D3D11HostDisplay.cpp index 767cdd7bf9..06b8e219fa 100644 --- a/pcsx2/Frontend/D3D11HostDisplay.cpp +++ b/pcsx2/Frontend/D3D11HostDisplay.cpp @@ -36,8 +36,8 @@ class D3D11HostDisplayTexture : public HostDisplayTexture { public: - D3D11HostDisplayTexture(wil::com_ptr_nothrow texture, - wil::com_ptr_nothrow srv, u32 width, u32 height, bool dynamic) + D3D11HostDisplayTexture(wil::com_ptr_nothrow texture, wil::com_ptr_nothrow srv, u32 width, + u32 height, bool dynamic) : m_texture(std::move(texture)) , m_srv(std::move(srv)) , m_width(width) @@ -103,19 +103,18 @@ bool D3D11HostDisplay::HasSurface() const return static_cast(m_swap_chain); } -std::unique_ptr D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */) +std::unique_ptr D3D11HostDisplay::CreateTexture( + u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */) { - const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1u, 1u, - D3D11_BIND_SHADER_RESOURCE, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, - dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0); + const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1u, 1u, D3D11_BIND_SHADER_RESOURCE, + dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0); const D3D11_SUBRESOURCE_DATA srd{data, data_stride, data_stride * height}; ComPtr texture; HRESULT hr = m_device->CreateTexture2D(&desc, data ? &srd : nullptr, texture.addressof()); if (FAILED(hr)) return {}; - const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0, - 1); + const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0, 1); ComPtr srv; hr = m_device->CreateShaderResourceView(texture.get(), &srv_desc, srv.addressof()); if (FAILED(hr)) @@ -124,14 +123,15 @@ std::unique_ptr D3D11HostDisplay::CreateTexture(u32 width, u return std::make_unique(std::move(texture), std::move(srv), width, height, dynamic); } -void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride) +void D3D11HostDisplay::UpdateTexture( + HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride) { D3D11HostDisplayTexture* d3d11_texture = static_cast(texture); if (!d3d11_texture->IsDynamic()) { const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1); - m_context->UpdateSubresource(d3d11_texture->GetD3DTexture(), 0, &dst_box, texture_data, texture_data_stride, - texture_data_stride * height); + m_context->UpdateSubresource( + d3d11_texture->GetD3DTexture(), 0, &dst_box, texture_data, texture_data_stride, texture_data_stride * height); } else { @@ -167,10 +167,9 @@ bool D3D11HostDisplay::GetHostRefreshRate(float* refresh_rate) if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 && desc.BufferDesc.RefreshRate.Denominator > 0) { - DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, - desc.BufferDesc.RefreshRate.Denominator); - *refresh_rate = static_cast(desc.BufferDesc.RefreshRate.Numerator) / - static_cast(desc.BufferDesc.RefreshRate.Denominator); + DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, desc.BufferDesc.RefreshRate.Denominator); + *refresh_rate = + static_cast(desc.BufferDesc.RefreshRate.Numerator) / static_cast(desc.BufferDesc.RefreshRate.Denominator); return true; } } @@ -189,52 +188,21 @@ bool D3D11HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync) if (EmuConfig.GS.UseDebugDevice) create_flags |= D3D11_CREATE_DEVICE_DEBUG; - ComPtr temp_dxgi_factory; - HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.put())); - if (FAILED(hr)) - { - Console.Error("Failed to create DXGI factory: 0x%08X", hr); + m_dxgi_factory = D3D::CreateFactory(EmuConfig.GS.UseDebugDevice); + if (!m_dxgi_factory) return false; - } - u32 adapter_index; - if (!EmuConfig.GS.Adapter.empty()) - { - AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get())); - for (adapter_index = 0; adapter_index < static_cast(adapter_info.adapter_names.size()); adapter_index++) - { - if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index]) - break; - } - if (adapter_index == static_cast(adapter_info.adapter_names.size())) - { - Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(), - adapter_info.adapter_names[0].c_str()); - adapter_index = 0; - } - } - else - { - Console.WriteLn("No adapter selected, using first."); - adapter_index = 0; - } - - ComPtr dxgi_adapter; - hr = temp_dxgi_factory->EnumAdapters(adapter_index, dxgi_adapter.put()); - if (FAILED(hr)) - Console.Warning("Failed to enumerate adapter %u, using default", adapter_index); + ComPtr dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), EmuConfig.GS.Adapter); static constexpr std::array requested_feature_levels = { {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}}; - hr = - D3D11CreateDevice(dxgi_adapter.get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, - create_flags, requested_feature_levels.data(), static_cast(requested_feature_levels.size()), - D3D11_SDK_VERSION, m_device.put(), nullptr, m_context.put()); + HRESULT hr = D3D11CreateDevice(dxgi_adapter.get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, + create_flags, requested_feature_levels.data(), static_cast(requested_feature_levels.size()), D3D11_SDK_VERSION, + m_device.put(), nullptr, m_context.put()); // we re-grab these later, see below dxgi_adapter.reset(); - temp_dxgi_factory.reset(); if (FAILED(hr)) { @@ -252,39 +220,15 @@ bool D3D11HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync) } } - // we need the specific factory for the device, otherwise MakeWindowAssociation() is flaky. ComPtr dxgi_device; - if (!m_device.try_query_to(&dxgi_device) || FAILED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put()))) || - FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(m_dxgi_factory.put())))) - { - Console.Warning("Failed to get parent adapter/device/factory"); - return false; - } + if (m_device.try_query_to(&dxgi_device) && SUCCEEDED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put())))) + Console.WriteLn(fmt::format("D3D Adapter: {}", D3D::GetAdapterName(dxgi_adapter.get()))); + else + Console.Error("Failed to obtain D3D adapter name."); - DXGI_ADAPTER_DESC adapter_desc; - if (SUCCEEDED(dxgi_adapter->GetDesc(&adapter_desc))) - { - char adapter_name_buffer[128]; - const int name_length = - WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, static_cast(std::wcslen(adapter_desc.Description)), - adapter_name_buffer, sizeof(adapter_name_buffer), 0, nullptr); - if (name_length >= 0) - { - adapter_name_buffer[name_length] = 0; - Console.WriteLn("D3D Adapter: %s", adapter_name_buffer); - } - } - - m_allow_tearing_supported = false; - ComPtr dxgi_factory5; - if (m_dxgi_factory.try_query_to(&dxgi_factory5)) - { - BOOL allow_tearing_supported = false; - hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, - sizeof(allow_tearing_supported)); - if (SUCCEEDED(hr)) - m_allow_tearing_supported = (allow_tearing_supported == TRUE); - } + BOOL allow_tearing_supported = false; + hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported)); + m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE); m_window_info = wi; m_vsync_mode = vsync; @@ -323,33 +267,36 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode) const u32 width = static_cast(client_rc.right - client_rc.left); const u32 height = static_cast(client_rc.bottom - client_rc.top); - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferDesc.Width = width; - swap_chain_desc.BufferDesc.Height = height; - swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.Width = width; + swap_chain_desc.Height = height; + swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.BufferCount = 3; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = window_hwnd; - swap_chain_desc.Windowed = TRUE; swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD; m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain && !fullscreen_mode); if (m_using_allow_tearing) swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fs_desc = {}; if (fullscreen_mode) { swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - swap_chain_desc.Windowed = FALSE; - swap_chain_desc.BufferDesc = *fullscreen_mode; + swap_chain_desc.Width = fullscreen_mode->Width; + swap_chain_desc.Height = fullscreen_mode->Height; + fs_desc.RefreshRate = fullscreen_mode->RefreshRate; + fs_desc.ScanlineOrdering = fullscreen_mode->ScanlineOrdering; + fs_desc.Scaling = fullscreen_mode->Scaling; + fs_desc.Windowed = FALSE; } - Console.WriteLn("Creating a %dx%d %s %s swap chain", swap_chain_desc.BufferDesc.Width, - swap_chain_desc.BufferDesc.Height, m_using_flip_model_swap_chain ? "flip-discard" : "discard", - swap_chain_desc.Windowed ? "windowed" : "full-screen"); + Console.WriteLn("Creating a %dx%d %s %s swap chain", swap_chain_desc.Width, swap_chain_desc.Height, + m_using_flip_model_swap_chain ? "flip-discard" : "discard", fullscreen_mode ? "full-screen" : "windowed"); - HRESULT hr = m_dxgi_factory->CreateSwapChain(m_device.get(), &swap_chain_desc, m_swap_chain.put()); + HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd( + m_device.get(), window_hwnd, &swap_chain_desc, fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put()); if (FAILED(hr) && m_using_flip_model_swap_chain) { Console.Warning("Failed to create a flip-discard swap chain, trying discard."); @@ -358,22 +305,18 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode) m_using_flip_model_swap_chain = false; m_using_allow_tearing = false; - hr = m_dxgi_factory->CreateSwapChain(m_device.get(), &swap_chain_desc, m_swap_chain.put()); + hr = m_dxgi_factory->CreateSwapChainForHwnd( + m_device.get(), window_hwnd, &swap_chain_desc, fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put()); if (FAILED(hr)) { - Console.Error("CreateSwapChain failed: 0x%08X", hr); + Console.Error("CreateSwapChainForHwnd failed: 0x%08X", hr); return false; } } - ComPtr dxgi_factory; - hr = m_swap_chain->GetParent(IID_PPV_ARGS(dxgi_factory.put())); - if (SUCCEEDED(hr)) - { - hr = dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) - Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed"); - } + hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(hr)) + Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed"); return CreateSwapChainRTV(); } @@ -391,8 +334,7 @@ bool D3D11HostDisplay::CreateSwapChainRTV() D3D11_TEXTURE2D_DESC backbuffer_desc; backbuffer->GetDesc(&backbuffer_desc); - CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0, - backbuffer_desc.ArraySize); + CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0, backbuffer_desc.ArraySize); hr = m_device->CreateRenderTargetView(backbuffer.get(), &rtv_desc, m_swap_chain_rtv.put()); if (FAILED(hr)) { @@ -408,11 +350,10 @@ bool D3D11HostDisplay::CreateSwapChainRTV() { BOOL fullscreen = FALSE; DXGI_SWAP_CHAIN_DESC desc; - if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && - SUCCEEDED(m_swap_chain->GetDesc(&desc))) + if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && SUCCEEDED(m_swap_chain->GetDesc(&desc))) { - m_window_info.surface_refresh_rate = static_cast(desc.BufferDesc.RefreshRate.Numerator) / - static_cast(desc.BufferDesc.RefreshRate.Denominator); + m_window_info.surface_refresh_rate = + static_cast(desc.BufferDesc.RefreshRate.Numerator) / static_cast(desc.BufferDesc.RefreshRate.Denominator); } else { @@ -501,8 +442,7 @@ void D3D11HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, m_swap_chain_rtv.reset(); - HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, - m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); + HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); if (FAILED(hr)) Console.Error("ResizeBuffers() failed: 0x%08X", hr); @@ -681,7 +621,8 @@ void D3D11HostDisplay::PopTimestampQuery() while (m_waiting_timestamp_queries > 0) { D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint; - const HRESULT disjoint_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][0].get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH); + const HRESULT disjoint_hr = m_context->GetData( + m_timestamp_queries[m_read_timestamp_query][0].get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH); if (disjoint_hr != S_OK) break; @@ -696,11 +637,14 @@ void D3D11HostDisplay::PopTimestampQuery() else { u64 start = 0, end = 0; - const HRESULT start_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][1].get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH); - const HRESULT end_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH); + const HRESULT start_hr = m_context->GetData( + m_timestamp_queries[m_read_timestamp_query][1].get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH); + const HRESULT end_hr = + m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH); if (start_hr == S_OK && end_hr == S_OK) { - m_accumulated_gpu_time += static_cast(static_cast(end - start) / (static_cast(disjoint.Frequency) / 1000.0)); + m_accumulated_gpu_time += + static_cast(static_cast(end - start) / (static_cast(disjoint.Frequency) / 1000.0)); m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES; m_waiting_timestamp_queries--; } @@ -753,77 +697,38 @@ float D3D11HostDisplay::GetAndResetAccumulatedGPUTime() HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList() { - ComPtr dxgi_factory; - const HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.put())); - if (FAILED(hr)) + auto factory = D3D::CreateFactory(false); + if (!factory) return {}; - return GetAdapterAndModeList(dxgi_factory.get()); + return GetAdapterAndModeList(factory.get()); } -HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList(IDXGIFactory* dxgi_factory) +HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList(IDXGIFactory5* dxgi_factory) { AdapterAndModeList adapter_info; - ComPtr current_adapter; - while (SUCCEEDED(dxgi_factory->EnumAdapters(static_cast(adapter_info.adapter_names.size()), - current_adapter.put()))) - { - DXGI_ADAPTER_DESC adapter_desc; - std::string adapter_name; - if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc))) - { - char adapter_name_buffer[128]; - const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, - static_cast(std::wcslen(adapter_desc.Description)), - adapter_name_buffer, sizeof(adapter_name_buffer), 0, nullptr); - if (name_length >= 0) - adapter_name.assign(adapter_name_buffer, static_cast(name_length)); - else - adapter_name.assign("(Unknown)"); - } - else - { - adapter_name.assign("(Unknown)"); - } + adapter_info.adapter_names = D3D::GetAdapterNames(dxgi_factory); - if (adapter_info.fullscreen_modes.empty()) + auto adapter = D3D::GetChosenOrFirstAdapter(dxgi_factory, EmuConfig.GS.Adapter); + if (adapter) + { + ComPtr output; + if (SUCCEEDED(adapter->EnumOutputs(0, &output))) { - ComPtr output; - if (SUCCEEDED(current_adapter->EnumOutputs(0, &output))) + UINT num_modes = 0; + if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) { - UINT num_modes = 0; - if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) + std::vector modes(num_modes); + if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data()))) { - std::vector modes(num_modes); - if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data()))) + for (const DXGI_MODE_DESC& mode : modes) { - for (const DXGI_MODE_DESC& mode : modes) - { - adapter_info.fullscreen_modes.push_back(GetFullscreenModeString( - mode.Width, mode.Height, - static_cast(mode.RefreshRate.Numerator) / static_cast(mode.RefreshRate.Denominator))); - } + adapter_info.fullscreen_modes.push_back(GetFullscreenModeString(mode.Width, mode.Height, + static_cast(mode.RefreshRate.Numerator) / static_cast(mode.RefreshRate.Denominator))); } } } } - - // handle duplicate adapter names - if (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })) - { - std::string original_adapter_name = std::move(adapter_name); - - u32 current_extra = 2; - do - { - adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); - current_extra++; - } while (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })); - } - - adapter_info.adapter_names.push_back(std::move(adapter_name)); } return adapter_info; @@ -833,4 +738,3 @@ HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList() { return GetAdapterAndModeList(m_dxgi_factory.get()); } - diff --git a/pcsx2/Frontend/D3D11HostDisplay.h b/pcsx2/Frontend/D3D11HostDisplay.h index 4bfe1d2240..b66112f658 100644 --- a/pcsx2/Frontend/D3D11HostDisplay.h +++ b/pcsx2/Frontend/D3D11HostDisplay.h @@ -20,7 +20,7 @@ #include "common/WindowInfo.h" #include #include -#include +#include #include #include #include @@ -77,7 +77,7 @@ protected: static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16; static constexpr u8 NUM_TIMESTAMP_QUERIES = 5; - static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); + static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory5* dxgi_factory); bool CreateImGuiContext() override; void DestroyImGuiContext() override; @@ -94,8 +94,8 @@ protected: ComPtr m_device; ComPtr m_context; - ComPtr m_dxgi_factory; - ComPtr m_swap_chain; + ComPtr m_dxgi_factory; + ComPtr m_swap_chain; ComPtr m_swap_chain_rtv; bool m_allow_tearing_supported = false; diff --git a/pcsx2/Frontend/D3D12HostDisplay.cpp b/pcsx2/Frontend/D3D12HostDisplay.cpp index fccf538c81..70c4bd9299 100644 --- a/pcsx2/Frontend/D3D12HostDisplay.cpp +++ b/pcsx2/Frontend/D3D12HostDisplay.cpp @@ -122,10 +122,9 @@ bool D3D12HostDisplay::GetHostRefreshRate(float* refresh_rate) if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 && desc.BufferDesc.RefreshRate.Denominator > 0) { - DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, - desc.BufferDesc.RefreshRate.Denominator); - *refresh_rate = static_cast(desc.BufferDesc.RefreshRate.Numerator) / - static_cast(desc.BufferDesc.RefreshRate.Denominator); + DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, desc.BufferDesc.RefreshRate.Denominator); + *refresh_rate = + static_cast(desc.BufferDesc.RefreshRate.Numerator) / static_cast(desc.BufferDesc.RefreshRate.Denominator); return true; } } @@ -140,56 +139,19 @@ void D3D12HostDisplay::SetVSync(VsyncMode mode) bool D3D12HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync) { - ComPtr temp_dxgi_factory; - HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.put())); - if (FAILED(hr)) - { - Console.Error("Failed to create DXGI factory: 0x%08X", hr); - return false; - } - - u32 adapter_index; - if (!EmuConfig.GS.Adapter.empty()) - { - AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get())); - for (adapter_index = 0; adapter_index < static_cast(adapter_info.adapter_names.size()); adapter_index++) - { - if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index]) - break; - } - if (adapter_index == static_cast(adapter_info.adapter_names.size())) - { - Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(), adapter_info.adapter_names[0].c_str()); - adapter_index = 0; - } - } - else - { - Console.WriteLn("No adapter selected, using first."); - adapter_index = 0; - } - - if (!D3D12::Context::Create(temp_dxgi_factory.get(), adapter_index, EmuConfig.GS.UseDebugDevice)) + m_dxgi_factory = D3D::CreateFactory(EmuConfig.GS.UseDebugDevice); + if (!m_dxgi_factory) return false; - if (FAILED(hr)) - { - Console.Error("Failed to create D3D device: 0x%08X", hr); + ComPtr dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), EmuConfig.GS.Adapter); + + if (!D3D12::Context::Create(m_dxgi_factory.get(), dxgi_adapter.get(), EmuConfig.GS.UseDebugDevice)) return false; - } - m_dxgi_factory = std::move(temp_dxgi_factory); - - m_allow_tearing_supported = false; - ComPtr dxgi_factory5(m_dxgi_factory.try_query()); - if (dxgi_factory5) - { - BOOL allow_tearing_supported = false; - hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, - sizeof(allow_tearing_supported)); - if (SUCCEEDED(hr)) - m_allow_tearing_supported = (allow_tearing_supported == TRUE); - } + BOOL allow_tearing_supported = false; + HRESULT hr = + m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported)); + m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE); m_window_info = wi; m_vsync_mode = vsync; @@ -226,40 +188,43 @@ bool D3D12HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode) const u32 width = static_cast(client_rc.right - client_rc.left); const u32 height = static_cast(client_rc.bottom - client_rc.top); - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferDesc.Width = width; - swap_chain_desc.BufferDesc.Height = height; - swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.Width = width; + swap_chain_desc.Height = height; + swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.BufferCount = 3; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = window_hwnd; - swap_chain_desc.Windowed = TRUE; swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; m_using_allow_tearing = (m_allow_tearing_supported && !fullscreen_mode); if (m_using_allow_tearing) swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fs_desc = {}; if (fullscreen_mode) { swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - swap_chain_desc.Windowed = FALSE; - swap_chain_desc.BufferDesc = *fullscreen_mode; + swap_chain_desc.Width = fullscreen_mode->Width; + swap_chain_desc.Height = fullscreen_mode->Height; + fs_desc.RefreshRate = fullscreen_mode->RefreshRate; + fs_desc.ScanlineOrdering = fullscreen_mode->ScanlineOrdering; + fs_desc.Scaling = fullscreen_mode->Scaling; + fs_desc.Windowed = FALSE; } - DevCon.WriteLn("Creating a %dx%d %s swap chain", swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height, - swap_chain_desc.Windowed ? "windowed" : "full-screen"); + DevCon.WriteLn( + "Creating a %dx%d %s swap chain", swap_chain_desc.Width, swap_chain_desc.Height, fullscreen_mode ? "full-screen" : "windowed"); - HRESULT hr = - m_dxgi_factory->CreateSwapChain(g_d3d12_context->GetCommandQueue(), &swap_chain_desc, m_swap_chain.put()); + HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd(g_d3d12_context->GetCommandQueue(), window_hwnd, &swap_chain_desc, + fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put()); if (FAILED(hr)) { - Console.Error("CreateSwapChain failed: 0x%08X", hr); + Console.Error("CreateSwapChainForHwnd failed: 0x%08X", hr); return false; } - hr = m_dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); + hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES); if (FAILED(hr)) Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed"); @@ -301,11 +266,10 @@ bool D3D12HostDisplay::CreateSwapChainRTV() { BOOL fullscreen = FALSE; DXGI_SWAP_CHAIN_DESC desc; - if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && - SUCCEEDED(m_swap_chain->GetDesc(&desc))) + if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && SUCCEEDED(m_swap_chain->GetDesc(&desc))) { - m_window_info.surface_refresh_rate = static_cast(desc.BufferDesc.RefreshRate.Numerator) / - static_cast(desc.BufferDesc.RefreshRate.Denominator); + m_window_info.surface_refresh_rate = + static_cast(desc.BufferDesc.RefreshRate.Numerator) / static_cast(desc.BufferDesc.RefreshRate.Denominator); } else { @@ -402,8 +366,7 @@ void D3D12HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, DestroySwapChainRTVs(); - HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, - m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); + HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); if (FAILED(hr)) Console.Error("ResizeBuffers() failed: 0x%08X", hr); @@ -529,7 +492,8 @@ HostDisplay::PresentResult D3D12HostDisplay::BeginPresent(bool frame_skip) cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), clear_color.data(), 0, nullptr); cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetWriteDescriptor().cpu_handle, FALSE, nullptr); - const D3D12_VIEWPORT vp{0.0f, 0.0f, static_cast(m_window_info.surface_width), static_cast(m_window_info.surface_height), 0.0f, 1.0f}; + const D3D12_VIEWPORT vp{ + 0.0f, 0.0f, static_cast(m_window_info.surface_width), static_cast(m_window_info.surface_height), 0.0f, 1.0f}; const D3D12_RECT scissor{0, 0, static_cast(m_window_info.surface_width), static_cast(m_window_info.surface_height)}; cmdlist->RSSetViewports(1, &vp); cmdlist->RSSetScissorRects(1, &scissor); @@ -571,77 +535,38 @@ float D3D12HostDisplay::GetAndResetAccumulatedGPUTime() HostDisplay::AdapterAndModeList D3D12HostDisplay::StaticGetAdapterAndModeList() { - ComPtr dxgi_factory; - const HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.put())); - if (FAILED(hr)) + auto factory = D3D::CreateFactory(false); + if (!factory) return {}; - return GetAdapterAndModeList(dxgi_factory.get()); + return GetAdapterAndModeList(factory.get()); } -HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFactory* dxgi_factory) +HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFactory5* dxgi_factory) { AdapterAndModeList adapter_info; - ComPtr current_adapter; - while (SUCCEEDED(dxgi_factory->EnumAdapters(static_cast(adapter_info.adapter_names.size()), - current_adapter.put()))) - { - DXGI_ADAPTER_DESC adapter_desc; - std::string adapter_name; - if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc))) - { - char adapter_name_buffer[128]; - const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, - static_cast(std::wcslen(adapter_desc.Description)), - adapter_name_buffer, std::size(adapter_name_buffer), 0, nullptr); - if (name_length >= 0) - adapter_name.assign(adapter_name_buffer, static_cast(name_length)); - else - adapter_name.assign("(Unknown)"); - } - else - { - adapter_name.assign("(Unknown)"); - } + adapter_info.adapter_names = D3D::GetAdapterNames(dxgi_factory); - if (adapter_info.fullscreen_modes.empty()) + auto adapter = D3D::GetChosenOrFirstAdapter(dxgi_factory, EmuConfig.GS.Adapter); + if (adapter) + { + ComPtr output; + if (SUCCEEDED(adapter->EnumOutputs(0, &output))) { - ComPtr output; - if (SUCCEEDED(current_adapter->EnumOutputs(0, &output))) + UINT num_modes = 0; + if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) { - UINT num_modes = 0; - if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) + std::vector modes(num_modes); + if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data()))) { - std::vector modes(num_modes); - if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data()))) + for (const DXGI_MODE_DESC& mode : modes) { - for (const DXGI_MODE_DESC& mode : modes) - { - adapter_info.fullscreen_modes.push_back(StringUtil::StdStringFromFormat( - "%u x %u @ %f hz", mode.Width, mode.Height, - static_cast(mode.RefreshRate.Numerator) / static_cast(mode.RefreshRate.Denominator))); - } + adapter_info.fullscreen_modes.push_back(GetFullscreenModeString(mode.Width, mode.Height, + static_cast(mode.RefreshRate.Numerator) / static_cast(mode.RefreshRate.Denominator))); } } } } - - // handle duplicate adapter names - if (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })) - { - std::string original_adapter_name = std::move(adapter_name); - - u32 current_extra = 2; - do - { - adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); - current_extra++; - } while (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })); - } - - adapter_info.adapter_names.push_back(std::move(adapter_name)); } return adapter_info; diff --git a/pcsx2/Frontend/D3D12HostDisplay.h b/pcsx2/Frontend/D3D12HostDisplay.h index 8487dd8de0..23bfd9455b 100644 --- a/pcsx2/Frontend/D3D12HostDisplay.h +++ b/pcsx2/Frontend/D3D12HostDisplay.h @@ -25,7 +25,7 @@ #include "HostDisplay.h" #include -#include +#include #include #include #include @@ -80,7 +80,7 @@ public: static AdapterAndModeList StaticGetAdapterAndModeList(); protected: - static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); + static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory5* dxgi_factory); bool CreateImGuiContext() override; void DestroyImGuiContext() override; @@ -90,8 +90,8 @@ protected: bool CreateSwapChainRTV(); void DestroySwapChainRTVs(); - ComPtr m_dxgi_factory; - ComPtr m_swap_chain; + ComPtr m_dxgi_factory; + ComPtr m_swap_chain; std::vector m_swap_chain_buffers; u32 m_current_swap_chain_buffer = 0; diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 8418c4a1b8..6adcfd04a9 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -129,24 +129,6 @@ void GSclose() static RenderAPI GetAPIForRenderer(GSRendererType renderer) { -#if defined(_WIN32) - // On Windows, we use DX11 for software, since it's always available. - constexpr RenderAPI default_api = RenderAPI::D3D11; -#elif defined(__APPLE__) - // For Macs, default to Metal. - constexpr RenderAPI default_api = RenderAPI::Metal; -#else - // For Linux, default to OpenGL (because of hardware compatibility), if we - // have it, otherwise Vulkan (if we have it). -#if defined(ENABLE_OPENGL) - constexpr RenderAPI default_api = RenderAPI::OpenGL; -#elif defined(ENABLE_VULKAN) - constexpr RenderAPI default_api = RenderAPI::Vulkan; -#else - constexpr RenderAPI default_api = RenderAPI::None; -#endif -#endif - switch (renderer) { case GSRendererType::OGL: @@ -169,7 +151,7 @@ static RenderAPI GetAPIForRenderer(GSRendererType renderer) #endif default: - return default_api; + return GetAPIForRenderer(GSUtil::GetPreferredRenderer()); } } diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index 1d2e32bd49..a9b1ad5fe1 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -203,25 +203,14 @@ GSRendererType GSUtil::GetPreferredRenderer() // Mac: Prefer Metal hardware. return GSRendererType::Metal; #elif defined(_WIN32) - const u8 preferred = D3D::ShouldPreferRenderer(); -#if defined(ENABLE_VULKAN) - if (preferred == D3D::Renderer::Vulkan) - return GSRendererType::VK; -#endif -#if defined(ENABLE_OPENGL) - if (preferred == D3D::Renderer::OpenGL) - return GSRendererType::OGL; -#endif - if (preferred == D3D::Renderer::Direct3D12) - return GSRendererType::DX12; - - return GSRendererType::DX11; + // Use D3D device info to select renderer. + return D3D::GetPreferredRenderer(); #else // Linux: Prefer GL/Vulkan, whatever is available. #if defined(ENABLE_OPENGL) return GSRendererType::OGL; #elif defined(ENABLE_VULKAN) - return GSRendererType::Vulkan; + return GSRendererType::VK; #else return GSRendererType::SW; #endif diff --git a/pcsx2/GS/Renderers/DX11/D3D.cpp b/pcsx2/GS/Renderers/DX11/D3D.cpp index 07fcd1bd9c..ffc3597e87 100644 --- a/pcsx2/GS/Renderers/DX11/D3D.cpp +++ b/pcsx2/GS/Renderers/DX11/D3D.cpp @@ -17,194 +17,278 @@ #include "GS/Renderers/DX11/D3D.h" #include "GS/GSExtra.h" +#include "common/Console.h" #include "common/StringUtil.h" #include #include "fmt/format.h" -namespace D3D +wil::com_ptr_nothrow D3D::CreateFactory(bool debug) { - wil::com_ptr_nothrow CreateFactory(bool debug) + UINT flags = 0; + if (debug) + flags |= DXGI_CREATE_FACTORY_DEBUG; + + wil::com_ptr_nothrow factory; + const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.put())); + if (FAILED(hr)) + Console.Error("D3D: Failed to create DXGI factory: %08X", hr); + + return factory; +} + +static std::string FixupDuplicateAdapterNames(const std::vector& adapter_names, std::string adapter_name) +{ + if (std::any_of(adapter_names.begin(), adapter_names.end(), + [&adapter_name](const std::string& other) { return (adapter_name == other); })) { - UINT flags = 0; - if (debug) - flags |= DXGI_CREATE_FACTORY_DEBUG; + std::string original_adapter_name = std::move(adapter_name); - // we use CreateDXGIFactory2 because we assume at least windows 8.1 anyway - wil::com_ptr_nothrow factory; - HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.put())); - - // if we failed to create a factory with debug support - // try one without - if (FAILED(hr) && debug) + u32 current_extra = 2; + do { - fprintf(stderr, "D3D: failed to create debug dxgi factory, trying without debugging\n"); - hr = CreateDXGIFactory2(0, IID_PPV_ARGS(factory.put()));; - } + adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); + current_extra++; + } while (std::any_of(adapter_names.begin(), adapter_names.end(), + [&adapter_name](const std::string& other) { return (adapter_name == other); })); + } + + return adapter_name; +} + +std::vector D3D::GetAdapterNames(IDXGIFactory5* factory) +{ + std::vector adapter_names; + + wil::com_ptr_nothrow adapter; + for (u32 index = 0;; index++) + { + const HRESULT hr = factory->EnumAdapters1(index, adapter.put()); + if (hr == DXGI_ERROR_NOT_FOUND) + break; if (FAILED(hr)) { - fprintf(stderr, "D3D: failed to create dxgi factory\n" - "check that your system meets our minimum requirements:\n" - "https://github.com/PCSX2/pcsx2#system-requirements\n"); + Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr)); + continue; } - return factory; + adapter_names.push_back(FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get()))); } - wil::com_ptr_nothrow GetAdapterFromIndex(IDXGIFactory2* factory, int index) - { - ASSERT(factory); + return adapter_names; +} - wil::com_ptr_nothrow adapter; - if (index < 0 || factory->EnumAdapters1(index, adapter.put()) == DXGI_ERROR_NOT_FOUND) +wil::com_ptr_nothrow D3D::GetAdapterByName(IDXGIFactory5* factory, const std::string_view& name) +{ + if (name.empty()) + return {}; + + // This might seem a bit odd to cache the names.. but there's a method to the madness. + // We might have two GPUs with the same name... :) + std::vector adapter_names; + + wil::com_ptr_nothrow adapter; + for (u32 index = 0;; index++) + { + const HRESULT hr = factory->EnumAdapters1(index, adapter.put()); + if (hr == DXGI_ERROR_NOT_FOUND) + break; + + if (FAILED(hr)) { - // try index 0 (default adapter) - if (index >= 0) - fprintf(stderr, "D3D: adapter not found, falling back to the default\n"); - if (FAILED(factory->EnumAdapters1(0, adapter.put()))) - { - // either there are no adapters connected or something major is wrong with the system - fprintf(stderr, "D3D: failed to EnumAdapters\n"); - } + Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr)); + continue; } - return adapter; + std::string adapter_name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get())); + if (adapter_name == name) + { + Console.WriteLn(fmt::format("D3D: Found adapter '{}'", adapter_name)); + return adapter; + } + + adapter_names.push_back(std::move(adapter_name)); } - std::string GetDriverVersionFromLUID(const LUID& luid) - { - std::string ret; + Console.Warning(fmt::format("Adapter '{}' not found.", name)); + return {}; +} - HKEY hKey; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS) +wil::com_ptr_nothrow D3D::GetFirstAdapter(IDXGIFactory5* factory) +{ + wil::com_ptr_nothrow adapter; + HRESULT hr = factory->EnumAdapters1(0, adapter.put()); + if (FAILED(hr)) + Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() for first adapter returned %08X", hr)); + + return adapter; +} + +wil::com_ptr_nothrow D3D::GetChosenOrFirstAdapter(IDXGIFactory5* factory, const std::string_view& name) +{ + wil::com_ptr_nothrow adapter = GetAdapterByName(factory, name); + if (!adapter) + adapter = GetFirstAdapter(factory); + + return adapter; +} + +std::string D3D::GetAdapterName(IDXGIAdapter1* adapter) +{ + std::string ret; + + DXGI_ADAPTER_DESC1 desc; + HRESULT hr = adapter->GetDesc1(&desc); + if (SUCCEEDED(hr)) + { + ret = StringUtil::WideStringToUTF8String(desc.Description); + } + else + { + Console.Error(fmt::format("IDXGIAdapter1::GetDesc() returned {:08X}", hr)); + } + + if (ret.empty()) + ret = "(Unknown)"; + + return ret; +} + +std::string D3D::GetDriverVersionFromLUID(const LUID& luid) +{ + std::string ret; + + HKEY hKey; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + DWORD max_key_len = 0, adapter_count = 0; + if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr) == ERROR_SUCCESS) { - DWORD max_key_len = 0, adapter_count = 0; - if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) + std::vector current_name(max_key_len + 1); + for (DWORD i = 0; i < adapter_count; ++i) { - std::vector current_name(max_key_len + 1); - for (DWORD i = 0; i < adapter_count; ++i) + DWORD subKeyLength = static_cast(current_name.size()); + if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, nullptr) == + ERROR_SUCCESS) { - DWORD subKeyLength = static_cast(current_name.size()); - if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, - nullptr) == ERROR_SUCCESS) + LUID current_luid = {}; + DWORD current_luid_size = sizeof(uint64_t); + if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, ¤t_luid, + ¤t_luid_size) == ERROR_SUCCESS && + current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart) { - LUID current_luid = {}; - DWORD current_luid_size = sizeof(uint64_t); - if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, - ¤t_luid, ¤t_luid_size) == ERROR_SUCCESS && - current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart) + LARGE_INTEGER driver_version = {}; + DWORD driver_version_size = sizeof(driver_version); + if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, + &driver_version, &driver_version_size) == ERROR_SUCCESS) { - LARGE_INTEGER driver_version = {}; - DWORD driver_version_size = sizeof(driver_version); - if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, - &driver_version, &driver_version_size) == ERROR_SUCCESS) - { - WORD nProduct = HIWORD(driver_version.HighPart); - WORD nVersion = LOWORD(driver_version.HighPart); - WORD nSubVersion = HIWORD(driver_version.LowPart); - WORD nBuild = LOWORD(driver_version.LowPart); - ret = fmt::format("{}.{}.{}.{}", nProduct, nVersion, nSubVersion, nBuild); - } + WORD nProduct = HIWORD(driver_version.HighPart); + WORD nVersion = LOWORD(driver_version.HighPart); + WORD nSubVersion = HIWORD(driver_version.LowPart); + WORD nBuild = LOWORD(driver_version.LowPart); + ret = fmt::format("{}.{}.{}.{}", nProduct, nVersion, nSubVersion, nBuild); } } } } - - RegCloseKey(hKey); } - return ret; + RegCloseKey(hKey); } - u8 Vendor() + return ret; +} + +D3D::VendorID D3D::GetVendorID(IDXGIAdapter1* adapter) +{ + DXGI_ADAPTER_DESC1 desc; + const HRESULT hr = adapter->GetDesc1(&desc); + if (FAILED(hr)) { - auto factory = CreateFactory(false); - auto adapter = GetAdapterFromIndex(factory.get(), 0); + Console.Error(fmt::format("IDXGIAdapter1::GetDesc() returned {:08X}", hr)); + return VendorID::Unknown; + } - ASSERT(adapter); - - DXGI_ADAPTER_DESC1 desc = {}; - if (FAILED(adapter->GetDesc1(&desc))) - { - fprintf(stderr, "D3D: failed to get the adapter description\n"); + switch (desc.VendorId) + { + case 0x10DE: + return VendorID::Nvidia; + case 0x1002: + case 0x1022: + return VendorID::AMD; + case 0x163C: + case 0x8086: + case 0x8087: + return VendorID::Intel; + default: return VendorID::Unknown; - } + } +} - switch (desc.VendorId) - { - case 0x10DE: - return VendorID::Nvidia; - case 0x1002: - case 0x1022: - return VendorID::AMD; - case 0x163C: - case 0x8086: - case 0x8087: - return VendorID::Intel; - default: - return VendorID::Unknown; - } +GSRendererType D3D::GetPreferredRenderer() +{ + auto factory = CreateFactory(false); + auto adapter = GetChosenOrFirstAdapter(factory.get(), GSConfig.Adapter); + + // If we somehow can't get a D3D11 device, it's unlikely any of the renderers are going to work. + if (!adapter) + return GSRendererType::DX11; + + D3D_FEATURE_LEVEL feature_level; + + static const D3D_FEATURE_LEVEL check[] = { + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_0, + }; + + const HRESULT hr = D3D11CreateDevice(adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, std::data(check), + std::size(check), D3D11_SDK_VERSION, nullptr, &feature_level, nullptr); + + if (FAILED(hr)) + { + // See note above. + return GSRendererType::DX11; } - u8 ShouldPreferRenderer() + switch (GetVendorID(adapter.get())) { - auto factory = CreateFactory(false); - auto adapter = GetAdapterFromIndex(factory.get(), 0); - - ASSERT(adapter); - - D3D_FEATURE_LEVEL feature_level; - - static const D3D_FEATURE_LEVEL check[] = { - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_0, - }; - - const HRESULT hr = D3D11CreateDevice( - adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, - std::data(check), std::size(check), D3D11_SDK_VERSION, nullptr, &feature_level, nullptr - ); - - if (FAILED(hr)) - return Renderer::Default; - - switch (Vendor()) + case VendorID::Nvidia: { - case VendorID::Nvidia: - { - if (feature_level == D3D_FEATURE_LEVEL_12_0) - return Renderer::Vulkan; - else if (feature_level == D3D_FEATURE_LEVEL_11_0) - return Renderer::OpenGL; - else - return Renderer::Direct3D11; - } + if (feature_level == D3D_FEATURE_LEVEL_12_0) + return GSRendererType::VK; + else if (feature_level == D3D_FEATURE_LEVEL_11_0) + return GSRendererType::OGL; + else + return GSRendererType::DX11; + } - case VendorID::AMD: - { - if (feature_level == D3D_FEATURE_LEVEL_12_0) - return Renderer::Vulkan; - else - return Renderer::Direct3D11; - } + case VendorID::AMD: + { + if (feature_level == D3D_FEATURE_LEVEL_12_0) + return GSRendererType::VK; + else + return GSRendererType::DX11; + } - case VendorID::Intel: - { - // Older Intel GPUs prior to Xe seem to have broken OpenGL drivers which choke - // on some of our shaders, causing what appears to be GPU timeouts+device removals. - // Vulkan has broken barriers, also prior to Xe. So just fall back to DX11 everywhere, - // unless we can find some way of differentiating Xe. - return Renderer::Direct3D11; - } + case VendorID::Intel: + { + // Older Intel GPUs prior to Xe seem to have broken OpenGL drivers which choke + // on some of our shaders, causing what appears to be GPU timeouts+device removals. + // Vulkan has broken barriers, also prior to Xe. So just fall back to DX11 everywhere, + // unless we have Arc, which is easy to identify. + if (StringUtil::StartsWith(GetAdapterName(adapter.get()), "Intel(R) Arc(TM) ")) + return GSRendererType::VK; + else + return GSRendererType::DX11; + } - default: - { - // Default is D3D11 - return Renderer::Direct3D11; - } + default: + { + // Default is D3D11 + return GSRendererType::DX11; } } } diff --git a/pcsx2/GS/Renderers/DX11/D3D.h b/pcsx2/GS/Renderers/DX11/D3D.h index ba7b0a0ee8..dc53c6ce1b 100644 --- a/pcsx2/GS/Renderers/DX11/D3D.h +++ b/pcsx2/GS/Renderers/DX11/D3D.h @@ -18,26 +18,39 @@ #include "common/RedtapeWindows.h" #include "common/RedtapeWilCom.h" -#include -#include +#include "pcsx2/Config.h" + +#include #include +#include +#include namespace D3D { // create a dxgi factory - wil::com_ptr_nothrow CreateFactory(bool debug); + wil::com_ptr_nothrow CreateFactory(bool debug); - // get an adapter based on position - // assuming no one removes/moves it, it should always have the same id - // however in the event that the adapter is not found due to the above, use the default - wil::com_ptr_nothrow GetAdapterFromIndex(IDXGIFactory2* factory, int index); + // returns a list of all adapter names + std::vector GetAdapterNames(IDXGIFactory5* factory); + + // get an adapter based on name + wil::com_ptr_nothrow GetAdapterByName(IDXGIFactory5* factory, const std::string_view& name); + + // returns the first adapter in the system + wil::com_ptr_nothrow GetFirstAdapter(IDXGIFactory5* factory); + + // returns the adapter specified in the configuration, or the default + wil::com_ptr_nothrow GetChosenOrFirstAdapter(IDXGIFactory5* factory, const std::string_view& name); + + // returns a utf-8 string of the specified adapter's name + std::string GetAdapterName(IDXGIAdapter1* adapter); // returns the driver version from the registry as a string std::string GetDriverVersionFromLUID(const LUID& luid); // this is sort of a legacy thing that doesn't have much to do with d3d (just the easiest way) // checks to see if the adapter at 0 is NV and thus we should prefer OpenGL - enum VendorID + enum class VendorID { Unknown, Nvidia, @@ -45,15 +58,6 @@ namespace D3D Intel }; - enum Renderer - { - Default, - OpenGL, - Vulkan, - Direct3D11, - Direct3D12 - }; - - u8 Vendor(); - u8 ShouldPreferRenderer(); -}; + VendorID GetVendorID(IDXGIAdapter1* adapter); + GSRendererType GetPreferredRenderer(); +}; // namespace D3D diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 2e43d4db74..e4705179ea 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -119,7 +119,13 @@ bool GSDevice11::Create() { // HACK: check AMD // Broken point sampler should be enabled only on AMD. - m_features.broken_point_sampler = (D3D::Vendor() == D3D::VendorID::AMD); + wil::com_ptr_nothrow dxgi_device; + wil::com_ptr_nothrow dxgi_adapter; + if (SUCCEEDED(m_dev->QueryInterface(dxgi_device.put())) && + SUCCEEDED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put())))) + { + m_features.broken_point_sampler = (D3D::GetVendorID(dxgi_adapter.get()) == D3D::VendorID::AMD); + } } SetFeatures();