gl/interpreter: Separable shader objects

- We use a real cache for separate VS and FS objects
This commit is contained in:
kd-11 2026-04-12 14:25:49 +03:00 committed by kd-11
parent af2af23306
commit 5c4b0a165b
2 changed files with 92 additions and 29 deletions

View File

@ -71,8 +71,7 @@ namespace gl
const u32 completed = ctr.load();
dlg->update_msg(0, fmt::format("Building variant %u of %u...", completed, limit));
dlg->set_value(0, completed);
}
while (ctr < limit);
} while (ctr < limit);
dlg->inc_value(1, 1);
dlg->refresh();
@ -82,9 +81,9 @@ namespace gl
{
for (auto& prog : m_program_cache)
{
prog.second->vertex_shader.remove();
prog.second->fragment_shader.remove();
prog.second->prog.remove();
prog.second->vertex_shader->remove();
prog.second->fragment_shader->remove();
prog.second->prog->remove();
}
}
@ -139,11 +138,22 @@ namespace gl
m_current_interpreter = build_program(opt);
}
return &m_current_interpreter->prog;
return m_current_interpreter->prog.get();
}
void shader_interpreter::build_vs(u64 compiler_options, interpreter::cached_program& prog_data)
{
{
std::lock_guard lock(m_vs_cache_lock);
if (auto found = m_vs_cache.find(compiler_options);
found != m_vs_cache.end())
{
prog_data.vertex_shader = found->second;
return;
}
}
::glsl::shader_properties properties{};
properties.domain = ::glsl::program_domain::glsl_vertex_program;
properties.require_lit_emulation = true;
@ -201,12 +211,36 @@ namespace gl
builder << program_common::interpreter::get_vertex_interpreter();
const std::string s = builder.str();
prog_data.vertex_shader.create(::glsl::program_domain::glsl_vertex_program, s);
prog_data.vertex_shader.compile();
prog_data.vertex_shader = std::make_shared<glsl::shader>();
prog_data.vertex_shader->create(::glsl::program_domain::glsl_vertex_program, s);
prog_data.vertex_shader->compile();
{
std::lock_guard lock(m_vs_cache_lock);
const auto [found, inserted] = m_vs_cache.try_emplace(compiler_options, prog_data.vertex_shader);
if (!inserted)
{
// Cache hit
prog_data.vertex_shader->remove();
prog_data.vertex_shader = found->second;
}
}
}
void shader_interpreter::build_fs(u64 compiler_options, interpreter::cached_program& prog_data)
{
{
std::lock_guard lock(m_fs_cache_lock);
if (auto found = m_fs_cache.find(compiler_options);
found != m_fs_cache.end())
{
prog_data.fragment_shader = found->second;
return;
}
}
// Allocate TIUs
auto& allocator = prog_data.allocator;
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES)
@ -355,8 +389,21 @@ namespace gl
builder << program_common::interpreter::get_fragment_interpreter();
const std::string s = builder.str();
prog_data.fragment_shader.create(::glsl::program_domain::glsl_fragment_program, s);
prog_data.fragment_shader.compile();
prog_data.fragment_shader = std::make_shared<glsl::shader>();
prog_data.fragment_shader->create(::glsl::program_domain::glsl_fragment_program, s);
prog_data.fragment_shader->compile();
{
std::lock_guard lock(m_fs_cache_lock);
const auto [found, inserted] = m_fs_cache.try_emplace(compiler_options, prog_data.fragment_shader);
if (!inserted)
{
// Cache hit
prog_data.fragment_shader->remove();
prog_data.fragment_shader = found->second;
}
}
}
interpreter::cached_program* shader_interpreter::build_program(u64 compiler_options)
@ -365,9 +412,10 @@ namespace gl
build_fs(compiler_options, *data);
build_vs(compiler_options, *data);
data->prog.create().
attach(data->vertex_shader).
attach(data->fragment_shader).
data->prog = std::make_shared<glsl::program>();
data->prog->create().
attach(*data->vertex_shader).
attach(*data->fragment_shader).
link();
post_init_hook(data, compiler_options);
@ -383,13 +431,13 @@ namespace gl
build_fs(compiler_options, *data);
build_vs(compiler_options, *data);
prog->attach(data->vertex_shader).
attach(data->fragment_shader);
prog->attach(*data->vertex_shader).
attach(*data->fragment_shader);
};
auto storage_hook = [=](std::unique_ptr<glsl::program>& prog)
{
data->prog.swap(std::move(*prog));
data->prog.reset(prog.release());
post_init_hook(data, compiler_options);
if (callback)
@ -409,8 +457,8 @@ namespace gl
void shader_interpreter::post_init_hook(interpreter::cached_program* data, u64 compiler_options)
{
data->prog.uniforms[0] = GL_STREAM_BUFFER_START + 0;
data->prog.uniforms[1] = GL_STREAM_BUFFER_START + 1;
data->prog->uniforms[0] = GL_STREAM_BUFFER_START + 0;
data->prog->uniforms[1] = GL_STREAM_BUFFER_START + 1;
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES)
{
@ -426,7 +474,7 @@ namespace gl
allocator.pools[i].allocate(assigned++);
}
data->prog.uniforms[type_names[i]] = allocator.pools[i].allocated;
data->prog->uniforms[type_names[i]] = allocator.pools[i].allocated;
}
}
@ -435,7 +483,7 @@ namespace gl
bool shader_interpreter::is_interpreter(const glsl::program* program) const
{
return (program == &m_current_interpreter->prog);
return (program == m_current_interpreter->prog.get());
}
void shader_interpreter::update_fragment_textures(
@ -528,9 +576,9 @@ namespace gl
}
}
if (allocator.pools[0].flags) m_current_interpreter->prog.uniforms["sampler1D_array"] = allocator.pools[0].allocated;
if (allocator.pools[1].flags) m_current_interpreter->prog.uniforms["sampler2D_array"] = allocator.pools[1].allocated;
if (allocator.pools[2].flags) m_current_interpreter->prog.uniforms["samplerCube_array"] = allocator.pools[2].allocated;
if (allocator.pools[3].flags) m_current_interpreter->prog.uniforms["sampler3D_array"] = allocator.pools[3].allocated;
if (allocator.pools[0].flags) m_current_interpreter->prog->uniforms["sampler1D_array"] = allocator.pools[0].allocated;
if (allocator.pools[1].flags) m_current_interpreter->prog->uniforms["sampler2D_array"] = allocator.pools[1].allocated;
if (allocator.pools[2].flags) m_current_interpreter->prog->uniforms["samplerCube_array"] = allocator.pools[2].allocated;
if (allocator.pools[3].flags) m_current_interpreter->prog->uniforms["sampler3D_array"] = allocator.pools[3].allocated;
}
}

View File

@ -62,19 +62,34 @@ namespace gl
void allocate(int size);
};
enum cached_program_flags
{
CACHED_PIPE_UNOPTIMIZED = 1
};
struct cached_program
{
glsl::shader vertex_shader;
glsl::shader fragment_shader;
glsl::program prog;
u32 flags = 0;
std::shared_ptr<glsl::shader> vertex_shader;
std::shared_ptr<glsl::shader> fragment_shader;
std::shared_ptr<glsl::program> prog;
texture_pool_allocator allocator;
};
}
class shader_interpreter
{
using shader_cache_t = std::unordered_map<u64, std::unique_ptr<interpreter::cached_program>>;
shader_cache_t m_program_cache;
using shader_cache_t = std::unordered_map<u64, std::shared_ptr<glsl::shader>>;
using pipeline_cache_t = std::unordered_map<u64, std::unique_ptr<interpreter::cached_program>>;
shared_mutex m_vs_cache_lock;
shared_mutex m_fs_cache_lock;
shader_cache_t m_vs_cache;
shader_cache_t m_fs_cache;
pipeline_cache_t m_program_cache;
void build_vs(u64 compiler_options, interpreter::cached_program& prog_data);
void build_fs(u64 compiler_options, interpreter::cached_program& prog_data);