From e5c10520620a45368487fd995f6ef1f3096fafcf Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 11 May 2023 19:45:57 +1000 Subject: [PATCH] GS: Add option to disable vertex shader expand And automatically disable it on Fermi (buggy driver). --- pcsx2-qt/Settings/GraphicsSettingsWidget.cpp | 1 + pcsx2-qt/Settings/GraphicsSettingsWidget.ui | 29 ++++++++++++-------- pcsx2/Config.h | 1 + pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 20 ++++++++++++-- pcsx2/GS/Renderers/DX11/GSDevice11.h | 2 +- pcsx2/GS/Renderers/DX12/GSDevice12.cpp | 2 +- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 2 +- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 10 ++++++- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 3 +- pcsx2/GS/Renderers/Vulkan/VKContext.h | 1 - pcsx2/Pcsx2Config.cpp | 3 ++ 11 files changed, 54 insertions(+), 20 deletions(-) diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index ca8d3623e1..267226cdda 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -252,6 +252,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "EmuCore/GS", "DisableFramebufferFetch", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "EmuCore/GS", "DisableDualSourceBlend", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableShaderCache, "EmuCore/GS", "DisableShaderCache", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableVertexShaderExpand, "EmuCore/GS", "DisableVertexShaderExpand", false); SettingWidgetBinder::BindWidgetToIntSetting( sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast(GSHardwareDownloadMode::Enabled)); diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index 2f25abfdc2..bd141392cf 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -7,7 +7,7 @@ 0 0 720 - 498 + 492 @@ -2146,13 +2146,6 @@ - - - - Disable Dual Source Blending - - - @@ -2160,10 +2153,10 @@ - - + + - Use Debug Device + Disable Dual Source Blending @@ -2174,6 +2167,20 @@ + + + + Use Debug Device + + + + + + + Disable Vertex Shader Expand + + + diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 2f696d73f6..c493ecddc0 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -647,6 +647,7 @@ struct Pcsx2Config DisableShaderCache : 1, DisableDualSourceBlend : 1, DisableFramebufferFetch : 1, + DisableVertexShaderExpand : 1, DisableThreadedPresentation : 1, SkipDuplicateFrames : 1, OsdShowMessages : 1, diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 18af60ef8d..ec6306f888 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -188,7 +188,7 @@ bool GSDevice11::Create() } } - SetFeatures(); + SetFeatures(dxgi_adapter.get()); std::optional shader = Host::ReadResourceFileToString("shaders/dx11/tfx.fx"); if (!shader.has_value()) @@ -532,7 +532,7 @@ void GSDevice11::Destroy() #endif } -void GSDevice11::SetFeatures() +void GSDevice11::SetFeatures(IDXGIAdapter1* adapter) { // Check all three formats, since the feature means any can be used. m_features.dxt_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC1_UNORM) && @@ -542,7 +542,21 @@ void GSDevice11::SetFeatures() m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM); const D3D_FEATURE_LEVEL feature_level = m_dev->GetFeatureLevel(); - m_features.vs_expand = (feature_level >= D3D_FEATURE_LEVEL_11_0); + m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && feature_level >= D3D_FEATURE_LEVEL_11_0); + + // NVIDIA GPUs prior to Kepler appear to have broken vertex shader buffer loading. + if (m_features.vs_expand && (D3D::GetVendorID(adapter) == D3D::VendorID::Nvidia)) + { + // There's nothing Fermi specific which we can query in DX11. Closest we have is typed UAV loads, + // which is Kepler+. Anyone using Kepler should be using Vulkan anyway. + D3D11_FEATURE_DATA_D3D11_OPTIONS2 options; + if (SUCCEEDED(m_dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &options, sizeof(options))) && + !options.TypedUAVLoadAdditionalFormats) + { + Console.Warning("Disabling VS expand due to potentially buggy NVIDIA driver."); + m_features.vs_expand = false; + } + } } bool GSDevice11::HasSurface() const diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index bcd9ee57e4..1528fa58b6 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -118,7 +118,7 @@ private: NUM_TIMESTAMP_QUERIES = 5, }; - void SetFeatures(); + void SetFeatures(IDXGIAdapter1* adapter); bool CreateSwapChain(); bool CreateSwapChainRTV(); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index e18c2b297c..cb2c5ce2d0 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -610,7 +610,7 @@ bool GSDevice12::CheckFeatures() m_features.clip_control = true; m_features.stencil_buffer = true; m_features.test_and_sample_depth = false; - m_features.vs_expand = true; + m_features.vs_expand = !GSConfig.DisableVertexShaderExpand; m_features.dxt_textures = g_d3d12_context->SupportsTextureFormat(DXGI_FORMAT_BC1_UNORM) && g_d3d12_context->SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) && diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index 8854ad1afa..1d960f939f 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -833,7 +833,7 @@ bool GSDeviceMTL::Create() MTLPixelFormat layer_px_fmt = [m_layer pixelFormat]; m_features.broken_point_sampler = [[m_dev.dev name] containsString:@"AMD"]; - m_features.vs_expand = true; + m_features.vs_expand = !GSConfig.DisableVertexShaderExpand; m_features.primitive_id = m_dev.features.primid; m_features.texture_barrier = true; m_features.provoking_vertex_last = false; diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index ec12c2cb6d..55d9f4eda3 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -159,12 +159,20 @@ bool GSDeviceOGL::Create() m_features.stencil_buffer = true; m_features.test_and_sample_depth = m_features.texture_barrier; + // NVIDIA GPUs prior to Kepler appear to have broken vertex shader buffer loading. + // Use bindless textures (introduced in Kepler) to differentiate. + const bool buggy_vs_expand = + GLLoader::vendor_id_nvidia && (!GLAD_GL_ARB_bindless_texture && !GLAD_GL_NV_bindless_texture); + if (buggy_vs_expand) + Console.Warning("Disabling vertex shader expand due to broken NVIDIA driver."); + if (GLAD_GL_ARB_shader_storage_buffer_object) { GLint max_vertex_ssbos = 0; glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max_vertex_ssbos); DevCon.WriteLn("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: %d", max_vertex_ssbos); - m_features.vs_expand = (max_vertex_ssbos > 0 && GLAD_GL_ARB_gpu_shader5); + m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && !buggy_vs_expand && max_vertex_ssbos > 0 && + GLAD_GL_ARB_gpu_shader5); } if (!m_features.vs_expand) Console.Warning("Vertex expansion is not supported. This will reduce performance."); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 578e8c6215..2458ccd900 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -696,7 +696,8 @@ bool GSDeviceVK::CheckFeatures() m_features.provoking_vertex_last = g_vulkan_context->GetOptionalExtensions().vk_ext_provoking_vertex; m_features.dual_source_blend = features.dualSrcBlend && !GSConfig.DisableDualSourceBlend; m_features.clip_control = true; - m_features.vs_expand = g_vulkan_context->GetOptionalExtensions().vk_khr_shader_draw_parameters; + m_features.vs_expand = + !GSConfig.DisableVertexShaderExpand && g_vulkan_context->GetOptionalExtensions().vk_khr_shader_draw_parameters; if (!m_features.dual_source_blend) Console.Warning("Vulkan driver is missing dual-source blending. This will have an impact on performance."); diff --git a/pcsx2/GS/Renderers/Vulkan/VKContext.h b/pcsx2/GS/Renderers/Vulkan/VKContext.h index ff4eae7179..98738efbcd 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKContext.h +++ b/pcsx2/GS/Renderers/Vulkan/VKContext.h @@ -52,7 +52,6 @@ public: bool vk_ext_line_rasterization : 1; bool vk_ext_rasterization_order_attachment_access : 1; bool vk_ext_full_screen_exclusive : 1; - bool vk_ext_surface_maintenance1 : 1; bool vk_khr_driver_properties : 1; bool vk_khr_fragment_shader_barycentric : 1; bool vk_khr_shader_draw_parameters : 1; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 8244ce2bf3..c25d534bfa 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -415,6 +415,7 @@ Pcsx2Config::GSOptions::GSOptions() UseBlitSwapChain = false; DisableShaderCache = false; DisableFramebufferFetch = false; + DisableVertexShaderExpand = false; DisableThreadedPresentation = false; SkipDuplicateFrames = false; OsdShowMessages = true; @@ -579,6 +580,7 @@ bool Pcsx2Config::GSOptions::RestartOptionsAreEqual(const GSOptions& right) cons OpEqu(DisableShaderCache) && OpEqu(DisableDualSourceBlend) && OpEqu(DisableFramebufferFetch) && + OpEqu(DisableVertexShaderExpand) && OpEqu(DisableThreadedPresentation) && OpEqu(OverrideTextureBarriers) && OpEqu(ExclusiveFullscreenControl); @@ -634,6 +636,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) GSSettingBool(DisableShaderCache); GSSettingBool(DisableDualSourceBlend); GSSettingBool(DisableFramebufferFetch); + GSSettingBool(DisableVertexShaderExpand); GSSettingBool(DisableThreadedPresentation); GSSettingBool(SkipDuplicateFrames); GSSettingBool(OsdShowMessages);