From e382f2b64ad3fca092cdeac38db51a2e490f6150 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 28 Nov 2023 14:08:29 +1000 Subject: [PATCH] Settings: Add option to disable DSB/fbfetch --- src/common/CMakeLists.txt | 4 ++-- src/core/host.cpp | 16 +++++++++++----- src/core/settings.cpp | 4 ++++ src/core/settings.h | 2 ++ src/core/system.cpp | 13 ++++++++++--- src/duckstation-qt/advancedsettingswidget.cpp | 9 +++++++++ src/util/d3d11_device.cpp | 13 +++++++------ src/util/d3d11_device.h | 4 ++-- src/util/d3d12_device.cpp | 14 +++++++------- src/util/d3d12_device.h | 5 +++-- src/util/gpu_device.cpp | 5 +++-- src/util/gpu_device.h | 12 ++++++++++-- src/util/metal_device.h | 4 ++-- src/util/metal_device.mm | 12 ++++++------ src/util/opengl_device.cpp | 18 +++++++++++------- src/util/opengl_device.h | 4 ++-- src/util/vulkan_device.cpp | 17 ++++++++++------- src/util/vulkan_device.h | 5 +++-- src/util/vulkan_pipeline.cpp | 4 ++-- 19 files changed, 106 insertions(+), 59 deletions(-) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c877f9024..b6b0073ba 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -71,11 +71,11 @@ if(WIN32) endif() if(MSVC) - if(${CPU_ARCH} STREQUAL "x64") + if(CPU_ARCH_X64) enable_language(ASM_MASM) target_sources(common PRIVATE fastjmp_x86.asm) set_source_files_properties(fastjmp_x86.asm PROPERTIES COMPILE_FLAGS "/D_M_X86_64") - elseif(${CPU_ARCH} STREQUAL "aarch32" OR ${CPU_ARCH} STREQUAL "aarch64") + elseif(CPU_ARCH_ARM32 OR CPU_ARCH_ARM64) enable_language(ASM_MARMASM) target_sources(common PRIVATE fastjmp_arm.asm) endif() diff --git a/src/core/host.cpp b/src/core/host.cpp index 0797384de..a11b833e9 100644 --- a/src/core/host.cpp +++ b/src/core/host.cpp @@ -241,13 +241,19 @@ bool Host::CreateGPUDevice(RenderAPI api) Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api)); g_gpu_device = GPUDevice::CreateDeviceForAPI(api); + u32 disabled_features = 0; + if (g_settings.gpu_disable_dual_source_blend) + disabled_features |= GPUDevice::FEATURE_MASK_DUAL_SOURCE_BLEND; + if (g_settings.gpu_disable_framebuffer_fetch) + disabled_features |= GPUDevice::FEATURE_MASK_FRAMEBUFFER_FETCH; + // TODO: FSUI should always use vsync.. const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled; - if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter, - g_settings.gpu_disable_shader_cache ? std::string_view() : - std::string_view(EmuFolders::Cache), - SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync, - g_settings.gpu_threaded_presentation)) + if (!g_gpu_device || !g_gpu_device->Create( + g_settings.gpu_adapter, + g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache), + SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync, + g_settings.gpu_threaded_presentation, static_cast(disabled_features))) { Log_ErrorPrintf("Failed to create GPU device."); if (g_gpu_device) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index de7cd5a38..cdee1b4a1 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -181,6 +181,8 @@ void Settings::Load(SettingsInterface& si) gpu_multisamples = static_cast(si.GetIntValue("GPU", "Multisamples", 1)); gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false); gpu_disable_shader_cache = si.GetBoolValue("GPU", "DisableShaderCache", false); + gpu_disable_dual_source_blend = si.GetBoolValue("GPU", "DisableDualSourceBlend", false); + gpu_disable_framebuffer_fetch = si.GetBoolValue("GPU", "DisableFramebufferFetch", false); gpu_per_sample_shading = si.GetBoolValue("GPU", "PerSampleShading", false); gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true); gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false); @@ -437,6 +439,8 @@ void Settings::Save(SettingsInterface& si) const si.SetIntValue("GPU", "Multisamples", static_cast(gpu_multisamples)); si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device); si.SetBoolValue("GPU", "DisableShaderCache", gpu_disable_shader_cache); + si.SetBoolValue("GPU", "DisableDualSourceBlend", gpu_disable_dual_source_blend); + si.SetBoolValue("GPU", "DisableFramebufferFetch", gpu_disable_framebuffer_fetch); si.SetBoolValue("GPU", "PerSampleShading", gpu_per_sample_shading); si.SetBoolValue("GPU", "UseThread", gpu_use_thread); si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation); diff --git a/src/core/settings.h b/src/core/settings.h index 80c6cdf21..8a4eea8b1 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -100,6 +100,8 @@ struct Settings bool gpu_threaded_presentation = true; bool gpu_use_debug_device = false; bool gpu_disable_shader_cache = false; + bool gpu_disable_dual_source_blend = false; + bool gpu_disable_framebuffer_fetch = false; bool gpu_per_sample_shading = false; bool gpu_true_color = true; bool gpu_scaled_dithering = true; diff --git a/src/core/system.cpp b/src/core/system.cpp index 63d119b45..f91e5199d 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -3525,11 +3525,18 @@ void System::CheckForSettingsChanges(const Settings& old_settings) { if (IsValid() && (g_settings.gpu_renderer != old_settings.gpu_renderer || g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device || - g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation)) + g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation || + g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache || + g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend || + g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch)) { // if debug device/threaded presentation change, we need to recreate the whole display - const bool recreate_device = (g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device || - g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation); + const bool recreate_device = + (g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device || + g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation || + g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache || + g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend || + g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch); Host::AddIconOSDMessage("RendererSwitch", ICON_FA_PAINT_ROLLER, fmt::format(TRANSLATE_FS("OSDMessage", "Switching to {}{} GPU renderer."), diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index 2fb9efdaa..51c41f71d 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -340,6 +340,10 @@ void AdvancedSettingsWidget::addTweakOptions() false); addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Shader Cache"), "GPU", "DisableShaderCache", false); + addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Dual-Source Blend"), "GPU", + "DisableDualSourceBlend", false); + addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Framebuffer Fetch"), "GPU", + "DisableFramebufferFetch", false); addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Stretch Display Vertically"), "Display", "StretchVertically", false); @@ -401,6 +405,8 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() static_cast(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); // GPU max run-ahead setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Use debug host GPU device setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Shader Cache + setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Dual-Source Blend + setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Framebuffer Fetch setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Stretch Display Vertically setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution setChoiceTweakOption(m_ui.tweakOptionTable, i++, @@ -447,6 +453,9 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() sif->DeleteValue("Hacks", "GPUFIFOSize"); sif->DeleteValue("Hacks", "GPUMaxRunAhead"); sif->DeleteValue("GPU", "UseDebugDevice"); + sif->DeleteValue("GPU", "DisableShaderCache"); + sif->DeleteValue("GPU", "DisableDualSourceBlend"); + sif->DeleteValue("GPU", "DisableFramebufferFetch"); sif->DeleteValue("Display", "StretchVertically"); sif->DeleteValue("Main", "IncreaseTimerResolution"); sif->DeleteValue("CDROM", "MechaconVersion"); diff --git a/src/util/d3d11_device.cpp b/src/util/d3d11_device.cpp index 948e16d2e..33e13e66b 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -63,7 +63,8 @@ bool D3D11Device::HasSurface() const return static_cast(m_swap_chain); } -bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation) +bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, + FeatureMask disabled_features) { std::unique_lock lock(s_instance_mutex); @@ -131,7 +132,7 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr sizeof(allow_tearing_supported)); m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE); - SetFeatures(); + SetFeatures(disabled_features); if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()) return false; @@ -152,7 +153,7 @@ void D3D11Device::DestroyDevice() m_device.Reset(); } -void D3D11Device::SetFeatures() +void D3D11Device::SetFeatures(FeatureMask disabled_features) { const D3D_FEATURE_LEVEL feature_level = m_device->GetFeatureLevel(); @@ -169,13 +170,13 @@ void D3D11Device::SetFeatures() } } - m_features.dual_source_blend = true; + m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND); m_features.framebuffer_fetch = false; m_features.per_sample_shading = (feature_level >= D3D_FEATURE_LEVEL_10_1); m_features.noperspective_interpolation = true; - m_features.supports_texture_buffers = true; + m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS); m_features.texture_buffers_emulated_with_ssbo = false; - m_features.geometry_shaders = true; + m_features.geometry_shaders = !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS); m_features.partial_msaa_resolve = false; m_features.gpu_timing = true; m_features.shader_cache = true; diff --git a/src/util/d3d11_device.h b/src/util/d3d11_device.h index 10ab7de45..67b12364a 100644 --- a/src/util/d3d11_device.h +++ b/src/util/d3d11_device.h @@ -111,7 +111,7 @@ public: static AdapterAndModeList StaticGetAdapterAndModeList(); protected: - bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override; + bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override; void DestroyDevice() override; private: @@ -129,7 +129,7 @@ private: static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory); - void SetFeatures(); + void SetFeatures(FeatureMask disabled_features); bool CheckStagingBufferSize(u32 width, u32 height, DXGI_FORMAT format); void DestroyStagingBuffer(); diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index 001e11c0a..9924c0873 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -116,7 +116,7 @@ D3D12Device::ComPtr D3D12Device::CreateRootSignature(const return rs; } -bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation) +bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) { std::unique_lock lock(s_instance_mutex); @@ -223,7 +223,7 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr return false; } - SetFeatures(); + SetFeatures(disabled_features); if (!CreateCommandLists() || !CreateDescriptorHeaps()) return false; @@ -1156,7 +1156,7 @@ void D3D12Device::InsertDebugMessage(const char* msg) #endif } -void D3D12Device::SetFeatures() +void D3D12Device::SetFeatures(FeatureMask disabled_features) { m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; m_max_multisamples = 1; @@ -1172,13 +1172,13 @@ void D3D12Device::SetFeatures() } } - m_features.dual_source_blend = true; + m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND); m_features.framebuffer_fetch = false; - m_features.noperspective_interpolation = true; m_features.per_sample_shading = true; - m_features.supports_texture_buffers = true; + m_features.noperspective_interpolation = true; + m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS); m_features.texture_buffers_emulated_with_ssbo = false; - m_features.geometry_shaders = true; + m_features.geometry_shaders = !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS); m_features.partial_msaa_resolve = true; m_features.gpu_timing = true; m_features.shader_cache = true; diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index d125058d1..d64ca4641 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -179,7 +179,8 @@ public: void UnbindTextureBuffer(D3D12TextureBuffer* buf); protected: - bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override; + bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, + FeatureMask disabled_features) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override; @@ -215,7 +216,7 @@ private: static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory); - void SetFeatures(); + void SetFeatures(FeatureMask disabled_features); bool CreateSwapChain(); bool CreateSwapChainRTV(); diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index def074a0a..80f66044c 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -223,7 +223,8 @@ bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs) } bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& shader_cache_path, - u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation) + u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation, + FeatureMask disabled_features) { m_vsync_enabled = vsync; m_debug_device = debug_device; @@ -234,7 +235,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& return false; } - if (!CreateDevice(adapter, threaded_presentation)) + if (!CreateDevice(adapter, threaded_presentation, disabled_features)) { Log_ErrorPrintf("Failed to create device."); return false; diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index a659e4c88..835290a1b 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -443,6 +443,14 @@ public: // TODO: gpu crash handling on present using DrawIndex = u16; + enum FeatureMask : u32 + { + FEATURE_MASK_DUAL_SOURCE_BLEND = (1 << 0), + FEATURE_MASK_FRAMEBUFFER_FETCH = (1 << 1), + FEATURE_MASK_TEXTURE_BUFFERS = (1 << 2), + FEATURE_MASK_GEOMETRY_SHADERS = (1 << 3), + }; + struct Features { bool dual_source_blend : 1; @@ -531,7 +539,7 @@ public: virtual RenderAPI GetRenderAPI() const = 0; bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version, - bool debug_device, bool vsync, bool threaded_presentation); + bool debug_device, bool vsync, bool threaded_presentation, FeatureMask disabled_features); void Destroy(); virtual bool HasSurface() const = 0; @@ -636,7 +644,7 @@ public: virtual float GetAndResetAccumulatedGPUTime(); protected: - virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) = 0; + virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) = 0; virtual void DestroyDevice() = 0; std::string GetShaderCacheBaseName(const std::string_view& type) const; diff --git a/src/util/metal_device.h b/src/util/metal_device.h index 6c4fe72ea..520d48cb8 100644 --- a/src/util/metal_device.h +++ b/src/util/metal_device.h @@ -283,7 +283,7 @@ public: static AdapterAndModeList StaticGetAdapterAndModeList(); protected: - bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override; + bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override; void DestroyDevice() override; private: @@ -298,7 +298,7 @@ private: ALWAYS_INLINE NSView* GetWindowView() const { return (__bridge NSView*)m_window_info.window_handle; } - void SetFeatures(); + void SetFeatures(FeatureMask disabled_features); bool LoadShaders(); id GetFunctionFromLibrary(id library, NSString* name); diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index d95f3189e..b0a8a2d96 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -123,7 +123,7 @@ void MetalDevice::SetVSync(bool enabled) [m_layer setDisplaySyncEnabled:enabled]; } -bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation) +bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) { @autoreleasepool { @@ -166,7 +166,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr m_queue = [queue retain]; Log_InfoPrintf("Metal Device: %s", [[m_device name] UTF8String]); - SetFeatures(); + SetFeatures(disabled_features); if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer()) return false; @@ -190,7 +190,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr } } -void MetalDevice::SetFeatures() +void MetalDevice::SetFeatures(FeatureMask disabled_features) { // https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] || @@ -211,11 +211,11 @@ void MetalDevice::SetFeatures() m_max_multisamples = multisamples; } - m_features.dual_source_blend = true; - m_features.framebuffer_fetch = false; // TODO + m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND); + m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && false; // TODO m_features.per_sample_shading = true; m_features.noperspective_interpolation = true; - m_features.supports_texture_buffers = true; + m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS); m_features.texture_buffers_emulated_with_ssbo = true; m_features.geometry_shaders = false; m_features.partial_msaa_resolve = false; diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 02b6c9026..f756ab360 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -299,7 +299,8 @@ bool OpenGLDevice::HasSurface() const return m_window_info.type != WindowInfo::Type::Surfaceless; } -bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation) +bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, + FeatureMask disabled_features) { m_gl_context = GL::Context::Create(m_window_info); if (!m_gl_context) @@ -348,7 +349,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p } bool buggy_pbo; - if (!CheckFeatures(&buggy_pbo)) + if (!CheckFeatures(&buggy_pbo, disabled_features)) return false; if (!CreateBuffers(buggy_pbo)) @@ -360,7 +361,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p return true; } -bool OpenGLDevice::CheckFeatures(bool* buggy_pbo) +bool OpenGLDevice::CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features) { const bool is_gles = m_gl_context->IsGLES(); @@ -427,16 +428,18 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo) GLint max_dual_source_draw_buffers = 0; glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers); m_features.dual_source_blend = - (max_dual_source_draw_buffers > 0) && + !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && (max_dual_source_draw_buffers > 0) && (GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended); - m_features.framebuffer_fetch = (GLAD_GL_EXT_shader_framebuffer_fetch || GLAD_GL_ARM_shader_framebuffer_fetch); + m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && + (GLAD_GL_EXT_shader_framebuffer_fetch || GLAD_GL_ARM_shader_framebuffer_fetch); #ifdef __APPLE__ // Partial texture buffer uploads appear to be broken in macOS's OpenGL driver. m_features.supports_texture_buffers = false; #else - m_features.supports_texture_buffers = (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2); + m_features.supports_texture_buffers = + !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS) && (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2); // And Samsung's ANGLE/GLES driver? if (std::strstr(reinterpret_cast(glGetString(GL_RENDERER)), "ANGLE")) @@ -493,7 +496,8 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo) // noperspective is not supported in GLSL ES. m_features.noperspective_interpolation = !is_gles; - m_features.geometry_shaders = GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2; + m_features.geometry_shaders = + !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && (GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2); m_features.gpu_timing = !(m_gl_context->IsGLES() && (!GLAD_GL_EXT_disjoint_timer_query || !glGetQueryObjectivEXT || !glGetQueryObjectui64vEXT)); diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index 66b267421..c584837f6 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -122,7 +122,7 @@ public: void UnbindPipeline(const OpenGLPipeline* pl); protected: - bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override; + bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override; @@ -138,7 +138,7 @@ private: static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024; static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; - bool CheckFeatures(bool* buggy_pbo); + bool CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features); bool CreateBuffers(bool buggy_pbo); void DestroyBuffers(); diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 29a131135..d987630f1 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -1601,7 +1601,8 @@ bool VulkanDevice::HasSurface() const return static_cast(m_swap_chain); } -bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation) +bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, + FeatureMask disabled_features) { std::unique_lock lock(s_instance_mutex); bool enable_debug_utils = m_debug_device; @@ -1704,7 +1705,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p if (!CreateDevice(surface, enable_validation_layer)) return false; - if (!CheckFeatures()) + if (!CheckFeatures(disabled_features)) { Host::ReportErrorAsync("Error", "Your GPU does not support the required Vulkan features."); return false; @@ -2163,7 +2164,7 @@ void VulkanDevice::InsertDebugMessage(const char* msg) #endif } -bool VulkanDevice::CheckFeatures() +bool VulkanDevice::CheckFeatures(FeatureMask disabled_features) { m_max_texture_size = m_device_properties.limits.maxImageDimension2D; @@ -2193,15 +2194,16 @@ bool VulkanDevice::CheckFeatures() else m_max_multisamples = 1; - m_features.dual_source_blend = m_device_features.dualSrcBlend; // TODO: Option to disable - m_features.framebuffer_fetch = false; // TODO: Option to disable + m_features.dual_source_blend = + !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend; + m_features.framebuffer_fetch = /*!(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && */false; if (!m_features.dual_source_blend) Log_WarningPrintf("Vulkan driver is missing dual-source blending. This will have an impact on performance."); m_features.noperspective_interpolation = true; m_features.per_sample_shading = m_device_features.sampleRateShading; - m_features.supports_texture_buffers = true; + m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS); #ifdef __APPLE__ // Partial texture buffer uploads appear to be broken in macOS/MoltenVK. @@ -2218,7 +2220,8 @@ bool VulkanDevice::CheckFeatures() if (m_features.texture_buffers_emulated_with_ssbo) Log_WarningPrintf("Emulating texture buffers with SSBOs."); - m_features.geometry_shaders = m_device_features.geometryShader; + m_features.geometry_shaders = + !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && m_device_features.geometryShader; m_features.partial_msaa_resolve = true; m_features.shader_cache = true; diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index 97331c85a..20b3d49cd 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -220,7 +220,8 @@ public: void UnbindTextureBuffer(VulkanTextureBuffer* buf); protected: - bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override; + bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, + FeatureMask disabled_features) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override; @@ -305,7 +306,7 @@ private: bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer); void ProcessDeviceExtensions(); - bool CheckFeatures(); + bool CheckFeatures(FeatureMask disabled_features); bool CreateAllocator(); void DestroyAllocator(); diff --git a/src/util/vulkan_pipeline.cpp b/src/util/vulkan_pipeline.cpp index e5ee2996a..744e1a824 100644 --- a/src/util/vulkan_pipeline.cpp +++ b/src/util/vulkan_pipeline.cpp @@ -139,8 +139,8 @@ std::unique_ptr VulkanDevice::CreatePipeline(const GPUPipeline::Gra VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, // InvSrcAlpha1 VK_BLEND_FACTOR_DST_ALPHA, // DstAlpha VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // InvDstAlpha - VK_BLEND_FACTOR_CONSTANT_ALPHA, // ConstantAlpha - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, // InvConstantAlpha + VK_BLEND_FACTOR_CONSTANT_COLOR, // ConstantAlpha + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, // InvConstantAlpha }}; static constexpr std::array(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{