diff options
| author | 2019-09-26 00:23:08 -0300 | |
|---|---|---|
| committer | 2019-10-25 09:01:32 -0400 | |
| commit | 78f3e8a75792c976eb5bfa6df4c020d898642684 (patch) | |
| tree | 4c7103c396f180654850362c89d01b46358e58cb | |
| parent | gl_shader_disk_cache: Store and load fast BRX (diff) | |
| download | yuzu-78f3e8a75792c976eb5bfa6df4c020d898642684.tar.gz yuzu-78f3e8a75792c976eb5bfa6df4c020d898642684.tar.xz yuzu-78f3e8a75792c976eb5bfa6df4c020d898642684.zip | |
gl_shader_cache: Implement locker variants invalidation
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 102 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.h | 15 | ||||
| -rw-r--r-- | src/video_core/shader/const_buffer_locker.cpp | 28 | ||||
| -rw-r--r-- | 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 7e7aea15f..f1b89165d 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) { | |||
| 225 | return fmt::format("{}{:016X}", GetProgramTypeName(program_type), unique_identifier); | 225 | return fmt::format("{}{:016X}", GetProgramTypeName(program_type), unique_identifier); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | Tegra::Engines::ConstBufferEngineInterface& GetConstBufferEngineInterface( | ||
| 229 | Core::System& system, ProgramType program_type) { | ||
| 230 | if (program_type == ProgramType::Compute) { | ||
| 231 | return system.GPU().KeplerCompute(); | ||
| 232 | } else { | ||
| 233 | return system.GPU().Maxwell3D(); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | std::unique_ptr<ConstBufferLocker> MakeLocker(Core::System& system, ProgramType program_type) { | ||
| 238 | return std::make_unique<ConstBufferLocker>(GetEnginesShaderType(program_type), | ||
| 239 | GetConstBufferEngineInterface(system, program_type)); | ||
| 240 | } | ||
| 241 | |||
| 242 | void FillLocker(ConstBufferLocker& locker, const ShaderDiskCacheUsage& usage) { | ||
| 243 | for (const auto& key : usage.keys) { | ||
| 244 | const auto [buffer, offset] = key.first; | ||
| 245 | locker.InsertKey(buffer, offset, key.second); | ||
| 246 | } | ||
| 247 | for (const auto& [offset, sampler] : usage.bound_samplers) { | ||
| 248 | locker.InsertBoundSampler(offset, sampler); | ||
| 249 | } | ||
| 250 | for (const auto& [key, sampler] : usage.bindless_samplers) { | ||
| 251 | const auto [buffer, offset] = key; | ||
| 252 | locker.InsertBindlessSampler(buffer, offset, sampler); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 228 | CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramType program_type, | 256 | CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramType program_type, |
| 229 | const ProgramCode& program_code, const ProgramCode& program_code_b, | 257 | const ProgramCode& program_code, const ProgramCode& program_code_b, |
| 230 | const ProgramVariant& variant, ConstBufferLocker& locker, | 258 | const ProgramVariant& variant, ConstBufferLocker& locker, |
| @@ -336,11 +364,27 @@ CachedShader::CachedShader(const ShaderParameters& params, ProgramType program_t | |||
| 336 | disk_cache{params.disk_cache}, device{params.device}, cpu_addr{params.cpu_addr}, | 364 | disk_cache{params.disk_cache}, device{params.device}, cpu_addr{params.cpu_addr}, |
| 337 | unique_identifier{params.unique_identifier}, program_type{program_type}, entries{entries}, | 365 | unique_identifier{params.unique_identifier}, program_type{program_type}, entries{entries}, |
| 338 | program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} { | 366 | program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} { |
| 339 | if (params.precompiled_variants) { | 367 | if (!params.precompiled_variants) { |
| 340 | for (const auto& pair : *params.precompiled_variants) { | 368 | return; |
| 341 | const auto& variant = pair->first.variant; | 369 | } |
| 342 | programs.emplace(variant, pair->second); | 370 | for (const auto& pair : *params.precompiled_variants) { |
| 371 | auto locker = MakeLocker(system, program_type); | ||
| 372 | const auto& usage = pair->first; | ||
| 373 | FillLocker(*locker, usage); | ||
| 374 | |||
| 375 | std::unique_ptr<LockerVariant>* locker_variant = nullptr; | ||
| 376 | const auto it = | ||
| 377 | std::find_if(locker_variants.begin(), locker_variants.end(), [&](const auto& variant) { | ||
| 378 | return variant->locker->HasEqualKeys(*locker); | ||
| 379 | }); | ||
| 380 | if (it == locker_variants.end()) { | ||
| 381 | locker_variant = &locker_variants.emplace_back(); | ||
| 382 | *locker_variant = std::make_unique<LockerVariant>(); | ||
| 383 | locker_variant->get()->locker = std::move(locker); | ||
| 384 | } else { | ||
| 385 | locker_variant = &*it; | ||
| 343 | } | 386 | } |
| 387 | locker_variant->get()->programs.emplace(usage.variant, pair->second); | ||
| 344 | } | 388 | } |
| 345 | } | 389 | } |
| 346 | 390 | ||
| @@ -380,19 +424,14 @@ Shader CachedShader::CreateFromCache(const ShaderParameters& params, | |||
| 380 | } | 424 | } |
| 381 | 425 | ||
| 382 | std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { | 426 | std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { |
| 383 | const auto [entry, is_cache_miss] = programs.try_emplace(variant); | 427 | UpdateVariant(); |
| 428 | |||
| 429 | const auto [entry, is_cache_miss] = curr_variant->programs.try_emplace(variant); | ||
| 384 | auto& program = entry->second; | 430 | auto& program = entry->second; |
| 385 | if (is_cache_miss) { | 431 | if (is_cache_miss) { |
| 386 | Tegra::Engines::ConstBufferEngineInterface* engine = nullptr; | ||
| 387 | if (program_type == ProgramType::Compute) { | ||
| 388 | engine = &system.GPU().KeplerCompute(); | ||
| 389 | } else { | ||
| 390 | engine = &system.GPU().Maxwell3D(); | ||
| 391 | } | ||
| 392 | ConstBufferLocker locker(GetEnginesShaderType(program_type), *engine); | ||
| 393 | program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, | 432 | program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, |
| 394 | variant, locker); | 433 | variant, *curr_variant->locker); |
| 395 | disk_cache.SaveUsage(GetUsage(variant, locker)); | 434 | disk_cache.SaveUsage(GetUsage(variant, *curr_variant->locker)); |
| 396 | 435 | ||
| 397 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); | 436 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); |
| 398 | } | 437 | } |
| @@ -408,6 +447,25 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar | |||
| 408 | return {program->handle, base_bindings}; | 447 | return {program->handle, base_bindings}; |
| 409 | } | 448 | } |
| 410 | 449 | ||
| 450 | void CachedShader::UpdateVariant() { | ||
| 451 | if (curr_variant && !curr_variant->locker->IsConsistent()) { | ||
| 452 | curr_variant = nullptr; | ||
| 453 | } | ||
| 454 | if (!curr_variant) { | ||
| 455 | for (auto& variant : locker_variants) { | ||
| 456 | if (variant->locker->IsConsistent()) { | ||
| 457 | curr_variant = variant.get(); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } | ||
| 461 | if (!curr_variant) { | ||
| 462 | auto& new_variant = locker_variants.emplace_back(); | ||
| 463 | new_variant = std::make_unique<LockerVariant>(); | ||
| 464 | new_variant->locker = MakeLocker(system, program_type); | ||
| 465 | curr_variant = new_variant.get(); | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 411 | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, | 469 | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, |
| 412 | const ConstBufferLocker& locker) const { | 470 | const ConstBufferLocker& locker) const { |
| 413 | ShaderDiskCacheUsage usage; | 471 | ShaderDiskCacheUsage usage; |
| @@ -475,21 +533,11 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 475 | } | 533 | } |
| 476 | } | 534 | } |
| 477 | if (!shader) { | 535 | if (!shader) { |
| 478 | ConstBufferLocker locker(GetEnginesShaderType(unspecialized.program_type)); | 536 | auto locker{MakeLocker(system, unspecialized.program_type)}; |
| 479 | for (const auto& key : usage.keys) { | 537 | FillLocker(*locker, usage); |
| 480 | const auto [buffer, offset] = key.first; | ||
| 481 | locker.InsertKey(buffer, offset, key.second); | ||
| 482 | } | ||
| 483 | for (const auto& [offset, sampler] : usage.bound_samplers) { | ||
| 484 | locker.InsertBoundSampler(offset, sampler); | ||
| 485 | } | ||
| 486 | for (const auto& [key, sampler] : usage.bindless_samplers) { | ||
| 487 | const auto [buffer, offset] = key; | ||
| 488 | locker.InsertBindlessSampler(buffer, offset, sampler); | ||
| 489 | } | ||
| 490 | shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, | 538 | shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, |
| 491 | unspecialized.code, unspecialized.code_b, usage.variant, | 539 | unspecialized.code, unspecialized.code_b, usage.variant, |
| 492 | locker, true); | 540 | *locker, true); |
| 493 | } | 541 | } |
| 494 | 542 | ||
| 495 | std::scoped_lock lock{mutex}; | 543 | 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 2935e6831..6bd7c9cf1 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 @@ | |||
| 21 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 21 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 22 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 22 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | 23 | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" |
| 24 | #include "video_core/shader/const_buffer_locker.h" | ||
| 24 | #include "video_core/shader/shader_ir.h" | 25 | #include "video_core/shader/shader_ir.h" |
| 25 | 26 | ||
| 26 | namespace Core { | 27 | namespace Core { |
| @@ -31,10 +32,6 @@ namespace Core::Frontend { | |||
| 31 | class EmuWindow; | 32 | class EmuWindow; |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | namespace VideoCommon::Shader { | ||
| 35 | class ConstBufferLocker; | ||
| 36 | } | ||
| 37 | |||
| 38 | namespace OpenGL { | 35 | namespace OpenGL { |
| 39 | 36 | ||
| 40 | class CachedShader; | 37 | class CachedShader; |
| @@ -92,10 +89,17 @@ public: | |||
| 92 | std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant); | 89 | std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant); |
| 93 | 90 | ||
| 94 | private: | 91 | private: |
| 92 | struct LockerVariant { | ||
| 93 | std::unique_ptr<VideoCommon::Shader::ConstBufferLocker> locker; | ||
| 94 | std::unordered_map<ProgramVariant, CachedProgram> programs; | ||
| 95 | }; | ||
| 96 | |||
| 95 | explicit CachedShader(const ShaderParameters& params, ProgramType program_type, | 97 | explicit CachedShader(const ShaderParameters& params, ProgramType program_type, |
| 96 | GLShader::ShaderEntries entries, ProgramCode program_code, | 98 | GLShader::ShaderEntries entries, ProgramCode program_code, |
| 97 | ProgramCode program_code_b); | 99 | ProgramCode program_code_b); |
| 98 | 100 | ||
| 101 | void UpdateVariant(); | ||
| 102 | |||
| 99 | ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, | 103 | ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, |
| 100 | const VideoCommon::Shader::ConstBufferLocker& locker) const; | 104 | const VideoCommon::Shader::ConstBufferLocker& locker) const; |
| 101 | 105 | ||
| @@ -113,7 +117,8 @@ private: | |||
| 113 | ProgramCode program_code; | 117 | ProgramCode program_code; |
| 114 | ProgramCode program_code_b; | 118 | ProgramCode program_code_b; |
| 115 | 119 | ||
| 116 | std::unordered_map<ProgramVariant, CachedProgram> programs; | 120 | LockerVariant* curr_variant = nullptr; |
| 121 | std::vector<std::unique_ptr<LockerVariant>> locker_variants; | ||
| 117 | }; | 122 | }; |
| 118 | 123 | ||
| 119 | class ShaderCacheOpenGL final : public RasterizerCache<Shader> { | 124 | class ShaderCacheOpenGL final : public RasterizerCache<Shader> { |
diff --git a/src/video_core/shader/const_buffer_locker.cpp b/src/video_core/shader/const_buffer_locker.cpp index fda9e3c38..592bbf657 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 { | |||
| 82 | return false; | 82 | return false; |
| 83 | } | 83 | } |
| 84 | return std::all_of(keys.begin(), keys.end(), | 84 | return std::all_of(keys.begin(), keys.end(), |
| 85 | [](const auto& key) { | 85 | [this](const auto& pair) { |
| 86 | const auto [value, other_value] = key.first; | 86 | const auto [cbuf, offset] = pair.first; |
| 87 | return value == other_value; | 87 | const auto value = pair.second; |
| 88 | return value == engine->AccessConstBuffer32(stage, cbuf, offset); | ||
| 88 | }) && | 89 | }) && |
| 89 | std::all_of(bound_samplers.begin(), bound_samplers.end(), | 90 | std::all_of(bound_samplers.begin(), bound_samplers.end(), |
| 90 | [this](const auto& sampler) { | 91 | [this](const auto& sampler) { |
| 91 | const auto [key, value] = sampler; | 92 | const auto [key, value] = sampler; |
| 92 | const auto other_value = engine->AccessBoundSampler(stage, key); | 93 | return value == engine->AccessBoundSampler(stage, key); |
| 93 | return value == other_value; | ||
| 94 | }) && | 94 | }) && |
| 95 | std::all_of( | 95 | std::all_of(bindless_samplers.begin(), bindless_samplers.end(), |
| 96 | bindless_samplers.begin(), bindless_samplers.end(), [this](const auto& sampler) { | 96 | [this](const auto& sampler) { |
| 97 | const auto [cbuf, offset] = sampler.first; | 97 | const auto [cbuf, offset] = sampler.first; |
| 98 | const auto value = sampler.second; | 98 | const auto value = sampler.second; |
| 99 | const auto other_value = engine->AccessBindlessSampler(stage, cbuf, offset); | 99 | return value == engine->AccessBindlessSampler(stage, cbuf, offset); |
| 100 | return value == other_value; | 100 | }); |
| 101 | }); | 101 | } |
| 102 | |||
| 103 | bool ConstBufferLocker::HasEqualKeys(const ConstBufferLocker& rhs) const { | ||
| 104 | return keys == rhs.keys && bound_samplers == rhs.bound_samplers && | ||
| 105 | bindless_samplers == rhs.bindless_samplers; | ||
| 102 | } | 106 | } |
| 103 | 107 | ||
| 104 | } // namespace VideoCommon::Shader | 108 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/const_buffer_locker.h b/src/video_core/shader/const_buffer_locker.h index 417d5a16f..966537fd6 100644 --- a/src/video_core/shader/const_buffer_locker.h +++ b/src/video_core/shader/const_buffer_locker.h | |||
| @@ -44,6 +44,9 @@ public: | |||
| 44 | /// the same value, false otherwise; | 44 | /// the same value, false otherwise; |
| 45 | bool IsConsistent() const; | 45 | bool IsConsistent() const; |
| 46 | 46 | ||
| 47 | /// Returns true if the keys are equal to the other ones in the locker. | ||
| 48 | bool HasEqualKeys(const ConstBufferLocker& rhs) const; | ||
| 49 | |||
| 47 | /// Gives an getter to the const buffer keys in the database. | 50 | /// Gives an getter to the const buffer keys in the database. |
| 48 | const KeyMap& GetKeys() const { | 51 | const KeyMap& GetKeys() const { |
| 49 | return keys; | 52 | return keys; |