diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index d72fb963cf..7a76859903 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -69,7 +69,9 @@ void GLGSRender::on_init_thread() // This allows context sharing to work (both GLRCs passed to wglShareLists have to be idle or you get ERROR_BUSY) m_context = m_frame->make_context(); - if (!g_cfg.video.disable_asynchronous_shader_compiler) + const auto shadermode = g_cfg.video.shadermode.get(); + + if (shadermode == shader_mode::async_recompiler || shadermode == shader_mode::async_with_interpreter) { m_decompiler_context = m_frame->make_context(); } @@ -222,7 +224,7 @@ void GLGSRender::on_init_thread() m_texture_parameters_buffer->create(gl::buffer::target::uniform, 16 * 0x100000); m_vertex_layout_buffer->create(gl::buffer::target::uniform, 16 * 0x100000); - if (g_cfg.video.interpreter_mode != shader_interpreter_mode::disabled) + if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only) { m_vertex_instructions_buffer->create(gl::buffer::target::ssbo, 16 * 0x100000); m_fragment_instructions_buffer->create(gl::buffer::target::ssbo, 16 * 0x100000); @@ -610,7 +612,8 @@ void GLGSRender::clear_surface(u32 arg) bool GLGSRender::load_program() { - const auto interpreter_mode = g_cfg.video.interpreter_mode.get(); + const auto shadermode = g_cfg.video.shadermode.get(); + if (m_interpreter_state = (m_graphics_state & rsx::pipeline_state::invalidate_pipeline_bits)) { get_current_fragment_program(fs_sampler_state); @@ -628,7 +631,7 @@ bool GLGSRender::load_program() return true; } - if (interpreter_mode == shader_interpreter_mode::forced) + if (shadermode == shader_mode::interpreter_only) { m_program = m_shader_interpreter.get(current_fp_metadata); return true; @@ -636,11 +639,11 @@ bool GLGSRender::load_program() } const bool was_interpreter = m_shader_interpreter.is_interpreter(m_program); - if (interpreter_mode != shader_interpreter_mode::forced) [[likely]] + if (shadermode != shader_mode::interpreter_only) [[likely]] { void* pipeline_properties = nullptr; m_program = m_prog_buffer.get_graphics_pipeline(current_vertex_program, current_fragment_program, pipeline_properties, - !g_cfg.video.disable_asynchronous_shader_compiler, true).get(); + shadermode != shader_mode::recompiler, true).get(); if (m_prog_buffer.check_cache_missed()) { @@ -673,7 +676,7 @@ bool GLGSRender::load_program() m_program = nullptr; } - if (!m_program && interpreter_mode != shader_interpreter_mode::disabled) + if (!m_program && (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)) { // Fall back to interpreter m_program = m_shader_interpreter.get(current_fp_metadata); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 4b79d50679..17ebc9dfb5 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -561,7 +561,9 @@ namespace rsx g_fxo->init("RSX Decompiler Thread", [this] { - if (g_cfg.video.disable_asynchronous_shader_compiler) + const auto shadermode = g_cfg.video.shadermode.get(); + + if (shadermode != shader_mode::async_recompiler && shadermode != shader_mode::async_with_interpreter) { // Die return; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 0f2a3f0427..f9298e2806 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -465,7 +465,9 @@ VKGSRender::VKGSRender() : GSRender() m_index_buffer_ring_info.create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_INDEX_RING_BUFFER_SIZE_M * 0x100000, "index buffer"); m_texture_upload_buffer_ring_info.create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_TEXTURE_UPLOAD_RING_BUFFER_SIZE_M * 0x100000, "texture upload buffer", 32 * 0x100000); - if (g_cfg.video.interpreter_mode != shader_interpreter_mode::disabled) + const auto shadermode = g_cfg.video.shadermode.get(); + + if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only) { m_vertex_instructions_buffer.create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 64 * 0x100000, "vertex instructions buffer", 512 * 16); m_fragment_instructions_buffer.create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 64 * 0x100000, "fragment instructions buffer", 2048); @@ -550,7 +552,7 @@ VKGSRender::VKGSRender() : GSRender() m_occlusion_query_pool.initialize(*m_current_command_buffer); - if (g_cfg.video.interpreter_mode != shader_interpreter_mode::disabled) + if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only) { m_shader_interpreter.init(*m_device); } @@ -1583,15 +1585,17 @@ bool VKGSRender::load_program() } } - if (g_cfg.video.interpreter_mode != shader_interpreter_mode::forced) [[likely]] + const auto shadermode = g_cfg.video.shadermode.get(); + + if (shadermode != shader_mode::interpreter_only) [[likely]] { vk::enter_uninterruptible(); - //Load current program from buffer + // Load current program from buffer vertex_program.skip_vertex_input_check = true; fragment_program.unnormalized_coords = 0; m_program = m_prog_buffer->get_graphics_pipeline(vertex_program, fragment_program, properties, - !g_cfg.video.disable_asynchronous_shader_compiler, true, *m_device, pipeline_layout).get(); + shadermode != shader_mode::recompiler, true, *m_device, pipeline_layout).get(); vk::leave_uninterruptible(); @@ -1621,7 +1625,7 @@ bool VKGSRender::load_program() m_program = nullptr; } - if (!m_program && g_cfg.video.interpreter_mode != shader_interpreter_mode::disabled) + if (!m_program && (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)) { if (!m_shader_interpreter.is_interpreter(old_program)) { diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 8ccb152f23..0da357e677 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -217,7 +217,9 @@ void VKGSRender::frame_context_cleanup(vk::frame_context_t *ctx, bool free_resou ctx->buffer_views_to_clean.clear(); - if (g_cfg.video.interpreter_mode != shader_interpreter_mode::disabled) + const auto shadermode = g_cfg.video.shadermode.get(); + + if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only) { // TODO: This is jank AF m_vertex_instructions_buffer.reset_allocation_stats(); diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index fd29d70c28..f424c9f53a 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -101,7 +101,7 @@ struct cfg_root : cfg::node cfg::_enum aspect_ratio{ this, "Aspect ratio", video_aspect::_16_9 }; cfg::_enum frame_limit{ this, "Frame limit", frame_limit_type::none, true }; cfg::_enum antialiasing_level{ this, "MSAA", msaa_level::_auto }; - cfg::_enum interpreter_mode{ this, "Shader interpreter mode", shader_interpreter_mode::disabled }; + cfg::_enum shadermode{ this, "Shader Mode", shader_mode::async_recompiler }; cfg::_bool write_color_buffers{ this, "Write Color Buffers" }; cfg::_bool write_depth_buffer{ this, "Write Depth Buffer" }; @@ -124,7 +124,6 @@ struct cfg_root : cfg::node cfg::_bool disable_on_disk_shader_cache{ this, "Disable On-Disk Shader Cache", false }; cfg::_bool disable_vulkan_mem_allocator{ this, "Disable Vulkan Memory Allocator", false }; cfg::_bool full_rgb_range_output{ this, "Use full RGB output range", true, true }; // Video out dynamic range - cfg::_bool disable_asynchronous_shader_compiler{ this, "Disable Asynchronous Shader Compiler", false }; cfg::_bool strict_texture_flushing{ this, "Strict Texture Flushing", false }; cfg::_bool disable_native_float16{ this, "Disable native float16 support", false }; cfg::_bool multithreaded_rsx{ this, "Multithreaded RSX", false }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index e5a4c787eb..489e411589 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -389,15 +389,16 @@ void fmt_class_string::format(std::string& out, u64 arg) } template <> -void fmt_class_string::format(std::string& out, u64 arg) +void fmt_class_string::format(std::string& out, u64 arg) { - format_enum(out, arg, [](shader_interpreter_mode value) + format_enum(out, arg, [](shader_mode value) { switch (value) { - case shader_interpreter_mode::disabled: return "Disabled"; - case shader_interpreter_mode::enabled: return "Enabled"; - case shader_interpreter_mode::forced: return "Forced"; + case shader_mode::recompiler: return "Shader Recompiler"; + case shader_mode::async_recompiler: return "Async Shader Recompiler"; + case shader_mode::async_with_interpreter: return "Async with Shader Interpreter"; + case shader_mode::interpreter_only: return "Shader Interpreter only"; } return unknown; diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index 7f6c03f0ad..cdeb4ff222 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -180,9 +180,10 @@ enum np_psn_status fake, }; -enum class shader_interpreter_mode +enum class shader_mode { - disabled, - enabled, - forced + recompiler, + async_recompiler, + async_with_interpreter, + interpreter_only }; diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index e95611f7b9..530494ee85 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -529,6 +529,15 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case video_renderer::vulkan: return tr("Vulkan", "Video renderer"); } break; + case emu_settings_type::ShaderMode: + switch (static_cast(index)) + { + case shader_mode::recompiler: return tr("Legacy (single threaded)", "Shader Mode"); + case shader_mode::async_recompiler: return tr("Async (multi threaded)", "Shader Mode"); + case shader_mode::async_with_interpreter: return tr("Async with Shader Interpreter", "Shader Mode"); + case shader_mode::interpreter_only: return tr("Shader Interpreter only", "Shader Mode"); + } + break; case emu_settings_type::FrameLimit: switch (static_cast(index)) { diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index c76ed7d2f3..e67fbcb7d0 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -64,7 +64,7 @@ enum class emu_settings_type ForceCPUBlitEmulation, DisableOnDiskShaderCache, DisableVulkanMemAllocator, - DisableAsyncShaderCompiler, + ShaderMode, MultithreadedRSX, VBlankRate, RelaxedZCULL, @@ -197,7 +197,7 @@ static const QMap settings_location = { emu_settings_type::ForceCPUBlitEmulation, { "Video", "Force CPU Blit"}}, { emu_settings_type::DisableOnDiskShaderCache, { "Video", "Disable On-Disk Shader Cache"}}, { emu_settings_type::DisableVulkanMemAllocator, { "Video", "Disable Vulkan Memory Allocator"}}, - { emu_settings_type::DisableAsyncShaderCompiler, { "Video", "Disable Asynchronous Shader Compiler"}}, + { emu_settings_type::ShaderMode, { "Video", "Shader Mode"}}, { emu_settings_type::MultithreadedRSX, { "Video", "Multithreaded RSX"}}, { emu_settings_type::RelaxedZCULL, { "Video", "Relaxed ZCULL Sync"}}, { emu_settings_type::AnisotropicFilterOverride, { "Video", "Anisotropic Filter Override"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 74e2233e3a..979fa87a54 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -406,9 +406,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std }); ui->disableVertexCache->setEnabled(!ui->multithreadedRSX->isChecked()); - m_emu_settings->EnhanceCheckBox(ui->disableAsyncShaders, emu_settings_type::DisableAsyncShaderCompiler); - SubscribeTooltip(ui->disableAsyncShaders, tooltips.settings.disable_async_shaders); - m_emu_settings->EnhanceCheckBox(ui->scrictModeRendering, emu_settings_type::StrictRenderingMode); SubscribeTooltip(ui->scrictModeRendering, tooltips.settings.strict_rendering_mode); connect(ui->scrictModeRendering, &QCheckBox::clicked, [this](bool checked) @@ -418,6 +415,21 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->gb_anisotropicFilter->setEnabled(!checked); }); + // Radio buttons + + SubscribeTooltip(ui->rb_legacy_recompiler, tooltips.settings.legacy_shader_recompiler); + SubscribeTooltip(ui->rb_async_recompiler, tooltips.settings.async_shader_recompiler); + SubscribeTooltip(ui->rb_async_with_shader_interpreter, tooltips.settings.async_with_shader_interpreter); + SubscribeTooltip(ui->rb_shader_interpreter_only, tooltips.settings.shader_interpreter_only); + + QButtonGroup *shader_mode_bg = new QButtonGroup(this); + shader_mode_bg->addButton(ui->rb_legacy_recompiler, static_cast(shader_mode::recompiler)); + shader_mode_bg->addButton(ui->rb_async_recompiler, static_cast(shader_mode::async_recompiler)); + shader_mode_bg->addButton(ui->rb_async_with_shader_interpreter, static_cast(shader_mode::async_with_interpreter)); + shader_mode_bg->addButton(ui->rb_shader_interpreter_only, static_cast(shader_mode::interpreter_only)); + + m_emu_settings->EnhanceRadioButton(shader_mode_bg, emu_settings_type::ShaderMode); + // Sliders m_emu_settings->EnhanceSlider(ui->resolutionScale, emu_settings_type::ResolutionScale); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 5d096104a6..1c84447eb5 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -432,6 +432,22 @@ + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + @@ -594,90 +610,152 @@ + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + - - - - 0 - 0 - + + + 12 - - Additional Settings + + 12 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - Write Color Buffers - - - - - - - Strict Rendering Mode - - - - - - - VSync - - - - - - - Stretch To Display Area - - - - - - - Disable Vertex Cache - - - - - - - Multithreaded RSX - - - - - - - Disable Async Shader Compiler - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 0 - 0 - - - - - - + + + + + 0 + 123 + + + + Shader Mode + + + + + + Legacy (single threaded) + + + + + + + Async (multi threaded) + + + + + + + Async with Shader Interpreter + + + + + + + Shader Interpreter only + + + + + + + + + + + 0 + 0 + + + + Additional Settings + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + Write Color Buffers + + + + + + + Strict Rendering Mode + + + + + + + VSync + + + + + + + Stretch To Display Area + + + + + + + Disable Vertex Cache + + + + + + + Multithreaded RSX + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 621ef61949..e543c6236c 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -139,10 +139,14 @@ public: const QString vsync = tr("By having this off you might obtain a higher frame rate at the cost of tearing artifacts in the game."); const QString strict_rendering_mode = tr("Enforces strict compliance to the API specification.\nMight result in degraded performance in some games.\nCan resolve rare cases of missing graphics and flickering.\nIf unsure, don't use this option."); const QString disable_vertex_cache = tr("Disables the vertex cache.\nMight resolve missing or flickering graphics output.\nMay degrade performance."); - const QString disable_async_shaders = tr("Disables asynchronous shader compilation.\nFixes missing graphics while shaders are compiling but introduces stuttering.\nDisable if you do not want to deal with graphics pop-in, or for testing before filing any bug reports."); const QString stretch_to_display_area = tr("Overrides the aspect ratio and stretches the image to the full display area."); const QString multithreaded_rsx = tr("Offloads some RSX operations to a secondary thread.\nMay improve performance for some high-core processors.\nMay cause slowdown in some situations due to the extra worker thread load."); + const QString legacy_shader_recompiler = tr("Disables asynchronous shader compilation.\nFixes missing graphics while shaders are compiling but introduces severe stuttering or lag.\nUse this if you do not want to deal with graphics pop-in, or for testing before filing any bug reports."); + const QString async_shader_recompiler = tr("This is the recommended option.\nIf a shader is not found in the cache, nothing will be rendered for this shader until it has compiled.\nYou may experience graphics pop-in."); + const QString async_with_shader_interpreter = tr("Hybrid rendering mode.\nIf a shader is not found in the cache, the interpreter will be used to render approximated graphics for this shader until it has compiled."); + const QString shader_interpreter_only = tr("All rendering is handled by the interpreter with no attempt to compile native shaders.\nThis mode is very slow and experimental."); + // gui const QString log_limit = tr("Sets the maximum amount of blocks that the log can display.\nThis usually equals the number of lines.\nSet 0 in order to remove the limit.");