mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Only load precompiled shaders if their sanitize_mul setting matches
This commit is contained in:
		
							parent
							
								
									6945b6539f
								
							
						
					
					
						commit
						cf4125a6a5
					
				
					 8 changed files with 85 additions and 50 deletions
				
			
		|  | @ -557,7 +557,7 @@ std::optional<std::string> GetCurrentDir() { | ||||||
| #endif | #endif | ||||||
|     free(dir); |     free(dir); | ||||||
|     return strDir; |     return strDir; | ||||||
| } | } // namespace FileUtil
 | ||||||
| 
 | 
 | ||||||
| bool SetCurrentDir(const std::string& directory) { | bool SetCurrentDir(const std::string& directory) { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  |  | ||||||
|  | @ -889,16 +889,17 @@ bool exec_shader(); | ||||||
| )"; | )"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::optional<std::string> DecompileProgram(const Pica::Shader::ProgramCode& program_code, | std::optional<ProgramResult> DecompileProgram(const Pica::Shader::ProgramCode& program_code, | ||||||
|                                             const Pica::Shader::SwizzleData& swizzle_data, |                                               const Pica::Shader::SwizzleData& swizzle_data, | ||||||
|                                             u32 main_offset, const RegGetter& inputreg_getter, |                                               u32 main_offset, const RegGetter& inputreg_getter, | ||||||
|                                             const RegGetter& outputreg_getter, bool sanitize_mul) { |                                               const RegGetter& outputreg_getter, | ||||||
|  |                                               bool sanitize_mul) { | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|         auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines(); |         auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines(); | ||||||
|         GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset, |         GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset, | ||||||
|                                 inputreg_getter, outputreg_getter, sanitize_mul); |                                 inputreg_getter, outputreg_getter, sanitize_mul); | ||||||
|         return generator.MoveShaderCode(); |         return {ProgramResult{generator.MoveShaderCode()}}; | ||||||
|     } catch (const DecompileFail& exception) { |     } catch (const DecompileFail& exception) { | ||||||
|         LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what()); |         LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what()); | ||||||
|         return {}; |         return {}; | ||||||
|  |  | ||||||
|  | @ -12,7 +12,10 @@ | ||||||
| namespace OpenGL::ShaderDecompiler { | namespace OpenGL::ShaderDecompiler { | ||||||
| 
 | 
 | ||||||
| using RegGetter = std::function<std::string(u32)>; | using RegGetter = std::function<std::string(u32)>; | ||||||
| using ProgramResult = std::string; | 
 | ||||||
|  | struct ProgramResult { | ||||||
|  |     std::string code; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| std::string GetCommonDeclarations(); | std::string GetCommonDeclarations(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -270,6 +270,12 @@ ShaderDiskCache::LoadPrecompiledFile(FileUtil::IOFile& file) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::optional<ShaderDiskCacheDecompiled> ShaderDiskCache::LoadDecompiledEntry() { | std::optional<ShaderDiskCacheDecompiled> ShaderDiskCache::LoadDecompiledEntry() { | ||||||
|  | 
 | ||||||
|  |     bool sanitize_mul; | ||||||
|  |     if (!LoadObjectFromPrecompiled(sanitize_mul)) { | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     u32 code_size{}; |     u32 code_size{}; | ||||||
|     if (!LoadObjectFromPrecompiled(code_size)) { |     if (!LoadObjectFromPrecompiled(code_size)) { | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -281,17 +287,19 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCache::LoadDecompiledEntry() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ShaderDiskCacheDecompiled entry; |     ShaderDiskCacheDecompiled entry; | ||||||
|     entry.code = std::move(code); |     entry.result.code = std::move(code); | ||||||
|  |     entry.sanitize_mul = sanitize_mul; | ||||||
| 
 | 
 | ||||||
|     return entry; |     return entry; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ShaderDiskCache::SaveDecompiledFile(u64 unique_identifier, | bool ShaderDiskCache::SaveDecompiledFile(u64 unique_identifier, | ||||||
|                                          const ShaderDecompiler::ProgramResult& code) { |                                          const ShaderDecompiler::ProgramResult& result, | ||||||
|  |                                          bool sanitize_mul) { | ||||||
|     if (!SaveObjectToPrecompiled(static_cast<u32>(PrecompiledEntryKind::Decompiled)) || |     if (!SaveObjectToPrecompiled(static_cast<u32>(PrecompiledEntryKind::Decompiled)) || | ||||||
|         !SaveObjectToPrecompiled(unique_identifier) || |         !SaveObjectToPrecompiled(unique_identifier) || !SaveObjectToPrecompiled(sanitize_mul) || | ||||||
|         !SaveObjectToPrecompiled(static_cast<u32>(code.size())) || |         !SaveObjectToPrecompiled(static_cast<u32>(result.code.size())) || | ||||||
|         !SaveArrayToPrecompiled(code.data(), code.size())) { |         !SaveArrayToPrecompiled(result.code.data(), result.code.size())) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -338,7 +346,8 @@ void ShaderDiskCache::SaveRaw(const ShaderDiskCacheRaw& entry) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ShaderDiskCache::SaveDecompiled(u64 unique_identifier, | void ShaderDiskCache::SaveDecompiled(u64 unique_identifier, | ||||||
|                                      const ShaderDecompiler::ProgramResult& code) { |                                      const ShaderDecompiler::ProgramResult& code, | ||||||
|  |                                      bool sanitize_mul) { | ||||||
|     if (!IsUsable()) |     if (!IsUsable()) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|  | @ -346,7 +355,7 @@ void ShaderDiskCache::SaveDecompiled(u64 unique_identifier, | ||||||
|         SavePrecompiledHeaderToVirtualPrecompiledCache(); |         SavePrecompiledHeaderToVirtualPrecompiledCache(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!SaveDecompiledFile(unique_identifier, code)) { |     if (!SaveDecompiledFile(unique_identifier, code, sanitize_mul)) { | ||||||
|         LOG_ERROR(Render_OpenGL, |         LOG_ERROR(Render_OpenGL, | ||||||
|                   "Failed to save decompiled entry to the precompiled file - removing"); |                   "Failed to save decompiled entry to the precompiled file - removing"); | ||||||
|         InvalidatePrecompiled(); |         InvalidatePrecompiled(); | ||||||
|  |  | ||||||
|  | @ -78,7 +78,8 @@ private: | ||||||
| 
 | 
 | ||||||
| /// Contains decompiled data from a shader
 | /// Contains decompiled data from a shader
 | ||||||
| struct ShaderDiskCacheDecompiled { | struct ShaderDiskCacheDecompiled { | ||||||
|     ShaderDecompiler::ProgramResult code; |     ShaderDecompiler::ProgramResult result; | ||||||
|  |     bool sanitize_mul; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Contains an OpenGL dumped binary program
 | /// Contains an OpenGL dumped binary program
 | ||||||
|  | @ -108,7 +109,8 @@ public: | ||||||
|     void SaveRaw(const ShaderDiskCacheRaw& entry); |     void SaveRaw(const ShaderDiskCacheRaw& entry); | ||||||
| 
 | 
 | ||||||
|     /// Saves a decompiled entry to the precompiled file. Does not check for collisions.
 |     /// Saves a decompiled entry to the precompiled file. Does not check for collisions.
 | ||||||
|     void SaveDecompiled(u64 unique_identifier, const ShaderDecompiler::ProgramResult& code); |     void SaveDecompiled(u64 unique_identifier, const ShaderDecompiler::ProgramResult& code, | ||||||
|  |                         bool sanitize_mul); | ||||||
| 
 | 
 | ||||||
|     /// Saves a dump entry to the precompiled file. Does not check for collisions.
 |     /// Saves a dump entry to the precompiled file. Does not check for collisions.
 | ||||||
|     void SaveDump(u64 unique_identifier, GLuint program); |     void SaveDump(u64 unique_identifier, GLuint program); | ||||||
|  | @ -126,7 +128,8 @@ private: | ||||||
|     std::optional<ShaderDiskCacheDecompiled> LoadDecompiledEntry(); |     std::optional<ShaderDiskCacheDecompiled> LoadDecompiledEntry(); | ||||||
| 
 | 
 | ||||||
|     /// Saves a decompiled entry to the passed file. Returns true on success.
 |     /// Saves a decompiled entry to the passed file. Returns true on success.
 | ||||||
|     bool SaveDecompiledFile(u64 unique_identifier, const ShaderDecompiler::ProgramResult& code); |     bool SaveDecompiledFile(u64 unique_identifier, const ShaderDecompiler::ProgramResult& code, | ||||||
|  |                             bool sanitize_mul); | ||||||
| 
 | 
 | ||||||
|     /// Returns if the cache can be used
 |     /// Returns if the cache can be used
 | ||||||
|     bool IsUsable() const; |     bool IsUsable() const; | ||||||
|  |  | ||||||
|  | @ -1231,7 +1231,8 @@ float ProcTexNoiseCoef(vec2 x) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_shader) { | ShaderDecompiler::ProgramResult GenerateFragmentShader(const PicaFSConfig& config, | ||||||
|  |                                                        bool separable_shader) { | ||||||
|     const auto& state = config.state; |     const auto& state = config.state; | ||||||
| 
 | 
 | ||||||
|     std::string out = R"( |     std::string out = R"( | ||||||
|  | @ -1482,7 +1483,7 @@ vec4 secondary_fragment_color = vec4(0.0); | ||||||
|     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 |     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 | ||||||
|     if (state.alpha_test_func == FramebufferRegs::CompareFunc::Never) { |     if (state.alpha_test_func == FramebufferRegs::CompareFunc::Never) { | ||||||
|         out += "discard; }"; |         out += "discard; }"; | ||||||
|         return out; |         return {out}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Append the scissor test
 |     // Append the scissor test
 | ||||||
|  | @ -1546,7 +1547,7 @@ vec4 secondary_fragment_color = vec4(0.0); | ||||||
|                                                                 "VideoCore_Pica_UseGasMode", true); |                                                                 "VideoCore_Pica_UseGasMode", true); | ||||||
|         LOG_CRITICAL(Render_OpenGL, "Unimplemented gas mode"); |         LOG_CRITICAL(Render_OpenGL, "Unimplemented gas mode"); | ||||||
|         out += "discard; }"; |         out += "discard; }"; | ||||||
|         return out; |         return {out}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (state.shadow_rendering) { |     if (state.shadow_rendering) { | ||||||
|  | @ -1584,10 +1585,10 @@ do { | ||||||
| 
 | 
 | ||||||
|     out += "}"; |     out += "}"; | ||||||
| 
 | 
 | ||||||
|     return out; |     return {out}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string GenerateTrivialVertexShader(bool separable_shader) { | ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader) { | ||||||
|     std::string out = ""; |     std::string out = ""; | ||||||
|     if (separable_shader) { |     if (separable_shader) { | ||||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; |         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||||
|  | @ -1630,11 +1631,11 @@ void main() { | ||||||
| } | } | ||||||
| )"; | )"; | ||||||
| 
 | 
 | ||||||
|     return out; |     return {out}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup, | std::optional<ShaderDecompiler::ProgramResult> GenerateVertexShader( | ||||||
|                                                 const PicaVSConfig& config, bool separable_shader) { |     const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config, bool separable_shader) { | ||||||
|     std::string out = ""; |     std::string out = ""; | ||||||
|     if (separable_shader) { |     if (separable_shader) { | ||||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n"; |         out += "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||||
|  | @ -1664,7 +1665,7 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& | ||||||
|     if (!program_source_opt) |     if (!program_source_opt) | ||||||
|         return {}; |         return {}; | ||||||
| 
 | 
 | ||||||
|     std::string& program_source = *program_source_opt; |     std::string& program_source = program_source_opt->code; | ||||||
| 
 | 
 | ||||||
|     out += R"( |     out += R"( | ||||||
| #define uniforms vs_uniforms | #define uniforms vs_uniforms | ||||||
|  | @ -1696,7 +1697,7 @@ layout (std140) uniform vs_config { | ||||||
| 
 | 
 | ||||||
|     out += program_source; |     out += program_source; | ||||||
| 
 | 
 | ||||||
|     return out; |     return {{out}}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool separable_shader) { | static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool separable_shader) { | ||||||
|  | @ -1784,7 +1785,8 @@ void EmitPrim(Vertex vtx0, Vertex vtx1, Vertex vtx2) { | ||||||
|     return out; |     return out; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader) { | ShaderDecompiler::ProgramResult GenerateFixedGeometryShader(const PicaFixedGSConfig& config, | ||||||
|  |                                                             bool separable_shader) { | ||||||
|     std::string out = ""; |     std::string out = ""; | ||||||
|     if (separable_shader) { |     if (separable_shader) { | ||||||
|         out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; |         out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; | ||||||
|  | @ -1814,6 +1816,6 @@ void main() { | ||||||
|     out += "    EmitPrim(prim_buffer[0], prim_buffer[1], prim_buffer[2]);\n"; |     out += "    EmitPrim(prim_buffer[0], prim_buffer[1], prim_buffer[2]);\n"; | ||||||
|     out += "}\n"; |     out += "}\n"; | ||||||
| 
 | 
 | ||||||
|     return out; |     return {out}; | ||||||
| } | } | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,10 @@ | ||||||
| 
 | 
 | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
|  | namespace ShaderDecompiler { | ||||||
|  | struct ProgramResult; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| enum class ProgramType : u32 { VS, GS, FS }; | enum class ProgramType : u32 { VS, GS, FS }; | ||||||
| 
 | 
 | ||||||
| enum Attributes { | enum Attributes { | ||||||
|  | @ -202,20 +206,21 @@ struct PicaFixedGSConfig : Common::HashableStruct<PicaGSConfigCommonRaw> { | ||||||
|  * @param separable_shader generates shader that can be used for separate shader object |  * @param separable_shader generates shader that can be used for separate shader object | ||||||
|  * @returns String of the shader source code |  * @returns String of the shader source code | ||||||
|  */ |  */ | ||||||
| std::string GenerateTrivialVertexShader(bool separable_shader); | ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Generates the GLSL vertex shader program source code for the given VS program |  * Generates the GLSL vertex shader program source code for the given VS program | ||||||
|  * @returns String of the shader source code; boost::none on failure |  * @returns String of the shader source code; boost::none on failure | ||||||
|  */ |  */ | ||||||
| std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup, | std::optional<ShaderDecompiler::ProgramResult> GenerateVertexShader( | ||||||
|                                                 const PicaVSConfig& config, bool separable_shader); |     const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config, bool separable_shader); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Generates the GLSL fixed geometry shader program source code for non-GS PICA pipeline |  * Generates the GLSL fixed geometry shader program source code for non-GS PICA pipeline | ||||||
|  * @returns String of the shader source code |  * @returns String of the shader source code | ||||||
|  */ |  */ | ||||||
| std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader); | ShaderDecompiler::ProgramResult GenerateFixedGeometryShader(const PicaFixedGSConfig& config, | ||||||
|  |                                                             bool separable_shader); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Generates the GLSL fragment shader program source code for the current Pica state |  * Generates the GLSL fragment shader program source code for the current Pica state | ||||||
|  | @ -224,7 +229,8 @@ std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool se | ||||||
|  * @param separable_shader generates shader that can be used for separate shader object |  * @param separable_shader generates shader that can be used for separate shader object | ||||||
|  * @returns String of the shader source code |  * @returns String of the shader source code | ||||||
|  */ |  */ | ||||||
| std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_shader); | ShaderDecompiler::ProgramResult GenerateFragmentShader(const PicaFSConfig& config, | ||||||
|  |                                                        bool separable_shader); | ||||||
| 
 | 
 | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,18 +10,19 @@ | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | ||||||
| #include "video_core/renderer_opengl/gl_shader_manager.h" | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||||
|  | #include "video_core/video_core.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
| static u64 GetUniqueIdentifier(const Pica::Regs& regs, const ProgramCode& code) { | static u64 GetUniqueIdentifier(const Pica::Regs& regs, const ProgramCode& code) { | ||||||
|     u64 hash = 0; |     std::size_t hash = 0; | ||||||
|     u64 regs_uid = Common::ComputeHash64(regs.reg_array.data(), Pica::Regs::NUM_REGS * sizeof(u32)); |     u64 regs_uid = Common::ComputeHash64(regs.reg_array.data(), Pica::Regs::NUM_REGS * sizeof(u32)); | ||||||
|     boost::hash_combine(hash, regs_uid); |     boost::hash_combine(hash, regs_uid); | ||||||
|     if (code.size() > 0) { |     if (code.size() > 0) { | ||||||
|         u64 code_uid = Common::ComputeHash64(code.data(), code.size() * sizeof(u32)); |         u64 code_uid = Common::ComputeHash64(code.data(), code.size() * sizeof(u32)); | ||||||
|         boost::hash_combine(hash, code_uid); |         boost::hash_combine(hash, code_uid); | ||||||
|     } |     } | ||||||
|     return hash; |     return static_cast<u64>(hash); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static OGLProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, | static OGLProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, | ||||||
|  | @ -200,7 +201,7 @@ private: | ||||||
| class TrivialVertexShader { | class TrivialVertexShader { | ||||||
| public: | public: | ||||||
|     explicit TrivialVertexShader(bool separable) : program(separable) { |     explicit TrivialVertexShader(bool separable) : program(separable) { | ||||||
|         program.Create(GenerateTrivialVertexShader(separable).c_str(), GL_VERTEX_SHADER); |         program.Create(GenerateTrivialVertexShader(separable).code.c_str(), GL_VERTEX_SHADER); | ||||||
|     } |     } | ||||||
|     GLuint Get() const { |     GLuint Get() const { | ||||||
|         return program.GetHandle(); |         return program.GetHandle(); | ||||||
|  | @ -210,7 +211,8 @@ private: | ||||||
|     OGLShaderStage program; |     OGLShaderStage program; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <typename KeyConfigType, std::string (*CodeGenerator)(const KeyConfigType&, bool), | template <typename KeyConfigType, | ||||||
|  |           ShaderDecompiler::ProgramResult (*CodeGenerator)(const KeyConfigType&, bool), | ||||||
|           GLenum ShaderType> |           GLenum ShaderType> | ||||||
| class ShaderCache { | class ShaderCache { | ||||||
| public: | public: | ||||||
|  | @ -222,7 +224,7 @@ public: | ||||||
|         std::optional<ShaderDecompiler::ProgramResult> result{}; |         std::optional<ShaderDecompiler::ProgramResult> result{}; | ||||||
|         if (new_shader) { |         if (new_shader) { | ||||||
|             result = CodeGenerator(config, separable); |             result = CodeGenerator(config, separable); | ||||||
|             cached_shader.Create(result->c_str(), ShaderType); |             cached_shader.Create(result->code.c_str(), ShaderType); | ||||||
|         } |         } | ||||||
|         return {cached_shader.GetHandle(), result}; |         return {cached_shader.GetHandle(), result}; | ||||||
|     } |     } | ||||||
|  | @ -244,8 +246,8 @@ private: | ||||||
| // program buffer from the previous shader, which is hashed into the config, resulting several
 | // program buffer from the previous shader, which is hashed into the config, resulting several
 | ||||||
| // different config values from the same shader program.
 | // different config values from the same shader program.
 | ||||||
| template <typename KeyConfigType, | template <typename KeyConfigType, | ||||||
|           std::optional<std::string> (*CodeGenerator)(const Pica::Shader::ShaderSetup&, |           std::optional<ShaderDecompiler::ProgramResult> (*CodeGenerator)( | ||||||
|                                                       const KeyConfigType&, bool), |               const Pica::Shader::ShaderSetup&, const KeyConfigType&, bool), | ||||||
|           GLenum ShaderType> |           GLenum ShaderType> | ||||||
| class ShaderDoubleCache { | class ShaderDoubleCache { | ||||||
| public: | public: | ||||||
|  | @ -261,11 +263,11 @@ public: | ||||||
|                 return {0, {}}; |                 return {0, {}}; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string& program = *program_opt; |             std::string& program = program_opt->code; | ||||||
|             auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{separable}); |             auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{separable}); | ||||||
|             OGLShaderStage& cached_shader = iter->second; |             OGLShaderStage& cached_shader = iter->second; | ||||||
|             if (new_shader) { |             if (new_shader) { | ||||||
|                 result = program; |                 result->code = program; | ||||||
|                 cached_shader.Create(program.c_str(), ShaderType); |                 cached_shader.Create(program.c_str(), ShaderType); | ||||||
|             } |             } | ||||||
|             shader_map[key] = &cached_shader; |             shader_map[key] = &cached_shader; | ||||||
|  | @ -336,6 +338,7 @@ public: | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     bool is_amd; |     bool is_amd; | ||||||
|  |     bool separable; | ||||||
| 
 | 
 | ||||||
|     ShaderTuple current; |     ShaderTuple current; | ||||||
| 
 | 
 | ||||||
|  | @ -345,8 +348,6 @@ public: | ||||||
|     FixedGeometryShaders fixed_geometry_shaders; |     FixedGeometryShaders fixed_geometry_shaders; | ||||||
| 
 | 
 | ||||||
|     FragmentShaders fragment_shaders; |     FragmentShaders fragment_shaders; | ||||||
| 
 |  | ||||||
|     bool separable; |  | ||||||
|     std::unordered_map<ShaderTuple, OGLProgram, ShaderTuple::Hash> program_cache; |     std::unordered_map<ShaderTuple, OGLProgram, ShaderTuple::Hash> program_cache; | ||||||
|     OGLPipeline pipeline; |     OGLPipeline pipeline; | ||||||
|     ShaderDiskCache disk_cache; |     ShaderDiskCache disk_cache; | ||||||
|  | @ -401,7 +402,7 @@ void ShaderProgramManager::UseFragmentShader(const Pica::Regs& regs) { | ||||||
|         u64 unique_identifier = GetUniqueIdentifier(regs, {}); |         u64 unique_identifier = GetUniqueIdentifier(regs, {}); | ||||||
|         ShaderDiskCacheRaw raw{unique_identifier, ProgramType::FS, regs, {}}; |         ShaderDiskCacheRaw raw{unique_identifier, ProgramType::FS, regs, {}}; | ||||||
|         disk_cache.SaveRaw(raw); |         disk_cache.SaveRaw(raw); | ||||||
|         disk_cache.SaveDecompiled(unique_identifier, *result); |         disk_cache.SaveDecompiled(unique_identifier, *result, false); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -489,6 +490,12 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
| 
 | 
 | ||||||
|                 const auto dump{dumps.find(unique_identifier)}; |                 const auto dump{dumps.find(unique_identifier)}; | ||||||
|                 const auto decomp{decompiled.find(unique_identifier)}; |                 const auto decomp{decompiled.find(unique_identifier)}; | ||||||
|  | 
 | ||||||
|  |                 // Only load this shader if its sanitize_mul setting matches
 | ||||||
|  |                 if (decomp->second.sanitize_mul == VideoCore::g_hw_shader_accurate_mul) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 OGLProgram shader; |                 OGLProgram shader; | ||||||
| 
 | 
 | ||||||
|                 if (dump != dumps.end() && decomp != decompiled.end()) { |                 if (dump != dumps.end() && decomp != decompiled.end()) { | ||||||
|  | @ -505,12 +512,14 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|                     if (raw.GetProgramType() == ProgramType::VS) { |                     if (raw.GetProgramType() == ProgramType::VS) { | ||||||
|                         auto [conf, setup] = BuildVSConfigFromRaw(raw); |                         auto [conf, setup] = BuildVSConfigFromRaw(raw); | ||||||
|                         std::scoped_lock lock(mutex); |                         std::scoped_lock lock(mutex); | ||||||
|                         impl->programmable_vertex_shaders.Inject(conf, decomp->second.code, | 
 | ||||||
|  |                         impl->programmable_vertex_shaders.Inject(conf, decomp->second.result.code, | ||||||
|                                                                  std::move(shader)); |                                                                  std::move(shader)); | ||||||
|                     } else if (raw.GetProgramType() == ProgramType::FS) { |                     } else if (raw.GetProgramType() == ProgramType::FS) { | ||||||
|                         PicaFSConfig conf = PicaFSConfig::BuildFromRegs(raw.GetRawShaderConfig()); |                         PicaFSConfig conf = PicaFSConfig::BuildFromRegs(raw.GetRawShaderConfig()); | ||||||
|                         std::scoped_lock lock(mutex); |                         std::scoped_lock lock(mutex); | ||||||
|                         impl->fragment_shaders.Inject(conf, decomp->second.code, std::move(shader)); |                         impl->fragment_shaders.Inject(conf, decomp->second.result.code, | ||||||
|  |                                                       std::move(shader)); | ||||||
|                     } else { |                     } else { | ||||||
|                         // Unsupported shader type got stored somehow so nuke the cache
 |                         // Unsupported shader type got stored somehow so nuke the cache
 | ||||||
| 
 | 
 | ||||||
|  | @ -554,6 +563,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|             const auto& raw{raws[i]}; |             const auto& raw{raws[i]}; | ||||||
|             const u64 unique_identifier{raw.GetUniqueIdentifier()}; |             const u64 unique_identifier{raw.GetUniqueIdentifier()}; | ||||||
| 
 | 
 | ||||||
|  |             bool sanitize_mul = false; | ||||||
|             GLuint handle{0}; |             GLuint handle{0}; | ||||||
|             std::optional<ShaderDecompiler::ProgramResult> result; |             std::optional<ShaderDecompiler::ProgramResult> result; | ||||||
|             // Otherwise decompile and build the shader at boot and save the result to the
 |             // Otherwise decompile and build the shader at boot and save the result to the
 | ||||||
|  | @ -566,6 +576,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|                 auto [h, r] = impl->programmable_vertex_shaders.Get(conf, setup); |                 auto [h, r] = impl->programmable_vertex_shaders.Get(conf, setup); | ||||||
|                 handle = h; |                 handle = h; | ||||||
|                 result = r; |                 result = r; | ||||||
|  |                 sanitize_mul = conf.state.sanitize_mul; | ||||||
|             } else if (raw.GetProgramType() == ProgramType::FS) { |             } else if (raw.GetProgramType() == ProgramType::FS) { | ||||||
|                 PicaFSConfig conf = PicaFSConfig::BuildFromRegs(raw.GetRawShaderConfig()); |                 PicaFSConfig conf = PicaFSConfig::BuildFromRegs(raw.GetRawShaderConfig()); | ||||||
|                 std::scoped_lock lock(mutex); |                 std::scoped_lock lock(mutex); | ||||||
|  | @ -587,7 +598,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|             } |             } | ||||||
|             // If this is a new shader, add it the precompiled cache
 |             // If this is a new shader, add it the precompiled cache
 | ||||||
|             if (result) { |             if (result) { | ||||||
|                 disk_cache.SaveDecompiled(unique_identifier, *result); |                 disk_cache.SaveDecompiled(unique_identifier, *result, sanitize_mul); | ||||||
|                 disk_cache.SaveDump(unique_identifier, handle); |                 disk_cache.SaveDump(unique_identifier, handle); | ||||||
|                 precompiled_cache_altered = true; |                 precompiled_cache_altered = true; | ||||||
|             } |             } | ||||||
|  | @ -607,6 +618,6 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, | ||||||
|     if (precompiled_cache_altered) { |     if (precompiled_cache_altered) { | ||||||
|         disk_cache.SaveVirtualPrecompiledFile(); |         disk_cache.SaveVirtualPrecompiledFile(); | ||||||
|     } |     } | ||||||
| } | } // namespace OpenGL
 | ||||||
| 
 | 
 | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue