diff options
| author | 2019-01-15 01:07:57 -0300 | |
|---|---|---|
| committer | 2019-02-06 22:23:39 -0300 | |
| commit | cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b (patch) | |
| tree | 1ba7045068bc52438b1e40548597c4f4cec62120 /src | |
| parent | settings: Hide shader cache behind a setting (diff) | |
| download | yuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.tar.gz yuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.tar.xz yuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.zip | |
gl_shader_disk_cache: Save GLSL and entries into the precompiled file
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 71 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.h | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 65 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 177 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 21 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 2 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 9 |
9 files changed, 234 insertions, 135 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 18aafe767..48e003fa1 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -1009,22 +1009,20 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 1009 | 1009 | ||
| 1010 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | 1010 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { |
| 1011 | const auto& entry = entries[bindpoint]; | 1011 | const auto& entry = entries[bindpoint]; |
| 1012 | const auto texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); | ||
| 1012 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; | 1013 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; |
| 1013 | auto& unit = state.texture_units[current_bindpoint]; | ||
| 1014 | |||
| 1015 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); | ||
| 1016 | 1014 | ||
| 1017 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 1015 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); |
| 1018 | 1016 | ||
| 1019 | Surface surface = res_cache.GetTextureSurface(texture, entry); | 1017 | Surface surface = res_cache.GetTextureSurface(texture, entry); |
| 1020 | if (surface != nullptr) { | 1018 | if (surface != nullptr) { |
| 1021 | unit.texture = | 1019 | state.texture_units[current_bindpoint].texture = |
| 1022 | entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; | 1020 | entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; |
| 1023 | surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, | 1021 | surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, |
| 1024 | texture.tic.w_source); | 1022 | texture.tic.w_source); |
| 1025 | } else { | 1023 | } else { |
| 1026 | // Can occur when texture addr is null or its memory is unmapped/invalid | 1024 | // Can occur when texture addr is null or its memory is unmapped/invalid |
| 1027 | unit.texture = 0; | 1025 | state.texture_units[current_bindpoint].texture = 0; |
| 1028 | } | 1026 | } |
| 1029 | } | 1027 | } |
| 1030 | } | 1028 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index a70ff79d0..761b355e4 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -143,6 +143,8 @@ GLShader::ProgramResult CreateProgram(Maxwell::ShaderProgram program_type, Progr | |||
| 143 | // stage here. | 143 | // stage here. |
| 144 | setup.SetProgramB(std::move(program_code_b)); | 144 | setup.SetProgramB(std::move(program_code_b)); |
| 145 | } | 145 | } |
| 146 | setup.program.unique_identifier = | ||
| 147 | GetUniqueIdentifier(program_type, program_code, program_code_b); | ||
| 146 | 148 | ||
| 147 | switch (program_type) { | 149 | switch (program_type) { |
| 148 | case Maxwell::ShaderProgram::VertexA: | 150 | case Maxwell::ShaderProgram::VertexA: |
| @@ -348,15 +350,12 @@ void ShaderCacheOpenGL::LoadDiskCache() { | |||
| 348 | return; | 350 | return; |
| 349 | } | 351 | } |
| 350 | 352 | ||
| 351 | std::vector<ShaderDiskCachePrecompiledEntry> precompiled = disk_cache.LoadPrecompiled(); | 353 | std::map<u64, ShaderDiskCacheDecompiled> decompiled; |
| 352 | const auto SearchPrecompiled = [&precompiled](const ShaderDiskCacheUsage& usage) { | 354 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; |
| 353 | return std::find_if( | 355 | disk_cache.LoadPrecompiled(decompiled, dumps); |
| 354 | precompiled.begin(), precompiled.end(), | ||
| 355 | [&usage](const auto& precompiled_entry) { return precompiled_entry.usage == usage; }); | ||
| 356 | }; | ||
| 357 | 356 | ||
| 358 | const std::set<GLenum> supported_formats{GetSupportedFormats()}; | 357 | const std::set<GLenum> supported_formats{GetSupportedFormats()}; |
| 359 | const auto unspecialized{GenerateUnspecializedShaders(raws)}; | 358 | const auto unspecialized{GenerateUnspecializedShaders(raws, decompiled)}; |
| 360 | 359 | ||
| 361 | // Build shaders | 360 | // Build shaders |
| 362 | for (std::size_t i = 0; i < usages.size(); ++i) { | 361 | for (std::size_t i = 0; i < usages.size(); ++i) { |
| @@ -365,13 +364,17 @@ void ShaderCacheOpenGL::LoadDiskCache() { | |||
| 365 | i + 1, usages.size()); | 364 | i + 1, usages.size()); |
| 366 | 365 | ||
| 367 | const auto& unspec{unspecialized.at(usage.unique_identifier)}; | 366 | const auto& unspec{unspecialized.at(usage.unique_identifier)}; |
| 368 | 367 | const auto dump_it = dumps.find(usage); | |
| 369 | const auto precompiled_it = SearchPrecompiled(usage); | ||
| 370 | const bool is_precompiled = precompiled_it != precompiled.end(); | ||
| 371 | 368 | ||
| 372 | CachedProgram shader; | 369 | CachedProgram shader; |
| 373 | if (is_precompiled) { | 370 | if (dump_it != dumps.end()) { |
| 374 | shader = GeneratePrecompiledProgram(precompiled, *precompiled_it, supported_formats); | 371 | // If the shader is dumped, attempt to load it with |
| 372 | shader = GeneratePrecompiledProgram(dump_it->second, supported_formats); | ||
| 373 | if (!shader) { | ||
| 374 | // Invalidate the precompiled cache if a shader dumped shader was rejected | ||
| 375 | disk_cache.InvalidatePrecompiled(); | ||
| 376 | dumps.clear(); | ||
| 377 | } | ||
| 375 | } | 378 | } |
| 376 | if (!shader) { | 379 | if (!shader) { |
| 377 | shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type, | 380 | shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type, |
| @@ -385,52 +388,47 @@ void ShaderCacheOpenGL::LoadDiskCache() { | |||
| 385 | 388 | ||
| 386 | for (std::size_t i = 0; i < usages.size(); ++i) { | 389 | for (std::size_t i = 0; i < usages.size(); ++i) { |
| 387 | const auto& usage{usages[i]}; | 390 | const auto& usage{usages[i]}; |
| 388 | if (SearchPrecompiled(usage) == precompiled.end()) { | 391 | if (dumps.find(usage) == dumps.end()) { |
| 389 | const auto& program = precompiled_programs.at(usage); | 392 | const auto& program = precompiled_programs.at(usage); |
| 390 | disk_cache.SavePrecompiled(usage, program->handle); | 393 | disk_cache.SaveDump(usage, program->handle); |
| 391 | } | 394 | } |
| 392 | } | 395 | } |
| 393 | } | 396 | } |
| 394 | 397 | ||
| 395 | CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( | 398 | CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( |
| 396 | std::vector<ShaderDiskCachePrecompiledEntry>& precompiled, | 399 | const ShaderDiskCacheDump& dump, const std::set<GLenum>& supported_formats) { |
| 397 | const ShaderDiskCachePrecompiledEntry& precompiled_entry, | ||
| 398 | const std::set<GLenum>& supported_formats) { | ||
| 399 | 400 | ||
| 400 | if (supported_formats.find(precompiled_entry.binary_format) == supported_formats.end()) { | 401 | if (supported_formats.find(dump.binary_format) == supported_formats.end()) { |
| 401 | LOG_INFO(Render_OpenGL, "Precompiled cache entry with unsupported format - removing"); | 402 | LOG_INFO(Render_OpenGL, "Precompiled cache entry with unsupported format - removing"); |
| 402 | disk_cache.InvalidatePrecompiled(); | ||
| 403 | precompiled.clear(); | ||
| 404 | return {}; | 403 | return {}; |
| 405 | } | 404 | } |
| 406 | 405 | ||
| 407 | CachedProgram shader = std::make_shared<OGLProgram>(); | 406 | CachedProgram shader = std::make_shared<OGLProgram>(); |
| 408 | shader->handle = glCreateProgram(); | 407 | shader->handle = glCreateProgram(); |
| 409 | glProgramBinary(shader->handle, precompiled_entry.binary_format, | 408 | glProgramBinary(shader->handle, dump.binary_format, dump.binary.data(), |
| 410 | precompiled_entry.binary.data(), | 409 | static_cast<GLsizei>(dump.binary.size())); |
| 411 | static_cast<GLsizei>(precompiled_entry.binary.size())); | ||
| 412 | 410 | ||
| 413 | GLint link_status{}; | 411 | GLint link_status{}; |
| 414 | glGetProgramiv(shader->handle, GL_LINK_STATUS, &link_status); | 412 | glGetProgramiv(shader->handle, GL_LINK_STATUS, &link_status); |
| 415 | if (link_status == GL_FALSE) { | 413 | if (link_status == GL_FALSE) { |
| 416 | LOG_INFO(Render_OpenGL, "Precompiled cache rejected by the driver - removing"); | 414 | LOG_INFO(Render_OpenGL, "Precompiled cache rejected by the driver - removing"); |
| 417 | disk_cache.InvalidatePrecompiled(); | 415 | return {}; |
| 418 | precompiled.clear(); | ||
| 419 | |||
| 420 | shader.reset(); | ||
| 421 | } | 416 | } |
| 422 | 417 | ||
| 423 | return shader; | 418 | return shader; |
| 424 | } | 419 | } |
| 425 | 420 | ||
| 426 | std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShaders( | 421 | std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShaders( |
| 427 | const std::vector<ShaderDiskCacheRaw>& raws) { | 422 | const std::vector<ShaderDiskCacheRaw>& raws, |
| 423 | const std::map<u64, ShaderDiskCacheDecompiled>& decompiled) { | ||
| 428 | 424 | ||
| 429 | std::map<u64, UnspecializedShader> unspecialized; | 425 | std::map<u64, UnspecializedShader> unspecialized; |
| 426 | |||
| 430 | for (const auto& raw : raws) { | 427 | for (const auto& raw : raws) { |
| 428 | const u64 unique_identifier = raw.GetUniqueIdentifier(); | ||
| 431 | const u64 calculated_hash = | 429 | const u64 calculated_hash = |
| 432 | GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); | 430 | GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); |
| 433 | if (raw.GetUniqueIdentifier() != calculated_hash) { | 431 | if (unique_identifier != calculated_hash) { |
| 434 | LOG_ERROR( | 432 | LOG_ERROR( |
| 435 | Render_OpenGL, | 433 | Render_OpenGL, |
| 436 | "Invalid hash in entry={:016x} (obtained hash={:016x}) - removing shader cache", | 434 | "Invalid hash in entry={:016x} (obtained hash={:016x}) - removing shader cache", |
| @@ -439,10 +437,19 @@ std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShade | |||
| 439 | return {}; | 437 | return {}; |
| 440 | } | 438 | } |
| 441 | 439 | ||
| 442 | auto result = | 440 | GLShader::ProgramResult result; |
| 443 | CreateProgram(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); | 441 | if (const auto it = decompiled.find(unique_identifier); it != decompiled.end()) { |
| 442 | // If it's stored in the precompiled file, avoid decompiling it here | ||
| 443 | const auto& stored_decompiled{it->second}; | ||
| 444 | result = {stored_decompiled.code, stored_decompiled.entries}; | ||
| 445 | } else { | ||
| 446 | // Otherwise decompile the shader at boot and save the result to the decompiled file | ||
| 447 | result = | ||
| 448 | CreateProgram(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); | ||
| 449 | disk_cache.SaveDecompiled(unique_identifier, result.first, result.second); | ||
| 450 | } | ||
| 444 | 451 | ||
| 445 | precompiled_shaders.insert({raw.GetUniqueIdentifier(), result}); | 452 | precompiled_shaders.insert({unique_identifier, result}); |
| 446 | 453 | ||
| 447 | unspecialized.insert( | 454 | unspecialized.insert( |
| 448 | {raw.GetUniqueIdentifier(), | 455 | {raw.GetUniqueIdentifier(), |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 763a47bce..3b5a82f8a 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -117,12 +117,11 @@ public: | |||
| 117 | 117 | ||
| 118 | private: | 118 | private: |
| 119 | std::map<u64, UnspecializedShader> GenerateUnspecializedShaders( | 119 | std::map<u64, UnspecializedShader> GenerateUnspecializedShaders( |
| 120 | const std::vector<ShaderDiskCacheRaw>& raws); | 120 | const std::vector<ShaderDiskCacheRaw>& raws, |
| 121 | const std::map<u64, ShaderDiskCacheDecompiled>& decompiled); | ||
| 121 | 122 | ||
| 122 | CachedProgram GeneratePrecompiledProgram( | 123 | CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, |
| 123 | std::vector<ShaderDiskCachePrecompiledEntry>& precompiled, | 124 | const std::set<GLenum>& supported_formats); |
| 124 | const ShaderDiskCachePrecompiledEntry& precompiled_entry, | ||
| 125 | const std::set<GLenum>& supported_formats); | ||
| 126 | 125 | ||
| 127 | std::array<Shader, Maxwell::MaxShaderProgram> last_shaders; | 126 | std::array<Shader, Maxwell::MaxShaderProgram> last_shaders; |
| 128 | 127 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 9184a1287..d84caa6db 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -193,13 +193,14 @@ public: | |||
| 193 | ShaderEntries GetShaderEntries() const { | 193 | ShaderEntries GetShaderEntries() const { |
| 194 | ShaderEntries entries; | 194 | ShaderEntries entries; |
| 195 | for (const auto& cbuf : ir.GetConstantBuffers()) { | 195 | for (const auto& cbuf : ir.GetConstantBuffers()) { |
| 196 | entries.const_buffers.emplace_back(cbuf.second, stage, cbuf.first); | 196 | entries.const_buffers.emplace_back(cbuf.second.GetMaxOffset(), cbuf.second.IsIndirect(), |
| 197 | cbuf.first); | ||
| 197 | } | 198 | } |
| 198 | for (const auto& sampler : ir.GetSamplers()) { | 199 | for (const auto& sampler : ir.GetSamplers()) { |
| 199 | entries.samplers.emplace_back(sampler, stage); | 200 | entries.samplers.emplace_back(sampler); |
| 200 | } | 201 | } |
| 201 | for (const auto& gmem : ir.GetGlobalMemoryBases()) { | 202 | for (const auto& gmem : ir.GetGlobalMemoryBases()) { |
| 202 | entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset, stage); | 203 | entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset); |
| 203 | } | 204 | } |
| 204 | entries.clip_distances = ir.GetClipDistances(); | 205 | entries.clip_distances = ir.GetClipDistances(); |
| 205 | entries.shader_length = ir.GetLength(); | 206 | entries.shader_length = ir.GetLength(); |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 398be13d6..0031cb614 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h | |||
| @@ -23,65 +23,23 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs; | |||
| 23 | 23 | ||
| 24 | class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { | 24 | class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { |
| 25 | public: | 25 | public: |
| 26 | explicit ConstBufferEntry(const VideoCommon::Shader::ConstBuffer& entry, | 26 | explicit ConstBufferEntry(u32 max_offset, bool is_indirect, u32 index) |
| 27 | Maxwell::ShaderStage stage, u32 index) | 27 | : VideoCommon::Shader::ConstBuffer{max_offset, is_indirect}, index{index} {} |
| 28 | : VideoCommon::Shader::ConstBuffer{entry}, stage{stage}, index{index} {} | ||
| 29 | |||
| 30 | Maxwell::ShaderStage GetStage() const { | ||
| 31 | return stage; | ||
| 32 | } | ||
| 33 | 28 | ||
| 34 | u32 GetIndex() const { | 29 | u32 GetIndex() const { |
| 35 | return index; | 30 | return index; |
| 36 | } | 31 | } |
| 37 | 32 | ||
| 38 | private: | 33 | private: |
| 39 | Maxwell::ShaderStage stage{}; | ||
| 40 | u32 index{}; | 34 | u32 index{}; |
| 41 | }; | 35 | }; |
| 42 | 36 | ||
| 43 | class SamplerEntry : public VideoCommon::Shader::Sampler { | 37 | using SamplerEntry = VideoCommon::Shader::Sampler; |
| 44 | public: | ||
| 45 | explicit SamplerEntry(const VideoCommon::Shader::Sampler& entry, Maxwell::ShaderStage stage) | ||
| 46 | : VideoCommon::Shader::Sampler{entry}, stage{stage} {} | ||
| 47 | |||
| 48 | Maxwell::ShaderStage GetStage() const { | ||
| 49 | return stage; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | Maxwell::ShaderStage stage{}; | ||
| 54 | }; | ||
| 55 | |||
| 56 | class GlobalMemoryEntry { | ||
| 57 | public: | ||
| 58 | explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, Maxwell::ShaderStage stage) | ||
| 59 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, stage{stage} {} | ||
| 60 | |||
| 61 | u32 GetCbufIndex() const { | ||
| 62 | return cbuf_index; | ||
| 63 | } | ||
| 64 | |||
| 65 | u32 GetCbufOffset() const { | ||
| 66 | return cbuf_offset; | ||
| 67 | } | ||
| 68 | |||
| 69 | Maxwell::ShaderStage GetStage() const { | ||
| 70 | return stage; | ||
| 71 | } | ||
| 72 | |||
| 73 | private: | ||
| 74 | u32 cbuf_index{}; | ||
| 75 | u32 cbuf_offset{}; | ||
| 76 | Maxwell::ShaderStage stage{}; | ||
| 77 | std::string name; | ||
| 78 | }; | ||
| 79 | 38 | ||
| 80 | class GlobalMemoryEntry { | 39 | class GlobalMemoryEntry { |
| 81 | public: | 40 | public: |
| 82 | explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, Maxwell::ShaderStage stage, | 41 | explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset) |
| 83 | std::string name) | 42 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset} {} |
| 84 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, stage{stage}, name{std::move(name)} {} | ||
| 85 | 43 | ||
| 86 | u32 GetCbufIndex() const { | 44 | u32 GetCbufIndex() const { |
| 87 | return cbuf_index; | 45 | return cbuf_index; |
| @@ -91,22 +49,9 @@ public: | |||
| 91 | return cbuf_offset; | 49 | return cbuf_offset; |
| 92 | } | 50 | } |
| 93 | 51 | ||
| 94 | const std::string& GetName() const { | ||
| 95 | return name; | ||
| 96 | } | ||
| 97 | |||
| 98 | Maxwell::ShaderStage GetStage() const { | ||
| 99 | return stage; | ||
| 100 | } | ||
| 101 | |||
| 102 | u32 GetHash() const { | ||
| 103 | return (static_cast<u32>(stage) << 24) | (cbuf_index << 16) | cbuf_offset; | ||
| 104 | } | ||
| 105 | |||
| 106 | private: | 52 | private: |
| 107 | u32 cbuf_index{}; | 53 | u32 cbuf_index{}; |
| 108 | u32 cbuf_offset{}; | 54 | u32 cbuf_offset{}; |
| 109 | Maxwell::ShaderStage stage{}; | ||
| 110 | }; | 55 | }; |
| 111 | 56 | ||
| 112 | struct ShaderEntries { | 57 | struct ShaderEntries { |
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 6a23b8fe2..7628a74c2 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -24,11 +24,16 @@ | |||
| 24 | 24 | ||
| 25 | namespace OpenGL { | 25 | namespace OpenGL { |
| 26 | 26 | ||
| 27 | enum class EntryKind : u32 { | 27 | enum class TransferableEntryKind : u32 { |
| 28 | Raw, | 28 | Raw, |
| 29 | Usage, | 29 | Usage, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | enum class PrecompiledEntryKind : u32 { | ||
| 33 | Decompiled, | ||
| 34 | Dump, | ||
| 35 | }; | ||
| 36 | |||
| 32 | constexpr u32 NativeVersion = 1; | 37 | constexpr u32 NativeVersion = 1; |
| 33 | constexpr u32 ShaderHashSize = 64; | 38 | constexpr u32 ShaderHashSize = 64; |
| 34 | 39 | ||
| @@ -108,17 +113,17 @@ bool ShaderDiskCacheOpenGL::LoadTransferable(std::vector<ShaderDiskCacheRaw>& ra | |||
| 108 | 113 | ||
| 109 | // Version is valid, load the shaders | 114 | // Version is valid, load the shaders |
| 110 | while (file.Tell() < file_size) { | 115 | while (file.Tell() < file_size) { |
| 111 | EntryKind kind{}; | 116 | TransferableEntryKind kind{}; |
| 112 | file.ReadBytes(&kind, sizeof(u32)); | 117 | file.ReadBytes(&kind, sizeof(u32)); |
| 113 | 118 | ||
| 114 | switch (kind) { | 119 | switch (kind) { |
| 115 | case EntryKind::Raw: { | 120 | case TransferableEntryKind::Raw: { |
| 116 | ShaderDiskCacheRaw entry{file}; | 121 | ShaderDiskCacheRaw entry{file}; |
| 117 | transferable.insert({entry.GetUniqueIdentifier(), {}}); | 122 | transferable.insert({entry.GetUniqueIdentifier(), {}}); |
| 118 | raws.push_back(std::move(entry)); | 123 | raws.push_back(std::move(entry)); |
| 119 | break; | 124 | break; |
| 120 | } | 125 | } |
| 121 | case EntryKind::Usage: { | 126 | case TransferableEntryKind::Usage: { |
| 122 | ShaderDiskCacheUsage usage{}; | 127 | ShaderDiskCacheUsage usage{}; |
| 123 | file.ReadBytes(&usage, sizeof(usage)); | 128 | file.ReadBytes(&usage, sizeof(usage)); |
| 124 | usages.push_back(std::move(usage)); | 129 | usages.push_back(std::move(usage)); |
| @@ -133,16 +138,19 @@ bool ShaderDiskCacheOpenGL::LoadTransferable(std::vector<ShaderDiskCacheRaw>& ra | |||
| 133 | return true; | 138 | return true; |
| 134 | } | 139 | } |
| 135 | 140 | ||
| 136 | std::vector<ShaderDiskCachePrecompiledEntry> ShaderDiskCacheOpenGL::LoadPrecompiled() { | 141 | bool ShaderDiskCacheOpenGL::LoadPrecompiled( |
| 142 | std::map<u64, ShaderDiskCacheDecompiled>& decompiled, | ||
| 143 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>& dumps) { | ||
| 144 | |||
| 137 | if (!Settings::values.use_disk_shader_cache) { | 145 | if (!Settings::values.use_disk_shader_cache) { |
| 138 | return {}; | 146 | return false; |
| 139 | } | 147 | } |
| 140 | 148 | ||
| 141 | FileUtil::IOFile file(GetPrecompiledPath(), "rb"); | 149 | FileUtil::IOFile file(GetPrecompiledPath(), "rb"); |
| 142 | if (!file.IsOpen()) { | 150 | if (!file.IsOpen()) { |
| 143 | LOG_INFO(Render_OpenGL, "No precompiled shader cache found for game with title id={}", | 151 | LOG_INFO(Render_OpenGL, "No precompiled shader cache found for game with title id={}", |
| 144 | GetTitleID()); | 152 | GetTitleID()); |
| 145 | return {}; | 153 | return false; |
| 146 | } | 154 | } |
| 147 | const u64 file_size = file.GetSize(); | 155 | const u64 file_size = file.GetSize(); |
| 148 | 156 | ||
| @@ -152,24 +160,102 @@ std::vector<ShaderDiskCachePrecompiledEntry> ShaderDiskCacheOpenGL::LoadPrecompi | |||
| 152 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of yuzu - removing"); | 160 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of yuzu - removing"); |
| 153 | file.Close(); | 161 | file.Close(); |
| 154 | InvalidatePrecompiled(); | 162 | InvalidatePrecompiled(); |
| 155 | return {}; | 163 | return false; |
| 156 | } | 164 | } |
| 157 | 165 | ||
| 158 | std::vector<ShaderDiskCachePrecompiledEntry> precompiled; | ||
| 159 | while (file.Tell() < file_size) { | 166 | while (file.Tell() < file_size) { |
| 160 | ShaderDiskCachePrecompiledEntry entry; | 167 | PrecompiledEntryKind kind{}; |
| 161 | file.ReadBytes(&entry.usage, sizeof(entry.usage)); | 168 | file.ReadBytes(&kind, sizeof(u32)); |
| 162 | 169 | ||
| 163 | file.ReadBytes(&entry.binary_format, sizeof(u32)); | 170 | switch (kind) { |
| 171 | case PrecompiledEntryKind::Decompiled: { | ||
| 172 | ShaderDiskCacheDecompiled entry; | ||
| 173 | |||
| 174 | u64 unique_identifier{}; | ||
| 175 | file.ReadBytes(&unique_identifier, sizeof(u64)); | ||
| 176 | |||
| 177 | u32 code_size{}; | ||
| 178 | file.ReadBytes(&code_size, sizeof(u32)); | ||
| 179 | std::vector<u8> code(code_size); | ||
| 180 | file.ReadArray(code.data(), code.size()); | ||
| 181 | entry.code = std::string(reinterpret_cast<char*>(code.data()), code_size); | ||
| 182 | |||
| 183 | u32 const_buffers_count{}; | ||
| 184 | file.ReadBytes(&const_buffers_count, sizeof(u32)); | ||
| 185 | for (u32 i = 0; i < const_buffers_count; ++i) { | ||
| 186 | u32 max_offset{}, index{}; | ||
| 187 | u8 is_indirect{}; | ||
| 188 | file.ReadBytes(&max_offset, sizeof(u32)); | ||
| 189 | file.ReadBytes(&index, sizeof(u32)); | ||
| 190 | file.ReadBytes(&is_indirect, sizeof(u8)); | ||
| 191 | |||
| 192 | entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); | ||
| 193 | } | ||
| 194 | |||
| 195 | u32 samplers_count{}; | ||
| 196 | file.ReadBytes(&samplers_count, sizeof(u32)); | ||
| 197 | for (u32 i = 0; i < samplers_count; ++i) { | ||
| 198 | u64 offset{}, index{}; | ||
| 199 | u32 type{}; | ||
| 200 | u8 is_array{}, is_shadow{}; | ||
| 201 | file.ReadBytes(&offset, sizeof(u64)); | ||
| 202 | file.ReadBytes(&index, sizeof(u64)); | ||
| 203 | file.ReadBytes(&type, sizeof(u32)); | ||
| 204 | file.ReadBytes(&is_array, sizeof(u8)); | ||
| 205 | file.ReadBytes(&is_shadow, sizeof(u8)); | ||
| 206 | |||
| 207 | entry.entries.samplers.emplace_back( | ||
| 208 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | ||
| 209 | static_cast<Tegra::Shader::TextureType>(type), is_array != 0, is_shadow != 0); | ||
| 210 | } | ||
| 211 | |||
| 212 | u32 global_memory_count{}; | ||
| 213 | file.ReadBytes(&global_memory_count, sizeof(u32)); | ||
| 214 | for (u32 i = 0; i < global_memory_count; ++i) { | ||
| 215 | u32 cbuf_index{}, cbuf_offset{}; | ||
| 216 | file.ReadBytes(&cbuf_index, sizeof(u32)); | ||
| 217 | file.ReadBytes(&cbuf_offset, sizeof(u32)); | ||
| 218 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset); | ||
| 219 | } | ||
| 220 | |||
| 221 | for (auto& clip_distance : entry.entries.clip_distances) { | ||
| 222 | u8 clip_distance_raw{}; | ||
| 223 | file.ReadBytes(&clip_distance_raw, sizeof(u8)); | ||
| 224 | clip_distance = clip_distance_raw != 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | u64 shader_length{}; | ||
| 228 | file.ReadBytes(&shader_length, sizeof(u64)); | ||
| 229 | entry.entries.shader_length = static_cast<std::size_t>(shader_length); | ||
| 230 | |||
| 231 | decompiled.insert({unique_identifier, std::move(entry)}); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | case PrecompiledEntryKind::Dump: { | ||
| 235 | ShaderDiskCacheUsage usage; | ||
| 236 | file.ReadBytes(&usage, sizeof(usage)); | ||
| 237 | |||
| 238 | ShaderDiskCacheDump dump; | ||
| 239 | file.ReadBytes(&dump.binary_format, sizeof(u32)); | ||
| 164 | 240 | ||
| 165 | u32 binary_length{}; | 241 | u32 binary_length{}; |
| 166 | file.ReadBytes(&binary_length, sizeof(u32)); | 242 | file.ReadBytes(&binary_length, sizeof(u32)); |
| 167 | entry.binary.resize(binary_length); | 243 | dump.binary.resize(binary_length); |
| 168 | file.ReadBytes(entry.binary.data(), entry.binary.size()); | 244 | file.ReadBytes(dump.binary.data(), dump.binary.size()); |
| 169 | 245 | ||
| 170 | precompiled.push_back(entry); | 246 | dumps.insert({usage, dump}); |
| 247 | break; | ||
| 248 | } | ||
| 249 | default: | ||
| 250 | LOG_ERROR(Render_OpenGL, "Unknown precompiled shader cache entry kind={} - removing", | ||
| 251 | static_cast<u32>(kind)); | ||
| 252 | InvalidatePrecompiled(); | ||
| 253 | dumps.clear(); | ||
| 254 | decompiled.clear(); | ||
| 255 | return false; | ||
| 256 | } | ||
| 171 | } | 257 | } |
| 172 | return precompiled; | 258 | return true; |
| 173 | } | 259 | } |
| 174 | 260 | ||
| 175 | void ShaderDiskCacheOpenGL::InvalidateTransferable() const { | 261 | void ShaderDiskCacheOpenGL::InvalidateTransferable() const { |
| @@ -196,7 +282,7 @@ void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { | |||
| 196 | if (!file.IsOpen()) { | 282 | if (!file.IsOpen()) { |
| 197 | return; | 283 | return; |
| 198 | } | 284 | } |
| 199 | file.WriteObject(EntryKind::Raw); | 285 | file.WriteObject(TransferableEntryKind::Raw); |
| 200 | entry.Save(file); | 286 | entry.Save(file); |
| 201 | 287 | ||
| 202 | transferable.insert({id, {}}); | 288 | transferable.insert({id, {}}); |
| @@ -220,11 +306,58 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { | |||
| 220 | if (!file.IsOpen()) { | 306 | if (!file.IsOpen()) { |
| 221 | return; | 307 | return; |
| 222 | } | 308 | } |
| 223 | file.WriteObject(EntryKind::Usage); | 309 | file.WriteObject(TransferableEntryKind::Usage); |
| 224 | file.WriteObject(usage); | 310 | file.WriteObject(usage); |
| 225 | } | 311 | } |
| 226 | 312 | ||
| 227 | void ShaderDiskCacheOpenGL::SavePrecompiled(const ShaderDiskCacheUsage& usage, GLuint program) { | 313 | void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::string& code, |
| 314 | const GLShader::ShaderEntries& entries) { | ||
| 315 | if (!Settings::values.use_disk_shader_cache) { | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | |||
| 319 | FileUtil::IOFile file = AppendPrecompiledFile(); | ||
| 320 | if (!file.IsOpen()) { | ||
| 321 | return; | ||
| 322 | } | ||
| 323 | |||
| 324 | file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Decompiled)); | ||
| 325 | |||
| 326 | file.WriteObject(unique_identifier); | ||
| 327 | |||
| 328 | file.WriteObject(static_cast<u32>(code.size())); | ||
| 329 | file.WriteArray(code.data(), code.size()); | ||
| 330 | |||
| 331 | file.WriteObject(static_cast<u32>(entries.const_buffers.size())); | ||
| 332 | for (const auto& cbuf : entries.const_buffers) { | ||
| 333 | file.WriteObject(static_cast<u32>(cbuf.GetMaxOffset())); | ||
| 334 | file.WriteObject(static_cast<u32>(cbuf.GetIndex())); | ||
| 335 | file.WriteObject(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0)); | ||
| 336 | } | ||
| 337 | |||
| 338 | file.WriteObject(static_cast<u32>(entries.samplers.size())); | ||
| 339 | for (const auto& sampler : entries.samplers) { | ||
| 340 | file.WriteObject(static_cast<u64>(sampler.GetOffset())); | ||
| 341 | file.WriteObject(static_cast<u64>(sampler.GetIndex())); | ||
| 342 | file.WriteObject(static_cast<u32>(sampler.GetType())); | ||
| 343 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)); | ||
| 344 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)); | ||
| 345 | } | ||
| 346 | |||
| 347 | file.WriteObject(static_cast<u32>(entries.global_memory_entries.size())); | ||
| 348 | for (const auto& gmem : entries.global_memory_entries) { | ||
| 349 | file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())); | ||
| 350 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())); | ||
| 351 | } | ||
| 352 | |||
| 353 | for (const bool clip_distance : entries.clip_distances) { | ||
| 354 | file.WriteObject(static_cast<u8>(clip_distance ? 1 : 0)); | ||
| 355 | } | ||
| 356 | |||
| 357 | file.WriteObject(static_cast<u64>(entries.shader_length)); | ||
| 358 | } | ||
| 359 | |||
| 360 | void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { | ||
| 228 | if (!Settings::values.use_disk_shader_cache) { | 361 | if (!Settings::values.use_disk_shader_cache) { |
| 229 | return; | 362 | return; |
| 230 | } | 363 | } |
| @@ -234,6 +367,8 @@ void ShaderDiskCacheOpenGL::SavePrecompiled(const ShaderDiskCacheUsage& usage, G | |||
| 234 | return; | 367 | return; |
| 235 | } | 368 | } |
| 236 | 369 | ||
| 370 | file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Dump)); | ||
| 371 | |||
| 237 | file.WriteObject(usage); | 372 | file.WriteObject(usage); |
| 238 | 373 | ||
| 239 | GLint binary_length{}; | 374 | GLint binary_length{}; |
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h index 6c4c7bd5c..f11693789 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h | |||
| @@ -130,14 +130,16 @@ public: | |||
| 130 | } | 130 | } |
| 131 | }; | 131 | }; |
| 132 | 132 | ||
| 133 | struct ShaderDiskCachePrecompiledEntry { | 133 | struct ShaderDiskCacheDecompiled { |
| 134 | ShaderDiskCacheUsage usage; | ||
| 135 | GLenum binary_format; | ||
| 136 | std::vector<u8> binary; | ||
| 137 | std::string code; | 134 | std::string code; |
| 138 | GLShader::ShaderEntries entries; | 135 | GLShader::ShaderEntries entries; |
| 139 | }; | 136 | }; |
| 140 | 137 | ||
| 138 | struct ShaderDiskCacheDump { | ||
| 139 | GLenum binary_format; | ||
| 140 | std::vector<u8> binary; | ||
| 141 | }; | ||
| 142 | |||
| 141 | class ShaderDiskCacheOpenGL { | 143 | class ShaderDiskCacheOpenGL { |
| 142 | public: | 144 | public: |
| 143 | /// Loads transferable cache. If file has a old version, it deletes it. Returns true on success. | 145 | /// Loads transferable cache. If file has a old version, it deletes it. Returns true on success. |
| @@ -145,7 +147,8 @@ public: | |||
| 145 | std::vector<ShaderDiskCacheUsage>& usages); | 147 | std::vector<ShaderDiskCacheUsage>& usages); |
| 146 | 148 | ||
| 147 | /// Loads current game's precompiled cache. Invalidates if emulator's version has changed. | 149 | /// Loads current game's precompiled cache. Invalidates if emulator's version has changed. |
| 148 | std::vector<ShaderDiskCachePrecompiledEntry> LoadPrecompiled(); | 150 | bool LoadPrecompiled(std::map<u64, ShaderDiskCacheDecompiled>& decompiled, |
| 151 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>& dumps); | ||
| 149 | 152 | ||
| 150 | /// Removes the transferable (and precompiled) cache file. | 153 | /// Removes the transferable (and precompiled) cache file. |
| 151 | void InvalidateTransferable() const; | 154 | void InvalidateTransferable() const; |
| @@ -159,8 +162,12 @@ public: | |||
| 159 | /// Saves shader usage to the transferable file. Does not check for collisions. | 162 | /// Saves shader usage to the transferable file. Does not check for collisions. |
| 160 | void SaveUsage(const ShaderDiskCacheUsage& usage); | 163 | void SaveUsage(const ShaderDiskCacheUsage& usage); |
| 161 | 164 | ||
| 162 | /// Saves a precompiled shader entry. Does not check for collisions. | 165 | /// Saves a decompiled entry to the precompiled file. Does not check for collisions. |
| 163 | void SavePrecompiled(const ShaderDiskCacheUsage& usage, GLuint program); | 166 | void SaveDecompiled(u64 unique_identifier, const std::string& code, |
| 167 | const GLShader::ShaderEntries& entries); | ||
| 168 | |||
| 169 | /// Saves a dump entry to the precompiled file. Does not check for collisions. | ||
| 170 | void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program); | ||
| 164 | 171 | ||
| 165 | private: | 172 | private: |
| 166 | /// Opens current game's transferable file and write it's header if it doesn't exist | 173 | /// Opens current game's transferable file and write it's header if it doesn't exist |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index ac5e6917b..fd3105de3 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -26,8 +26,6 @@ struct ShaderSetup { | |||
| 26 | ProgramCode code; | 26 | ProgramCode code; |
| 27 | ProgramCode code_b; // Used for dual vertex shaders | 27 | ProgramCode code_b; // Used for dual vertex shaders |
| 28 | u64 unique_identifier; | 28 | u64 unique_identifier; |
| 29 | std::size_t real_size; | ||
| 30 | std::size_t real_size_b; | ||
| 31 | } program; | 29 | } program; |
| 32 | 30 | ||
| 33 | /// Used in scenarios where we have a dual vertex shaders | 31 | /// Used in scenarios where we have a dual vertex shaders |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 6e42e3dfb..ef0f3a106 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -236,6 +236,11 @@ private: | |||
| 236 | 236 | ||
| 237 | class ConstBuffer { | 237 | class ConstBuffer { |
| 238 | public: | 238 | public: |
| 239 | explicit ConstBuffer(u32 max_offset, bool is_indirect) | ||
| 240 | : max_offset{max_offset}, is_indirect{is_indirect} {} | ||
| 241 | |||
| 242 | ConstBuffer() = default; | ||
| 243 | |||
| 239 | void MarkAsUsed(u64 offset) { | 244 | void MarkAsUsed(u64 offset) { |
| 240 | max_offset = std::max(max_offset, static_cast<u32>(offset)); | 245 | max_offset = std::max(max_offset, static_cast<u32>(offset)); |
| 241 | } | 246 | } |
| @@ -252,6 +257,10 @@ public: | |||
| 252 | return max_offset + sizeof(float); | 257 | return max_offset + sizeof(float); |
| 253 | } | 258 | } |
| 254 | 259 | ||
| 260 | u32 GetMaxOffset() const { | ||
| 261 | return max_offset; | ||
| 262 | } | ||
| 263 | |||
| 255 | private: | 264 | private: |
| 256 | u32 max_offset{}; | 265 | u32 max_offset{}; |
| 257 | bool is_indirect{}; | 266 | bool is_indirect{}; |