forked from eden-emu/eden
		
	gl_shader_cache: Implement locker variants invalidation
This commit is contained in:
		
							parent
							
								
									c37c37d4a2
								
							
						
					
					
						commit
						aab971bda3
					
				
					 4 changed files with 104 additions and 44 deletions
				
			
		|  | @ -225,6 +225,34 @@ std::string GetShaderId(u64 unique_identifier, ProgramType program_type) { | ||||||
|     return fmt::format("{}{:016X}", GetProgramTypeName(program_type), unique_identifier); |     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<ConstBufferLocker> MakeLocker(Core::System& system, ProgramType program_type) { | ||||||
|  |     return std::make_unique<ConstBufferLocker>(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, | CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramType program_type, | ||||||
|                           const ProgramCode& program_code, const ProgramCode& program_code_b, |                           const ProgramCode& program_code, const ProgramCode& program_code_b, | ||||||
|                           const ProgramVariant& variant, ConstBufferLocker& locker, |                           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}, |       disk_cache{params.disk_cache}, device{params.device}, cpu_addr{params.cpu_addr}, | ||||||
|       unique_identifier{params.unique_identifier}, program_type{program_type}, entries{entries}, |       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)} { |       program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} { | ||||||
|     if (params.precompiled_variants) { |     if (!params.precompiled_variants) { | ||||||
|         for (const auto& pair : *params.precompiled_variants) { |         return; | ||||||
|             const auto& variant = pair->first.variant; |  | ||||||
|             programs.emplace(variant, pair->second); |  | ||||||
|     } |     } | ||||||
|  |     for (const auto& pair : *params.precompiled_variants) { | ||||||
|  |         auto locker = MakeLocker(system, program_type); | ||||||
|  |         const auto& usage = pair->first; | ||||||
|  |         FillLocker(*locker, usage); | ||||||
|  | 
 | ||||||
|  |         std::unique_ptr<LockerVariant>* 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<LockerVariant>(); | ||||||
|  |             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<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { | std::tuple<GLuint, BaseBindings> 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; |     auto& program = entry->second; | ||||||
|     if (is_cache_miss) { |     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, |         program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, | ||||||
|                               variant, locker); |                               variant, *curr_variant->locker); | ||||||
|         disk_cache.SaveUsage(GetUsage(variant, locker)); |         disk_cache.SaveUsage(GetUsage(variant, *curr_variant->locker)); | ||||||
| 
 | 
 | ||||||
|         LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); |         LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); | ||||||
|     } |     } | ||||||
|  | @ -408,6 +447,25 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar | ||||||
|     return {program->handle, base_bindings}; |     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<LockerVariant>(); | ||||||
|  |         new_variant->locker = MakeLocker(system, program_type); | ||||||
|  |         curr_variant = new_variant.get(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, | ||||||
|                                             const ConstBufferLocker& locker) const { |                                             const ConstBufferLocker& locker) const { | ||||||
|     ShaderDiskCacheUsage usage; |     ShaderDiskCacheUsage usage; | ||||||
|  | @ -475,21 +533,11 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (!shader) { |             if (!shader) { | ||||||
|                 ConstBufferLocker locker(GetEnginesShaderType(unspecialized.program_type)); |                 auto locker{MakeLocker(system, unspecialized.program_type)}; | ||||||
|                 for (const auto& key : usage.keys) { |                 FillLocker(*locker, usage); | ||||||
|                     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); |  | ||||||
|                 } |  | ||||||
|                 shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, |                 shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, | ||||||
|                                      unspecialized.code, unspecialized.code_b, usage.variant, |                                      unspecialized.code, unspecialized.code_b, usage.variant, | ||||||
|                                      locker, true); |                                      *locker, true); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::scoped_lock lock{mutex}; |             std::scoped_lock lock{mutex}; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | #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_decompiler.h" | ||||||
| #include "video_core/renderer_opengl/gl_shader_disk_cache.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" | #include "video_core/shader/shader_ir.h" | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
|  | @ -31,10 +32,6 @@ namespace Core::Frontend { | ||||||
| class EmuWindow; | class EmuWindow; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace VideoCommon::Shader { |  | ||||||
| class ConstBufferLocker; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
| class CachedShader; | class CachedShader; | ||||||
|  | @ -92,10 +89,17 @@ public: | ||||||
|     std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant); |     std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     struct LockerVariant { | ||||||
|  |         std::unique_ptr<VideoCommon::Shader::ConstBufferLocker> locker; | ||||||
|  |         std::unordered_map<ProgramVariant, CachedProgram> programs; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     explicit CachedShader(const ShaderParameters& params, ProgramType program_type, |     explicit CachedShader(const ShaderParameters& params, ProgramType program_type, | ||||||
|                           GLShader::ShaderEntries entries, ProgramCode program_code, |                           GLShader::ShaderEntries entries, ProgramCode program_code, | ||||||
|                           ProgramCode program_code_b); |                           ProgramCode program_code_b); | ||||||
| 
 | 
 | ||||||
|  |     void UpdateVariant(); | ||||||
|  | 
 | ||||||
|     ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, |     ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, | ||||||
|                                   const VideoCommon::Shader::ConstBufferLocker& locker) const; |                                   const VideoCommon::Shader::ConstBufferLocker& locker) const; | ||||||
| 
 | 
 | ||||||
