mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-05-07 13:37:46 +00:00
vk/interpreter: Implement base pipeline propagation
This commit is contained in:
parent
d519571e18
commit
ac28c391f6
5 changed files with 66 additions and 30 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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<glsl::program> 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<glsl::program>&) { 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,13 @@ namespace vk
|
|||
u32 fragment_textures_location = 0;
|
||||
};
|
||||
|
||||
std::unordered_map<pipeline_key, std::shared_ptr<glsl::program>, key_hasher> m_program_cache;
|
||||
struct pipeline_cache_entry_t
|
||||
{
|
||||
u32 flags = 0;
|
||||
std::shared_ptr<glsl::program> program;
|
||||
};
|
||||
|
||||
std::unordered_map<pipeline_key, pipeline_cache_entry_t, key_hasher> m_program_cache;
|
||||
std::unordered_map<u64, std::shared_ptr<VKVertexProgram>> m_vs_shader_cache;
|
||||
std::unordered_map<u64, std::shared_ptr<VKFragmentProgram>> m_fs_shader_cache;
|
||||
std::unordered_map<u64, pipeline_info_ex_t> m_pipeline_info_cache;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue