From 2f1a7cbee1ffecdd25ebc206ceab55ef934b7256 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 16 Mar 2018 23:10:22 +1000 Subject: [PATCH] Implement "Skip" ubershader mode Skip ubershader mode works the same as hybrid ubershaders in that the shaders are compiled asynchronously. However, instead of using the ubershader to draw the object, it skips it entirely until the specialized shader is made available. This mode will likely result in broken effects where a game creates an EFB copy, and does not redraw it every frame. Therefore, it is not a recommended option, however, it may result in better performance on low-end systems. --- .../settings/SettingsFragmentPresenter.java | 10 +- .../dolphinemu/utils/SettingsFile.java | 3 +- .../app/src/main/res/values/arrays.xml | 12 ++- .../app/src/main/res/values/strings.xml | 5 +- Source/Core/Core/Analytics.cpp | 21 ++-- Source/Core/Core/Config/GraphicsSettings.cpp | 5 +- Source/Core/Core/Config/GraphicsSettings.h | 2 +- .../Core/ConfigLoaders/IsSettingSaveable.cpp | 5 +- Source/Core/DolphinQt2/CMakeLists.txt | 1 + .../Config/Graphics/EnhancementsWidget.cpp | 16 --- .../Config/Graphics/EnhancementsWidget.h | 1 - .../Config/Graphics/GeneralWidget.cpp | 59 +++++++++-- .../Config/Graphics/GeneralWidget.h | 3 + .../Config/Graphics/GraphicsRadio.cpp | 24 +++++ .../Config/Graphics/GraphicsRadio.h | 26 +++++ Source/Core/DolphinQt2/DolphinQt2.vcxproj | 3 + Source/Core/DolphinWX/VideoConfigDiag.cpp | 100 ++++++++++-------- Source/Core/DolphinWX/VideoConfigDiag.h | 46 ++++++-- .../VideoBackends/Vulkan/VertexManager.cpp | 19 ++-- Source/Core/VideoCommon/VertexManagerBase.cpp | 36 +++++-- Source/Core/VideoCommon/VideoConfig.cpp | 9 +- Source/Core/VideoCommon/VideoConfig.h | 13 +-- 22 files changed, 292 insertions(+), 127 deletions(-) create mode 100644 Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.cpp create mode 100644 Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.h diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java index 11ad71a9cf..3caeaa514b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java @@ -259,10 +259,14 @@ public final class SettingsFragmentPresenter { IntSetting videoBackend = new IntSetting(SettingsFile.KEY_VIDEO_BACKEND_INDEX, SettingsFile.SECTION_CORE, SettingsFile.SETTINGS_DOLPHIN, getVideoBackendValue()); Setting showFps = null; + Setting shaderCompilationMode = null; + Setting waitForShaders = null; if (!mSettings.get(SettingsFile.SETTINGS_GFX).isEmpty()) { showFps = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_SHOW_FPS); + shaderCompilationMode = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_SHADER_COMPILATION_MODE); + waitForShaders = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_WAIT_FOR_SHADERS); } else { @@ -276,6 +280,8 @@ public final class SettingsFragmentPresenter sl.add(new SingleChoiceSetting(SettingsFile.KEY_VIDEO_BACKEND_INDEX, SettingsFile.SECTION_CORE, SettingsFile.SETTINGS_DOLPHIN, R.string.video_backend, R.string.video_backend_descrip, R.array.videoBackendEntries, R.array.videoBackendValues, 0, videoBackend)); sl.add(new CheckBoxSetting(SettingsFile.KEY_SHOW_FPS, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.show_fps, 0, false, showFps)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_SHADER_COMPILATION_MODE, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.shader_compilation_mode, R.string.shader_compilation_mode_descrip, R.array.shaderCompilationModeEntries, R.array.shaderCompilationModeValues, 0, shaderCompilationMode)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_WAIT_FOR_SHADERS, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.wait_for_shaders, 0, false, waitForShaders)); sl.add(new SubmenuSetting(null, null, R.string.enhancements, 0, SettingsFile.SECTION_GFX_ENHANCEMENTS)); sl.add(new SubmenuSetting(null, null, R.string.hacks, 0, SettingsFile.SECTION_GFX_HACKS)); @@ -290,7 +296,8 @@ public final class SettingsFragmentPresenter Setting perPixel = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_PER_PIXEL); Setting forceFilter = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_ENHANCEMENTS).getSetting(SettingsFile.KEY_FORCE_FILTERING); Setting disableFog = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_DISABLE_FOG); - Setting uberShaderMode = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_UBERSHADER_MODE); + Setting shaderCompilationMode = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_SHADER_COMPILATION_MODE); + Setting waitForShaders = mSettings.get(SettingsFile.SETTINGS_GFX).get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_WAIT_FOR_SHADERS); sl.add(new SingleChoiceSetting(SettingsFile.KEY_INTERNAL_RES, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.internal_resolution, R.string.internal_resolution_descrip, R.array.internalResolutionEntries, R.array.internalResolutionValues, 0, resolution)); sl.add(new SingleChoiceSetting(SettingsFile.KEY_FSAA, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.FSAA, R.string.FSAA_descrip, R.array.FSAAEntries, R.array.FSAAValues, 0, fsaa)); @@ -304,7 +311,6 @@ public final class SettingsFragmentPresenter sl.add(new CheckBoxSetting(SettingsFile.KEY_PER_PIXEL, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.per_pixel_lighting, R.string.per_pixel_lighting_descrip, false, perPixel)); sl.add(new CheckBoxSetting(SettingsFile.KEY_FORCE_FILTERING, SettingsFile.SECTION_GFX_ENHANCEMENTS, SettingsFile.SETTINGS_GFX, R.string.force_texture_filtering, R.string.force_texture_filtering_descrip, false, forceFilter)); sl.add(new CheckBoxSetting(SettingsFile.KEY_DISABLE_FOG, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.disable_fog, R.string.disable_fog_descrip, false, disableFog)); - sl.add(new SingleChoiceSetting(SettingsFile.KEY_UBERSHADER_MODE, SettingsFile.SECTION_GFX_SETTINGS, SettingsFile.SETTINGS_GFX, R.string.ubershader_mode, R.string.ubershader_mode_descrip, R.array.uberShaderModeEntries, R.array.uberShaderModeValues, 0, uberShaderMode)); /* Check if we support stereo diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java index 3e5a1586a3..34d4e2fa71 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java @@ -107,7 +107,8 @@ public final class SettingsFile public static final String KEY_IMMEDIATE_XFB = "ImmediateXFBEnable"; public static final String KEY_FAST_DEPTH = "FastDepthCalc"; public static final String KEY_ASPECT_RATIO = "AspectRatio"; - public static final String KEY_UBERSHADER_MODE = "UberShaderMode"; + public static final String KEY_SHADER_COMPILATION_MODE = "ShaderCompilationMode"; + public static final String KEY_WAIT_FOR_SHADERS = "WaitForShadersBeforeStarting"; public static final String KEY_GCPAD_TYPE = "SIDevice"; diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index ce9c4a542c..c9d6f9a414 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -92,15 +92,17 @@ - - Disabled - Hybrid - Exclusive + + Synchronous + Synchronous (Ubershaders) + Asynchronous (Ubershaders) + Asynchronous (Skip Drawing) - + 0 1 2 + 3 diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index c975edad91..ea7edcfbcd 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -184,8 +184,9 @@ Uses a less accurate algorithm to calculate depth values. Aspect Ratio Select what aspect ratio to use when rendering - Ubershader Mode - Specifies when to use Ubershaders. Disabled - Never, Hybrid - Use ubershaders while compiling specialized shaders. Exclusive - Use only ubershaders, largest performance impact. + Shader Compilation Mode + Specifies when to use Ubershaders. Disabled - Never, Hybrid - Use ubershaders while compiling specialized shaders. Exclusive - Use only ubershaders, largest performance impact. Skip Drawing - Do not draw objects while shaders are compiling, will cause broken effects. + Compile Shaders Before Starting Yes diff --git a/Source/Core/Core/Analytics.cpp b/Source/Core/Core/Analytics.cpp index db881d61de..6c45c1e400 100644 --- a/Source/Core/Core/Analytics.cpp +++ b/Source/Core/Core/Analytics.cpp @@ -178,17 +178,19 @@ void DolphinAnalytics::MakeBaseBuilder() m_base_builder = builder; } -static const char* GetUbershaderMode(const VideoConfig& video_config) +static const char* GetShaderCompilationMode(const VideoConfig& video_config) { - switch (video_config.iUberShaderMode) + switch (video_config.iShaderCompilationMode) { - case UberShaderMode::Exclusive: - return "exclusive"; - case UberShaderMode::Hybrid: - return "hybrid"; - case UberShaderMode::Disabled: + case ShaderCompilationMode::AsynchronousUberShaders: + return "async-ubershaders"; + case ShaderCompilationMode::AsynchronousSkipRendering: + return "async-skip-rendering"; + case ShaderCompilationMode::SynchronousUberShaders: + return "sync-ubershaders"; + case ShaderCompilationMode::Synchronous: default: - return "disabled"; + return "sync"; } } @@ -234,7 +236,8 @@ void DolphinAnalytics::MakePerGameBuilder() builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples); builder.AddData("cfg-gfx-stereo-mode", static_cast(g_Config.stereo_mode)); builder.AddData("cfg-gfx-per-pixel-lighting", g_Config.bEnablePixelLighting); - builder.AddData("cfg-gfx-ubershader-mode", GetUbershaderMode(g_Config)); + builder.AddData("cfg-gfx-shader-compilation-mode", GetShaderCompilationMode(g_Config)); + builder.AddData("cfg-gfx-wait-for-shaders", g_Config.bWaitForShadersBeforeStarting); builder.AddData("cfg-gfx-fast-depth", g_Config.bFastDepthCalc); builder.AddData("cfg-gfx-vertex-rounding", g_Config.UseVertexRounding()); diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 10a70c6020..7412c81740 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -78,8 +78,9 @@ const ConfigInfo GFX_COMMAND_BUFFER_EXECUTE_INTERVAL{ const ConfigInfo GFX_SHADER_CACHE{{System::GFX, "Settings", "ShaderCache"}, true}; const ConfigInfo GFX_WAIT_FOR_SHADERS_BEFORE_STARTING{ {System::GFX, "Settings", "WaitForShadersBeforeStarting"}, false}; -const ConfigInfo GFX_UBERSHADER_MODE{{System::GFX, "Settings", "UberShaderMode"}, - static_cast(UberShaderMode::Disabled)}; +const ConfigInfo GFX_SHADER_COMPILATION_MODE{ + {System::GFX, "Settings", "ShaderCompilationMode"}, + static_cast(ShaderCompilationMode::Synchronous)}; const ConfigInfo GFX_SHADER_COMPILER_THREADS{ {System::GFX, "Settings", "ShaderCompilerThreads"}, 1}; const ConfigInfo GFX_SHADER_PRECOMPILER_THREADS{ diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 5c1684777b..999192c578 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -60,7 +60,7 @@ extern const ConfigInfo GFX_BACKEND_MULTITHREADING; extern const ConfigInfo GFX_COMMAND_BUFFER_EXECUTE_INTERVAL; extern const ConfigInfo GFX_SHADER_CACHE; extern const ConfigInfo GFX_WAIT_FOR_SHADERS_BEFORE_STARTING; -extern const ConfigInfo GFX_UBERSHADER_MODE; +extern const ConfigInfo GFX_SHADER_COMPILATION_MODE; extern const ConfigInfo GFX_SHADER_COMPILER_THREADS; extern const ConfigInfo GFX_SHADER_PRECOMPILER_THREADS; diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index ef71c085ab..d9e210deaa 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -46,8 +46,9 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location) Config::GFX_DISABLE_FOG.location, Config::GFX_BORDERLESS_FULLSCREEN.location, Config::GFX_ENABLE_VALIDATION_LAYER.location, Config::GFX_BACKEND_MULTITHREADING.location, Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL.location, Config::GFX_SHADER_CACHE.location, - Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING.location, Config::GFX_UBERSHADER_MODE.location, - Config::GFX_SHADER_COMPILER_THREADS.location, Config::GFX_SHADER_PRECOMPILER_THREADS.location, + Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING.location, + Config::GFX_SHADER_COMPILATION_MODE.location, Config::GFX_SHADER_COMPILER_THREADS.location, + Config::GFX_SHADER_PRECOMPILER_THREADS.location, Config::GFX_SW_ZCOMPLOC.location, Config::GFX_SW_ZFREEZE.location, Config::GFX_SW_DUMP_OBJECTS.location, Config::GFX_SW_DUMP_TEV_STAGES.location, diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt index 52af9c951d..d00bc5ee1a 100644 --- a/Source/Core/DolphinQt2/CMakeLists.txt +++ b/Source/Core/DolphinQt2/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRCS Config/Graphics/HacksWidget.cpp Config/Graphics/GraphicsBool.cpp Config/Graphics/GraphicsChoice.cpp + Config/Graphics/GraphicsRadio.cpp Config/Graphics/GraphicsSlider.cpp Config/Graphics/GraphicsWidget.cpp Config/Graphics/GraphicsWindow.cpp diff --git a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp index b6baa9819f..06f611f5d1 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp @@ -63,9 +63,6 @@ void EnhancementsWidget::CreateWidgets() m_af_combo = new GraphicsChoice({tr("1x"), tr("2x"), tr("4x"), tr("8x"), tr("16x")}, Config::GFX_ENHANCE_MAX_ANISOTROPY); - m_ubershader_combo = new GraphicsChoice({tr("Disabled"), tr("Hybrid"), tr("Exclusive")}, - Config::GFX_UBERSHADER_MODE); - m_pp_effect = new QComboBox(); m_configure_pp_effect = new QPushButton(tr("Configure")); m_scaled_efb_copy = new GraphicsBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED); @@ -85,9 +82,6 @@ void EnhancementsWidget::CreateWidgets() enhancements_layout->addWidget(new QLabel(tr("Anisotropic Filtering:")), 2, 0); enhancements_layout->addWidget(m_af_combo, 2, 1, 1, -1); - enhancements_layout->addWidget(new QLabel(tr("Ubershaders:")), 3, 0); - enhancements_layout->addWidget(m_ubershader_combo, 3, 1, 1, -1); - enhancements_layout->addWidget(new QLabel(tr("Post-Processing Effect:")), 4, 0); enhancements_layout->addWidget(m_pp_effect, 4, 1); enhancements_layout->addWidget(m_configure_pp_effect, 4, 2); @@ -243,15 +237,6 @@ void EnhancementsWidget::AddDescriptions() "Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique " "viewing angles.\nMight cause issues in a small number of games.\n\nIf unsure, select 1x."); - static const char* TR_UBERSHADER_DESCRIPTION = - QT_TR_NOOP("Disabled: Ubershaders are never used. Stuttering will occur during shader " - "compilation, but GPU demands are low. Recommended for low-end hardware.\n\n" - "Hybrid: Ubershaders will be used to prevent stuttering during shader " - "compilation, but traditional shaders will be used when they will not cause " - "stuttering. Balances performance and smoothness.\n\n" - "Exclusive: Ubershaders will always be used. Only recommended for high-end " - "systems."); - static const char* TR_POSTPROCESSING_DESCRIPTION = QT_TR_NOOP( "Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off)."); @@ -303,7 +288,6 @@ void EnhancementsWidget::AddDescriptions() AddDescription(m_ir_combo, TR_INTERNAL_RESOLUTION_DESCRIPTION); AddDescription(m_aa_combo, TR_ANTIALIAS_DESCRIPTION); AddDescription(m_af_combo, TR_ANISOTROPIC_FILTERING_DESCRIPTION); - AddDescription(m_ubershader_combo, TR_UBERSHADER_DESCRIPTION); AddDescription(m_pp_effect, TR_POSTPROCESSING_DESCRIPTION); AddDescription(m_scaled_efb_copy, TR_SCALED_EFB_COPY_DESCRIPTION); AddDescription(m_per_pixel_lighting, TR_PER_PIXEL_LIGHTING_DESCRIPTION); diff --git a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.h b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.h index fd5b20a1b4..ac23ed84e9 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.h +++ b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.h @@ -30,7 +30,6 @@ private: QComboBox* m_ir_combo; QComboBox* m_aa_combo; QComboBox* m_af_combo; - QComboBox* m_ubershader_combo; QComboBox* m_pp_effect; QPushButton* m_configure_pp_effect; QCheckBox* m_scaled_efb_copy; diff --git a/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.cpp index 21281488b8..1542ae535a 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "Core/Config/GraphicsSettings.h" @@ -18,6 +19,7 @@ #include "Core/Core.h" #include "DolphinQt2/Config/Graphics/GraphicsBool.h" #include "DolphinQt2/Config/Graphics/GraphicsChoice.h" +#include "DolphinQt2/Config/Graphics/GraphicsRadio.h" #include "DolphinQt2/Config/Graphics/GraphicsWindow.h" #include "DolphinQt2/Settings.h" #include "UICommon/VideoUtils.h" @@ -87,8 +89,6 @@ void GeneralWidget::CreateWidgets() m_keep_window_top = new QCheckBox(tr("Keep Window on Top")); m_hide_cursor = new QCheckBox(tr("Hide Mouse Cursor")); m_render_main_window = new QCheckBox(tr("Render to Main Window")); - m_wait_for_shaders = new GraphicsBool(tr("Immediately Compile Shaders"), - Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING); m_options_box->setLayout(m_options_layout); @@ -103,10 +103,30 @@ void GeneralWidget::CreateWidgets() m_options_layout->addWidget(m_hide_cursor, 3, 0); m_options_layout->addWidget(m_render_main_window, 3, 1); - m_options_layout->addWidget(m_wait_for_shaders, 4, 0); + + // Other + auto* shader_compilation_box = new QGroupBox(tr("Shader Compilation")); + auto* shader_compilation_layout = new QGridLayout(); + + const std::array modes = {{ + "Synchronous", "Synchronous (Ubershaders)", "Asynchronous (Ubershaders)", + "Asynchronous (Skip Drawing)", + }}; + for (size_t i = 0; i < modes.size(); i++) + { + m_shader_compilation_mode[i] = new GraphicsRadioInt( + tr(modes[i]), Config::GFX_SHADER_COMPILATION_MODE, static_cast(i)); + shader_compilation_layout->addWidget(m_shader_compilation_mode[i], static_cast(i / 2), + static_cast(i % 2)); + } + m_wait_for_shaders = new GraphicsBool(tr("Compile Shaders Before Starting"), + Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING); + shader_compilation_layout->addWidget(m_wait_for_shaders); + shader_compilation_box->setLayout(shader_compilation_layout); main_layout->addWidget(m_video_box); main_layout->addWidget(m_options_box); + main_layout->addWidget(shader_compilation_box); main_layout->addStretch(); setLayout(main_layout); @@ -268,12 +288,27 @@ void GeneralWidget::AddDescriptions() static const char* TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION = QT_TR_NOOP("When playing on NetPlay, show chat messages, buffer changes and " "desync alerts.\n\nIf unsure, leave this unchecked."); - static const char* TR_WAIT_FOR_SHADERS_DESCRIPTION = QT_TR_NOOP( - "Waits for all shaders to finish compiling before starting a game. Enabling this " - "option may reduce stuttering or hitching for a short time after the game is " - "started, at the cost of a longer delay before the game starts.\n\nFor systems " - "with two or fewer cores, it is recommended to enable this option, as a large " - "shader queue may reduce frame rates. Otherwise, if unsure, leave this unchecked."); + static const char* TR_SHADER_COMPILE_SYNC_DESCRIPTION = + QT_TR_NOOP("Ubershaders are never used. Stuttering will occur during shader " + "compilation, but GPU demands are low. Recommended for low-end hardware.\n\nIf " + "unsure, select this mode."); + static const char* TR_SHADER_COMPILE_UBER_ONLY_DESCRIPTION = + QT_TR_NOOP("Ubershaders will always be used. Provides a near stutter-free experience at the " + "cost of high GPU requirements. Only recommended for high-end systems."); + static const char* TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION = + QT_TR_NOOP("Ubershaders will be used to prevent stuttering during shader compilation, but " + "specialized shaders will be used when they will not cause stuttering."); + static const char* TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION = + QT_TR_NOOP("Instead of using ubershaders during shader compilation, objects which use these " + "shaders will be not be rendered. This can further reduce stuttering and " + "performance requirements, compared to ubershaders, at the cost of introducing " + "visual glitches and broken effects. Not recommended."); + static const char* TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION = + QT_TR_NOOP("Waits for all shaders to finish compiling before starting a game. Enabling this " + "option may reduce stuttering or hitching for a short time after the game is " + "started, at the cost of a longer delay before the game starts. For systems with " + "two or fewer cores, it is recommended to enable this option, as a large shader " + "queue may reduce frame rates. Otherwise, if unsure, leave this unchecked."); AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION); #ifdef _WIN32 @@ -291,7 +326,11 @@ void GeneralWidget::AddDescriptions() AddDescription(m_show_messages, TR_SHOW_FPS_DESCRIPTION); AddDescription(m_keep_window_top, TR_KEEP_WINDOW_ON_TOP_DESCRIPTION); AddDescription(m_show_messages, TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION); - AddDescription(m_wait_for_shaders, TR_WAIT_FOR_SHADERS_DESCRIPTION); + AddDescription(m_shader_compilation_mode[0], TR_SHADER_COMPILE_SYNC_DESCRIPTION); + AddDescription(m_shader_compilation_mode[1], TR_SHADER_COMPILE_UBER_ONLY_DESCRIPTION); + AddDescription(m_shader_compilation_mode[2], TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION); + AddDescription(m_shader_compilation_mode[3], TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION); + AddDescription(m_wait_for_shaders, TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION); } void GeneralWidget::OnBackendChanged(const QString& backend_name) { diff --git a/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.h b/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.h index 8b2d22f331..b8dd799649 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.h +++ b/Source/Core/DolphinQt2/Config/Graphics/GeneralWidget.h @@ -4,11 +4,13 @@ #pragma once +#include #include "DolphinQt2/Config/Graphics/GraphicsWidget.h" class GraphicsWindow; class QCheckBox; class QComboBox; +class QRadioButton; class QGridLayout; namespace X11Utils @@ -52,6 +54,7 @@ private: QCheckBox* m_keep_window_top; QCheckBox* m_hide_cursor; QCheckBox* m_render_main_window; + std::array m_shader_compilation_mode{}; QCheckBox* m_wait_for_shaders; X11Utils::XRRConfiguration* m_xrr_config; diff --git a/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.cpp b/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.cpp new file mode 100644 index 0000000000..c8f87a548b --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.cpp @@ -0,0 +1,24 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Config/Graphics/GraphicsRadio.h" + +#include "Common/Config/Config.h" +#include "DolphinQt2/Settings.h" + +GraphicsRadioInt::GraphicsRadioInt(const QString& label, const Config::ConfigInfo& setting, + int value) + : QRadioButton(label), m_setting(setting), m_value(value) +{ + setChecked(Config::Get(m_setting) == m_value); + connect(this, &QRadioButton::toggled, this, &GraphicsRadioInt::Update); +} + +void GraphicsRadioInt::Update() +{ + if (!isChecked()) + return; + + Config::SetBaseOrCurrent(m_setting, m_value); +} diff --git a/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.h b/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.h new file mode 100644 index 0000000000..dde18704ee --- /dev/null +++ b/Source/Core/DolphinQt2/Config/Graphics/GraphicsRadio.h @@ -0,0 +1,26 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace Config +{ +template +struct ConfigInfo; +} + +class GraphicsRadioInt : public QRadioButton +{ + Q_OBJECT +public: + GraphicsRadioInt(const QString& label, const Config::ConfigInfo& setting, int value); + +private: + void Update(); + + const Config::ConfigInfo& m_setting; + int m_value; +}; diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj index 3fe5e2613d..a87fa822cd 100644 --- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj +++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj @@ -79,6 +79,7 @@ + @@ -161,6 +162,7 @@ + @@ -212,6 +214,7 @@ + diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index cdebfd27e9..ec6a434b8b 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -44,7 +44,6 @@ // template instantiation template class BoolSetting; -template class BoolSetting; template <> SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, @@ -59,19 +58,6 @@ SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, const wxSt Bind(wxEVT_CHECKBOX, &SettingCheckBox::UpdateValue, this); } -template <> -SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, - const Config::ConfigInfo& setting, bool reverse, long style) - : wxRadioButton(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), - m_setting(setting), m_reverse(reverse) -{ - SetToolTip(tooltip); - SetValue(Config::Get(m_setting) ^ m_reverse); - if (Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base) - SetFont(GetFont().MakeBold()); - Bind(wxEVT_RADIOBUTTON, &SettingRadioButton::UpdateValue, this); -} - template <> RefBoolSetting::RefBoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, bool& setting, bool reverse, @@ -311,18 +297,35 @@ static wxString gpu_texture_decoding_desc = "bottleneck.\n\nIf unsure, leave this unchecked."); static wxString ubershader_desc = wxTRANSLATE("Disabled: Ubershaders are never used. Stuttering will occur during shader " - "compilation, but GPU demands are low. Recommended for low-end hardware.\n\n" + "compilation, but GPU demands are low. Recommended for low-end hardware.\n" "Hybrid: Ubershaders will be used to prevent stuttering during shader " "compilation, but traditional shaders will be used when they will not cause " - "stuttering. Balances performance and smoothness.\n\n" + "stuttering. Balances performance and smoothness.\n" "Exclusive: Ubershaders will always be used. Only recommended for high-end " - "systems."); -static wxString wait_for_shaders_desc = + "systems.\n" + "Skip Drawing: Does not draw objects during shader compilation. Reduces " + "stuttering at the cost of missing objects, or broken effects."); +static wxString shader_compile_sync_desc = + wxTRANSLATE("Ubershaders are never used. Stuttering will occur during shader " + "compilation, but GPU demands are low. Recommended for low-end hardware.\n\nIf " + "unsure, select this mode."); +static wxString shader_compile_uber_only_desc = + wxTRANSLATE("Ubershaders will always be used. Provides a near stutter-free experience at the " + "cost of high GPU requirements. Only recommended for high-end systems."); +static wxString shader_compile_async_uber_desc = + wxTRANSLATE("Ubershaders will be used to prevent stuttering during shader compilation, but " + "specialized shaders will be used when they will not cause stuttering."); +static wxString shader_compile_async_skip_desc = + wxTRANSLATE("Instead of using ubershaders during shader compilation, objects which use these " + "shaders will be not be rendered. This can further reduce stuttering and " + "performance requirements, compared to ubershaders, at the cost of introducing " + "visual glitches and broken effects. Not recommended."); +static wxString shader_compile_before_start_desc = wxTRANSLATE("Waits for all shaders to finish compiling before starting a game. Enabling this " "option may reduce stuttering or hitching for a short time after the game is " - "started, at the cost of a longer delay before the game starts.\n\nFor systems " - "with two or fewer cores, it is recommended to enable this option, as a large " - "shader queue may reduce frame rates. Otherwise, if unsure, leave this unchecked."); + "started, at the cost of a longer delay before the game starts. For systems with " + "two or fewer cores, it is recommended to enable this option, as a large shader " + "queue may reduce frame rates. Otherwise, if unsure, leave this unchecked."); VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) : wxDialog(parent, wxID_ANY, wxString::Format(_("Dolphin %s Graphics Configuration"), @@ -448,10 +451,29 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) wxGetTranslation(backend_multithreading_desc), Config::GFX_BACKEND_MULTITHREADING)); } + } - szr_other->Add(CreateCheckBox(page_general, _("Immediately Compile Shaders"), - wxGetTranslation(wait_for_shaders_desc), - Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING)); + // - shader compilation + wxGridBagSizer* const szr_shader_compilation = new wxGridBagSizer(space5, space5); + { + const std::array, 4> modes = { + {{_("Synchronous"), wxGetTranslation(shader_compile_sync_desc)}, + {_("Synchronous (Ubershaders)"), wxGetTranslation(shader_compile_uber_only_desc)}, + {_("Asynchronous (Ubershaders)"), wxGetTranslation(shader_compile_async_uber_desc)}, + {_("Asynchronous (Skip Drawing)"), wxGetTranslation(shader_compile_async_skip_desc)}}}; + for (size_t i = 0; i < modes.size(); i++) + { + szr_shader_compilation->Add( + CreateRadioButton(page_general, modes[i].first, modes[i].second, + Config::GFX_SHADER_COMPILATION_MODE, static_cast(i)), + wxGBPosition(static_cast(i / 2), static_cast(i % 2)), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL); + } + szr_shader_compilation->Add( + CreateCheckBox(page_general, _("Compile Shaders Before Starting"), + wxGetTranslation(shader_compile_before_start_desc), + Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING), + wxGBPosition(2, 0), wxGBSpan(1, 2)); } wxStaticBoxSizer* const group_basic = @@ -469,12 +491,19 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT, space5); group_other->AddSpacer(space5); + wxStaticBoxSizer* const group_shader_compilation = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Shader Compilation")); + group_shader_compilation->Add(szr_shader_compilation, 1, wxEXPAND | wxLEFT | wxRIGHT, space5); + group_shader_compilation->AddSpacer(space5); + szr_general->AddSpacer(space5); szr_general->Add(group_basic, 0, wxEXPAND | wxLEFT | wxRIGHT, space5); szr_general->AddSpacer(space5); szr_general->Add(group_display, 0, wxEXPAND | wxLEFT | wxRIGHT, space5); szr_general->AddSpacer(space5); szr_general->Add(group_other, 0, wxEXPAND | wxLEFT | wxRIGHT, space5); + szr_general->AddSpacer(space5); + szr_general->Add(group_shader_compilation, 0, wxEXPAND | wxLEFT | wxRIGHT, space5); } szr_general->AddSpacer(space5); @@ -541,18 +570,6 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) row += 1; } - // ubershaders - { - const std::array mode_choices = {{_("Disabled"), _("Hybrid"), _("Exclusive")}}; - szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Ubershaders:")), wxGBPosition(row, 0), - wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - szr_enh->Add(CreateChoice(page_enh, Config::GFX_UBERSHADER_MODE, - wxGetTranslation(ubershader_desc), mode_choices.size(), - mode_choices.data()), - wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL); - row += 1; - } - // postproc shader if (vconfig.backend_info.bSupportsPostProcessing) { @@ -1111,17 +1128,6 @@ SettingChoice* VideoConfigDiag::CreateChoice(wxWindow* parent, return ch; } -SettingRadioButton* VideoConfigDiag::CreateRadioButton(wxWindow* parent, const wxString& label, - const wxString& description, - const Config::ConfigInfo& setting, - bool reverse, long style) -{ - SettingRadioButton* const rb = - new SettingRadioButton(parent, label, wxString(), setting, reverse, style); - RegisterControl(rb, description); - return rb; -} - /* Use this to register descriptions for controls which have NOT been created using the Create* * functions from above */ wxControl* VideoConfigDiag::RegisterControl(wxControl* const control, const wxString& description) diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index a15472885a..af3cccc4cb 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -64,7 +64,6 @@ private: }; typedef BoolSetting SettingCheckBox; -typedef BoolSetting SettingRadioButton; class IntegerSetting : public wxSpinCtrl { @@ -93,6 +92,33 @@ private: Config::ConfigInfo m_setting; }; +template +class SettingRadioButton : public wxRadioButton +{ +public: + SettingRadioButton(wxWindow* parent, const wxString& label, const wxString& tooltip, + const Config::ConfigInfo& setting, const ValueType& value, + long style = 0) + : wxRadioButton(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), + m_setting(setting), m_value(value) + { + SetToolTip(tooltip); + SetValue(Config::Get(m_setting) == m_value); + Bind(wxEVT_RADIOBUTTON, &SettingRadioButton::UpdateValue, this); + } + + void UpdateValue(wxCommandEvent& ev) + { + if (ev.IsChecked()) + Config::SetBaseOrCurrent(m_setting, m_value); + ev.Skip(); + } + +private: + Config::ConfigInfo m_setting; + ValueType m_value; +}; + class VideoConfigDiag : public wxDialog { public: @@ -125,10 +151,17 @@ protected: SettingChoice* CreateChoice(wxWindow* parent, const Config::ConfigInfo& setting, const wxString& description, int num = 0, const wxString choices[] = nullptr, long style = 0); - SettingRadioButton* CreateRadioButton(wxWindow* parent, const wxString& label, - const wxString& description, - const Config::ConfigInfo& setting, - bool reverse = false, long style = 0); + template + SettingRadioButton* CreateRadioButton(wxWindow* parent, const wxString& label, + const wxString& description, + const Config::ConfigInfo& setting, + const ValueType& value, long style = 0) + { + auto* const rb = + new SettingRadioButton(parent, label, wxString(), setting, value, style); + RegisterControl(rb, description); + return rb; + } // Same as above but only connects enter/leave window events wxControl* RegisterControl(wxControl* const control, const wxString& description); @@ -157,9 +190,6 @@ protected: SettingCheckBox* borderless_fullscreen; RefBoolSetting* render_to_main_checkbox; - SettingRadioButton* virtual_xfb; - SettingRadioButton* real_xfb; - SettingCheckBox* cache_hires_textures; wxCheckBox* progressive_scan_checkbox; diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index 1e97cf6308..ea9b27351b 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp @@ -166,16 +166,19 @@ void VertexManager::vFlush() } // Bind all pending state to the command buffer - g_renderer->SetPipeline(m_current_pipeline_object); - if (!StateTracker::GetInstance()->Bind()) + if (m_current_pipeline_object) { - WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count); - return; - } + g_renderer->SetPipeline(m_current_pipeline_object); + if (!StateTracker::GetInstance()->Bind()) + { + WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count); + return; + } - // Execute the draw - vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), index_count, 1, - m_current_draw_base_index, m_current_draw_base_vertex, 0); + // Execute the draw + vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), index_count, 1, + m_current_draw_base_index, m_current_draw_base_vertex, 0); + } StateTracker::GetInstance()->OnDraw(); } diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index b54b8060b9..8364b039c5 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -566,13 +566,25 @@ void VertexManagerBase::UpdatePipelineObject() m_current_pipeline_object = nullptr; m_pipeline_config_changed = false; - if (g_ActiveConfig.iUberShaderMode == UberShaderMode::Disabled) + switch (g_ActiveConfig.iShaderCompilationMode) + { + case ShaderCompilationMode::Synchronous: { // Ubershaders disabled? Block and compile the specialized shader. m_current_pipeline_object = g_shader_cache->GetPipelineForUid(m_current_pipeline_config); - return; } - else if (g_ActiveConfig.iUberShaderMode == UberShaderMode::Hybrid) + break; + + case ShaderCompilationMode::SynchronousUberShaders: + { + // Exclusive ubershader mode, always use ubershaders. + m_current_pipeline_object = + g_shader_cache->GetUberPipelineForUid(m_current_uber_pipeline_config); + } + break; + + case ShaderCompilationMode::AsynchronousUberShaders: + case ShaderCompilationMode::AsynchronousSkipRendering: { // Can we background compile shaders? If so, get the pipeline asynchronously. auto res = g_shader_cache->GetPipelineForUidAsync(m_current_pipeline_config); @@ -582,8 +594,20 @@ void VertexManagerBase::UpdatePipelineObject() m_current_pipeline_object = *res; return; } - } - // Exclusive ubershader mode, or hybrid and shaders are still compiling. - m_current_pipeline_object = g_shader_cache->GetUberPipelineForUid(m_current_uber_pipeline_config); + if (g_ActiveConfig.iShaderCompilationMode == ShaderCompilationMode::AsynchronousUberShaders) + { + // Specialized shaders not ready, use the ubershaders. + m_current_pipeline_object = + g_shader_cache->GetUberPipelineForUid(m_current_uber_pipeline_config); + } + else + { + // Ensure we try again next draw. Otherwise, if no registers change between frames, the + // object will never be drawn, even when the shader is ready. + m_pipeline_config_changed = true; + } + } + break; + } } diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 55abd69e75..9c90c009a0 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -103,7 +103,8 @@ void VideoConfig::Refresh() iCommandBufferExecuteInterval = Config::Get(Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL); bShaderCache = Config::Get(Config::GFX_SHADER_CACHE); bWaitForShadersBeforeStarting = Config::Get(Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING); - iUberShaderMode = static_cast(Config::Get(Config::GFX_UBERSHADER_MODE)); + iShaderCompilationMode = + static_cast(Config::Get(Config::GFX_SHADER_COMPILATION_MODE)); iShaderCompilerThreads = Config::Get(Config::GFX_SHADER_COMPILER_THREADS); iShaderPrecompilerThreads = Config::Get(Config::GFX_SHADER_PRECOMPILER_THREADS); @@ -178,6 +179,12 @@ bool VideoConfig::IsVSync() const return bVSync && !Core::GetIsThrottlerTempDisabled(); } +bool VideoConfig::UsingUberShaders() const +{ + return iShaderCompilationMode == ShaderCompilationMode::SynchronousUberShaders || + iShaderCompilationMode == ShaderCompilationMode::AsynchronousUberShaders; +} + static u32 GetNumAutoShaderCompilerThreads() { // Automatic number. We use clamp(cpus - 3, 1, 4). diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index c8bded371b..8e22765695 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -42,11 +42,12 @@ enum class StereoMode : int Nvidia3DVision }; -enum class UberShaderMode : int +enum class ShaderCompilationMode : int { - Disabled, - Hybrid, - Exclusive + Synchronous, + SynchronousUberShaders, + AsynchronousUberShaders, + AsynchronousSkipRendering }; struct ProjectionHackConfig final @@ -170,7 +171,7 @@ struct VideoConfig final // Shader compilation settings. bool bWaitForShadersBeforeStarting; - UberShaderMode iUberShaderMode; + ShaderCompilationMode iShaderCompilationMode; // Number of shader compiler threads. // 0 disables background compilation. @@ -238,7 +239,7 @@ struct VideoConfig final return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding; } bool UseVertexRounding() const { return bVertexRounding && iEFBScale != 1; } - bool UsingUberShaders() const { return iUberShaderMode != UberShaderMode::Disabled; } + bool UsingUberShaders() const; u32 GetShaderCompilerThreads() const; u32 GetShaderPrecompilerThreads() const; };