|  | @ -113,7 +117,8 @@ private: | ||||||
|     ProgramCode program_code; |     ProgramCode program_code; | ||||||
|     ProgramCode program_code_b; |     ProgramCode program_code_b; | ||||||
| 
 | 
 | ||||||
|     std::unordered_map<ProgramVariant, CachedProgram> programs; |     LockerVariant* curr_variant = nullptr; | ||||||
|  |     std::vector<std::unique_ptr<LockerVariant>> locker_variants; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class ShaderCacheOpenGL final : public RasterizerCache<Shader> { | class ShaderCacheOpenGL final : public RasterizerCache<Shader> { | ||||||
|  |  | ||||||
|  | @ -82,23 +82,27 @@ bool ConstBufferLocker::IsConsistent() const { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     return std::all_of(keys.begin(), keys.end(), |     return std::all_of(keys.begin(), keys.end(), | ||||||
|                        [](const auto& key) { |                        [this](const auto& pair) { | ||||||
|                            const auto [value, other_value] = key.first; |                            const auto [cbuf, offset] = pair.first; | ||||||
|                            return value == other_value; |                            const auto value = pair.second; | ||||||
|  |                            return value == engine->AccessConstBuffer32(stage, cbuf, offset); | ||||||
|                        }) && |                        }) && | ||||||
|            std::all_of(bound_samplers.begin(), bound_samplers.end(), |            std::all_of(bound_samplers.begin(), bound_samplers.end(), | ||||||
|                        [this](const auto& sampler) { |                        [this](const auto& sampler) { | ||||||
|                            const auto [key, value] = sampler; |                            const auto [key, value] = sampler; | ||||||
|                            const auto other_value = engine->AccessBoundSampler(stage, key); |                            return value == engine->AccessBoundSampler(stage, key); | ||||||
|                            return value == other_value; |  | ||||||
|                        }) && |                        }) && | ||||||
|            std::all_of( |            std::all_of(bindless_samplers.begin(), bindless_samplers.end(), | ||||||
|                bindless_samplers.begin(), bindless_samplers.end(), [this](const auto& sampler) { |                        [this](const auto& sampler) { | ||||||
|                            const auto [cbuf, offset] = sampler.first; |                            const auto [cbuf, offset] = sampler.first; | ||||||
|                            const auto value = sampler.second; |                            const auto value = sampler.second; | ||||||
|                    const auto other_value = engine->AccessBindlessSampler(stage, cbuf, offset); |                            return value == engine->AccessBindlessSampler(stage, cbuf, offset); | ||||||
|                    return value == other_value; |  | ||||||
|                        }); |                        }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool ConstBufferLocker::HasEqualKeys(const ConstBufferLocker& rhs) const { | ||||||
|  |     return keys == rhs.keys && bound_samplers == rhs.bound_samplers && | ||||||
|  |            bindless_samplers == rhs.bindless_samplers; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace VideoCommon::Shader
 | } // namespace VideoCommon::Shader
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,9 @@ public: | ||||||
|     /// the same value, false otherwise;
 |     /// the same value, false otherwise;
 | ||||||
|     bool IsConsistent() const; |     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.
 |     /// Gives an getter to the const buffer keys in the database.
 | ||||||
|     const KeyMap& GetKeys() const { |     const KeyMap& GetKeys() const { | ||||||
|         return keys; |         return keys; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 ReinUsesLisp
						ReinUsesLisp