diff --git a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp index 68b4c9dc01..6592dd4da9 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.cpp @@ -13,7 +13,8 @@ namespace gl { using glsl::shader; - using enum program_common::interpreter::compiler_option; + using enum program_common::interpreter::compiler_option; + using enum program_common::interpreter::cached_pipeline_flags; namespace interpreter { @@ -88,7 +89,7 @@ namespace gl // Second stage. Propagate base pipelines to all compatible ctr = 0; - reader_lock lock(m_program_cache_lock); + std::lock_guard lock(m_program_cache_lock); for (const auto& variant : variants.pipelines) { @@ -107,7 +108,7 @@ namespace gl } auto data = new interpreter::cached_program(); - data->flags |= interpreter::CACHED_PIPE_UNOPTIMIZED; + data->flags |= CACHED_PIPE_UNOPTIMIZED; data->allocator = base_pipeline->second->allocator; data->vertex_shader = base_pipeline->second->vertex_shader; data->fragment_shader = base_pipeline->second->fragment_shader; @@ -193,13 +194,13 @@ namespace gl if (m_current_interpreter) { - constexpr u32 test_mask = (interpreter::CACHED_PIPE_UNOPTIMIZED | interpreter::CACHED_PIPE_RECOMPILING); - constexpr u32 unoptimized_mask = interpreter::CACHED_PIPE_UNOPTIMIZED; + constexpr u32 test_mask = (CACHED_PIPE_UNOPTIMIZED | CACHED_PIPE_RECOMPILING); + constexpr u32 unoptimized_mask = 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; + m_current_interpreter->flags |= CACHED_PIPE_RECOMPILING; build_program_async(opt, {}); } return m_current_interpreter->prog.get(); diff --git a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h index ef070c3fd2..015e46cef8 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h +++ b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h @@ -62,12 +62,6 @@ namespace gl void allocate(int size); }; - enum cached_program_flags - { - CACHED_PIPE_UNOPTIMIZED = (1 << 0), - CACHED_PIPE_RECOMPILING = (1 << 1), - }; - struct cached_program { u32 flags = 0; diff --git a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h index b80f871769..26f4877bac 100644 --- a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h +++ b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h @@ -45,6 +45,12 @@ namespace program_common COMPILER_OPT_VS_MIN = COMPILER_OPT_ENABLE_INSTANCING, }; + enum cached_pipeline_flags : u32 + { + CACHED_PIPE_UNOPTIMIZED = (1 << 0), + CACHED_PIPE_RECOMPILING = (1 << 1), + }; + static std::string get_vertex_interpreter() { const char* s = diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 4ed492c313..f0723080f5 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -15,6 +15,7 @@ namespace vk { using enum program_common::interpreter::compiler_option; + using enum program_common::interpreter::cached_pipeline_flags; class async_pipe_compiler_context { @@ -497,7 +498,13 @@ namespace vk std::shared_ptr result = std::move(prog); std::lock_guard lock(this->m_program_cache_lock); - this->m_program_cache[key] = result; + + pipeline_cache_entry_t cached_program + { + .flags = 0, + .program = result + }; + this->m_program_cache[key] = cached_program; if (async_callback) { @@ -601,15 +608,21 @@ namespace vk auto found = m_program_cache.find(key); if (found != m_program_cache.end()) [[likely]] { - m_current_interpreter = found->second; + m_current_interpreter = found->second.program; return m_current_interpreter.get(); } } m_current_interpreter = link(properties, key.compiler_opt); + pipeline_cache_entry_t cache_entry + { + .flags = 0, + .program = m_current_interpreter + }; + std::lock_guard lock(m_program_cache_lock); - m_program_cache[key] = m_current_interpreter; + m_program_cache[key] = cache_entry; return m_current_interpreter.get(); } @@ -709,6 +722,8 @@ namespace vk } } + // Drain the queue. + // FIXME: Since the queue is executing from the context of the pipe compiler, we cannot properly stop this process. do { std::this_thread::sleep_for(16ms); @@ -719,26 +734,40 @@ namespace vk } while (ctr.load() < limit1); - // TODO: Propagate base pipelines for faster startup ctr = 0; - for (auto& variant : variants.pipelines) + std::lock_guard lock(m_program_cache_lock); + + for (const auto& props : pipe_properties) { - for (const auto& props : pipe_properties) + pipeline_key base_key; + base_key.properties = props; + + for (auto& variant : variants.pipelines) { - link(props, variant.vs_opts.shader_opt | variant.fs_opts.shader_opt, true, [&](std::shared_ptr&) { ctr++; }); + // Check if we have an exact match + base_key.compiler_opt = variant.vs_opts.shader_opt | variant.fs_opts.shader_opt; + if (auto found = m_program_cache.find(base_key); + found != m_program_cache.end()) + { + // We have a perfect match, no propagation required + continue; + } + + // Find a compatible pipeline + auto compat_key = base_key; + compat_key.compiler_opt = variant.vs_opts.compatible_shader_opts | variant.fs_opts.compatible_shader_opts; + auto found = m_program_cache.find(compat_key); + ensure(found != m_program_cache.end(), "Invalid interpreter configuration."); + + pipeline_cache_entry_t cache_entry + { + .flags = CACHED_PIPE_UNOPTIMIZED, + .program = found->second.program + }; + m_program_cache[base_key] = cache_entry; } } - do - { - std::this_thread::sleep_for(16ms); - - const auto completed = ctr.load(); - dlg->update_msg(1, fmt::format("Linking variant %u of %u...", completed, limit2)); - dlg->set_value(1, completed); - } - while (ctr.load() < limit2); - dlg->set_value(1, limit2); dlg->refresh(); } diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h index a14fe3c5a8..306a48d85b 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h @@ -57,7 +57,13 @@ namespace vk u32 fragment_textures_location = 0; }; - std::unordered_map, key_hasher> m_program_cache; + struct pipeline_cache_entry_t + { + u32 flags = 0; + std::shared_ptr program; + }; + + std::unordered_map m_program_cache; std::unordered_map> m_vs_shader_cache; std::unordered_map> m_fs_shader_cache; std::unordered_map m_pipeline_info_cache;