From 78f3e8a75792c976eb5bfa6df4c020d898642684 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 26 Sep 2019 00:23:08 -0300 Subject: [PATCH] gl_shader_cache: Implement locker variants invalidation --- .../renderer_opengl/gl_shader_cache.cpp | 102 +++++++++++++----- .../renderer_opengl/gl_shader_cache.h | 15 ++- src/video_core/shader/const_buffer_locker.cpp | 28 ++--- src/video_core/shader/const_buffer_locker.h | 3 + 4 files changed, 104 insertions(+), 44 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 7e7aea15f3..f1b89165d3 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -225,6 +225,34 @@ std::string GetShaderId(u64 unique_identifier, ProgramType program_type) { return fmt::format("{}{:016X}", GetProgramTypeName(program_type), unique_identifier); } +Tegra::Engines::ConstBufferEngineInterface& GetConstBufferEngineInterface( + Core::System& system, ProgramType program_type) { + if (program_type == ProgramType::Compute) { + return system.GPU().KeplerCompute(); + } else { + return system.GPU().Maxwell3D(); + } +} + +std::unique_ptr MakeLocker(Core::System& system, ProgramType program_type) { + return std::make_unique(GetEnginesShaderType(program_type), + GetConstBufferEngineInterface(system, program_type)); +} + +void FillLocker(ConstBufferLocker& locker, const ShaderDiskCacheUsage& usage) { + for (const auto& key : usage.keys) { + const auto [buffer, offset] = key.first; + locker.InsertKey(buffer, offset, key.second); + } + for (const auto& [offset, sampler] : usage.bound_samplers) { + locker.InsertBoundSampler(offset, sampler); + } + for (const auto& [key, sampler] : usage.bindless_samplers) { + const auto [buffer, offset] = key; + locker.InsertBindlessSampler(buffer, offset, sampler); + } +} + CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramType program_type, const ProgramCode& program_code, const ProgramCode& program_code_b, const ProgramVariant& variant, ConstBufferLocker& locker, @@ -336,11 +364,27 @@ CachedShader::CachedShader(const ShaderParameters& params, ProgramType program_t disk_cache{params.disk_cache}, device{params.device}, cpu_addr{params.cpu_addr}, unique_identifier{params.unique_identifier}, program_type{program_type}, entries{entries}, program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} { - if (params.precompiled_variants) { - for (const auto& pair : *params.precompiled_variants) { - const auto& variant = pair->first.variant; - programs.emplace(variant, pair->second); + if (!params.precompiled_variants) { + return; + } + for (const auto& pair : *params.precompiled_variants) { + auto locker = MakeLocker(system, program_type); + const auto& usage = pair->first; + FillLocker(*locker, usage); + + std::unique_ptr* locker_variant = nullptr; + const auto it = + std::find_if(locker_variants.begin(), locker_variants.end(), [&](const auto& variant) { + return variant->locker->HasEqualKeys(*locker); + }); + if (it == locker_variants.end()) { + locker_variant = &locker_variants.emplace_back(); + *locker_variant = std::make_unique(); + locker_variant->get()->locker = std::move(locker); + } else { + locker_variant = &*it; } + locker_variant->get()->programs.emplace(usage.variant, pair->second); } } @@ -380,19 +424,14 @@ Shader CachedShader::CreateFromCache(const ShaderParameters& params, } std::tuple CachedShader::GetProgramHandle(const ProgramVariant& variant) { - const auto [entry, is_cache_miss] = programs.try_emplace(variant); + UpdateVariant(); + + const auto [entry, is_cache_miss] = curr_variant->programs.try_emplace(variant); auto& program = entry->second; if (is_cache_miss) { - Tegra::Engines::ConstBufferEngineInterface* engine = nullptr; - if (program_type == ProgramType::Compute) { - engine = &system.GPU().KeplerCompute(); - } else { - engine = &system.GPU().Maxwell3D(); - } - ConstBufferLocker locker(GetEnginesShaderType(program_type), *engine); program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, - variant, locker); - disk_cache.SaveUsage(GetUsage(variant, locker)); + variant, *curr_variant->locker); + disk_cache.SaveUsage(GetUsage(variant, *curr_variant->locker)); LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); } @@ -408,6 +447,25 @@ std::tuple CachedShader::GetProgramHandle(const ProgramVar return {program->handle, base_bindings}; } +void CachedShader::UpdateVariant() { + if (curr_variant && !curr_variant->locker->IsConsistent()) { + curr_variant = nullptr; + } + if (!curr_variant) { + for (auto& variant : locker_variants) { + if (variant->locker->IsConsistent()) { + curr_variant = variant.get(); + } + } + } + if (!curr_variant) { + auto& new_variant = locker_variants.emplace_back(); + new_variant = std::make_unique(); + new_variant->locker = MakeLocker(system, program_type); + curr_variant = new_variant.get(); + } +} + ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, const ConstBufferLocker& locker) const { ShaderDiskCacheUsage usage; @@ -475,21 +533,11 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, } } if (!shader) { - ConstBufferLocker locker(GetEnginesShaderType(unspecialized.program_type)); - for (const auto& key : usage.keys) { - const auto [buffer, offset] = key.first; - locker.InsertKey(buffer, offset, key.second); - } - for (const auto& [offset, sampler] : usage.bound_samplers) { - locker.InsertBoundSampler(offset, sampler); - } - for (const auto& [key, sampler] : usage.bindless_samplers) { - const auto [buffer, offset] = key; - locker.InsertBindlessSampler(buffer, offset, sampler); - } + auto locker{MakeLocker(system, unspecialized.program_type)}; + FillLocker(*locker, usage); shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, unspecialized.code, unspecialized.code_b, usage.variant, - locker, true); + *locker, true); } std::scoped_lock lock{mutex}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 2935e68312..6bd7c9cf15 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -21,6 +21,7 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h" +#include "video_core/shader/const_buffer_locker.h" #include "video_core/shader/shader_ir.h" namespace Core { @@ -31,10 +32,6 @@ namespace Core::Frontend { class EmuWindow; } -namespace VideoCommon::Shader { -class ConstBufferLocker; -} - namespace OpenGL { class CachedShader; @@ -92,10 +89,17 @@ public: std::tuple GetProgramHandle(const ProgramVariant& variant); private: + struct LockerVariant { + std::unique_ptr locker; + std::unordered_map programs; + }; + explicit CachedShader(const ShaderParameters& params, ProgramType program_type, GLShader::ShaderEntries entries, ProgramCode program_code, ProgramCode program_code_b); + void UpdateVariant(); + ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, const VideoCommon::Shader::ConstBufferLocker& locker) const; @@ -113,7 +117,8 @@ private: ProgramCode program_code; ProgramCode program_code_b; - std::unordered_map programs; + LockerVariant* curr_variant = nullptr; + std::vector> locker_variants; }; class ShaderCacheOpenGL final : public RasterizerCache { diff --git a/src/video_core/shader/const_buffer_locker.cpp b/src/video_core/shader/const_buffer_locker.cpp index fda9e3c384..592bbf6576 100644 --- a/src/video_core/shader/const_buffer_locker.cpp +++ b/src/video_core/shader/const_buffer_locker.cpp @@ -82,23 +82,27 @@ bool ConstBufferLocker::IsConsistent() const { return false; } return std::all_of(keys.begin(), keys.end(), - [](const auto& key) { - const auto [value, other_value] = key.first; - return value == other_value; + [this](const auto& pair) { + const auto [cbuf, offset] = pair.first; + const auto value = pair.second; + return value == engine->AccessConstBuffer32(stage, cbuf, offset); }) && std::all_of(bound_samplers.begin(), bound_samplers.end(), [this](const auto& sampler) { const auto [key, value] = sampler; - const auto other_value = engine->AccessBoundSampler(stage, key); - return value == other_value; + return value == engine->AccessBoundSampler(stage, key); }) && - std::all_of( - bindless_samplers.begin(), bindless_samplers.end(), [this](const auto& sampler) { - const auto [cbuf, offset] = sampler.first; - const auto value = sampler.second; - const auto other_value = engine->AccessBindlessSampler(stage, cbuf, offset); - return value == other_value; - }); + std::all_of(bindless_samplers.begin(), bindless_samplers.end(), + [this](const auto& sampler) { + const auto [cbuf, offset] = sampler.first; + const auto value = sampler.second; + return value == engine->AccessBindlessSampler(stage, cbuf, offset); + }); +} + +bool ConstBufferLocker::HasEqualKeys(const ConstBufferLocker& rhs) const { + return keys == rhs.keys && bound_samplers == rhs.bound_samplers && + bindless_samplers == rhs.bindless_samplers; } } // namespace VideoCommon::Shader diff --git a/src/video_core/shader/const_buffer_locker.h b/src/video_core/shader/const_buffer_locker.h index 417d5a16f0..966537fd6e 100644 --- a/src/video_core/shader/const_buffer_locker.h +++ b/src/video_core/shader/const_buffer_locker.h @@ -44,6 +44,9 @@ public: /// the same value, false otherwise; bool IsConsistent() const; + /// Returns true if the keys are equal to the other ones in the locker. + bool HasEqualKeys(const ConstBufferLocker& rhs) const; + /// Gives an getter to the const buffer keys in the database. const KeyMap& GetKeys() const { return keys;