diff --git a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp index a2c63b505b..c7bb6f1024 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp @@ -59,7 +59,7 @@ namespace gl dlg->set_limit(1, limit2); atomic_t ctr = 0; - auto progress_hook = [&](interpreter::cached_program*) { ctr++; }; + auto progress_hook = [&](const std::shared_ptr&) { ctr++; }; auto update_progress = [&](u32 stage) { @@ -188,9 +188,22 @@ namespace gl std::lock_guard lock(m_program_cache_lock); if (auto it = m_program_cache.find(opt); it != m_program_cache.end()) [[likely]] { - m_current_interpreter = it->second.get(); + m_current_interpreter = it->second; + } + + if (m_current_interpreter) + { + constexpr u32 test_mask = (interpreter::CACHED_PIPE_UNOPTIMIZED | interpreter::CACHED_PIPE_RECOMPILING); + constexpr u32 unoptimized_mask = interpreter::CACHED_PIPE_UNOPTIMIZED; + if ((m_current_interpreter->flags & test_mask) == unoptimized_mask) + { + // Interpreter is unoptimized and we haven't tried to recompile it + // NOTE: This operation effectively orphans the current interpreter, but since unoptimized pipelines just have a non-owning reference then it's actually fine and we don't really leak anything. + m_current_interpreter->flags |= interpreter::CACHED_PIPE_RECOMPILING; + build_program_async(opt, {}); + } + return m_current_interpreter->prog.get(); } - return m_current_interpreter->prog.get(); } m_current_interpreter = build_program(opt); @@ -465,9 +478,9 @@ namespace gl } } - interpreter::cached_program* shader_interpreter::build_program(u64 compiler_options) + std::shared_ptr shader_interpreter::build_program(u64 compiler_options) { - auto data = new interpreter::cached_program(); + auto data = std::make_shared(); build_fs(compiler_options, *data); build_vs(compiler_options, *data); @@ -481,9 +494,9 @@ namespace gl return data; } - void shader_interpreter::build_program_async(u64 compiler_options, std::function callback) + void shader_interpreter::build_program_async(u64 compiler_options, async_build_callback_t callback) { - auto data = new interpreter::cached_program(); + auto data = std::make_shared(); auto post_create_hook = [=](glsl::program* prog) { @@ -514,7 +527,7 @@ namespace gl ); } - void shader_interpreter::post_init_hook(interpreter::cached_program* data, u64 compiler_options) + void shader_interpreter::post_init_hook(const std::shared_ptr& data, u64 compiler_options) { data->prog->uniforms[0] = GL_STREAM_BUFFER_START + 0; data->prog->uniforms[1] = GL_STREAM_BUFFER_START + 1; @@ -538,7 +551,7 @@ namespace gl } std::lock_guard lock(m_program_cache_lock); - m_program_cache[compiler_options].reset(data); + m_program_cache[compiler_options] = data; } bool shader_interpreter::is_interpreter(const glsl::program* program) const diff --git a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h index d6fafba388..ef070c3fd2 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h +++ b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h @@ -64,7 +64,8 @@ namespace gl enum cached_program_flags { - CACHED_PIPE_UNOPTIMIZED = 1 + CACHED_PIPE_UNOPTIMIZED = (1 << 0), + CACHED_PIPE_RECOMPILING = (1 << 1), }; struct cached_program @@ -81,7 +82,8 @@ namespace gl class shader_interpreter { using shader_cache_t = std::unordered_map>; - using pipeline_cache_t = std::unordered_map>; + using pipeline_cache_t = std::unordered_map>; + using async_build_callback_t = std::function&)>; shared_mutex m_vs_cache_lock; shared_mutex m_fs_cache_lock; @@ -94,11 +96,11 @@ namespace gl void build_vs(u64 compiler_options, interpreter::cached_program& prog_data); void build_fs(u64 compiler_options, interpreter::cached_program& prog_data); - interpreter::cached_program* build_program(u64 compiler_options); - void build_program_async(u64 compiler_options, std::function callback); - void post_init_hook(interpreter::cached_program* data, u64 compiler_options); + std::shared_ptr build_program(u64 compiler_options); + void build_program_async(u64 compiler_options, async_build_callback_t callback); + void post_init_hook(const std::shared_ptr& data, u64 compiler_options); - interpreter::cached_program* m_current_interpreter = nullptr; + std::shared_ptr m_current_interpreter; public: void create(rsx::shader_loading_dialog* dlg);