diff options
| author | 2019-09-25 21:46:34 -0300 | |
|---|---|---|
| committer | 2019-10-25 09:01:31 -0400 | |
| commit | ec85648af3316d5e43c7b57fca55d0dad3d03f96 (patch) | |
| tree | b5cc21e8b027a27e69c8197202f98d0c36706978 | |
| parent | const_buffer_locker: Minor style changes (diff) | |
| download | yuzu-ec85648af3316d5e43c7b57fca55d0dad3d03f96.tar.gz yuzu-ec85648af3316d5e43c7b57fca55d0dad3d03f96.tar.xz yuzu-ec85648af3316d5e43c7b57fca55d0dad3d03f96.zip | |
gl_shader_disk_cache: Store and load fast BRX
6 files changed, 210 insertions, 50 deletions
diff --git a/src/video_core/engines/const_buffer_engine_interface.h b/src/video_core/engines/const_buffer_engine_interface.h index c0e3a3a17..80f470777 100644 --- a/src/video_core/engines/const_buffer_engine_interface.h +++ b/src/video_core/engines/const_buffer_engine_interface.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <type_traits> | ||
| 7 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "video_core/engines/shader_bytecode.h" | 10 | #include "video_core/engines/shader_bytecode.h" |
| @@ -29,51 +30,49 @@ struct SamplerDescriptor { | |||
| 29 | u32 raw{}; | 30 | u32 raw{}; |
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| 33 | bool operator==(const SamplerDescriptor& rhs) const noexcept { | ||
| 34 | return raw == rhs.raw; | ||
| 35 | } | ||
| 36 | |||
| 32 | static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) { | 37 | static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) { |
| 33 | SamplerDescriptor result{}; | 38 | SamplerDescriptor result; |
| 34 | switch (tic_texture_type) { | 39 | switch (tic_texture_type) { |
| 35 | case Tegra::Texture::TextureType::Texture1D: { | 40 | case Tegra::Texture::TextureType::Texture1D: |
| 36 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); | 41 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
| 37 | result.is_array.Assign(0); | 42 | result.is_array.Assign(0); |
| 38 | result.is_buffer.Assign(0); | 43 | result.is_buffer.Assign(0); |
| 39 | result.is_shadow.Assign(0); | 44 | result.is_shadow.Assign(0); |
| 40 | return result; | 45 | return result; |
| 41 | } | 46 | case Tegra::Texture::TextureType::Texture2D: |
| 42 | case Tegra::Texture::TextureType::Texture2D: { | ||
| 43 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); | 47 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
| 44 | result.is_array.Assign(0); | 48 | result.is_array.Assign(0); |
| 45 | result.is_buffer.Assign(0); | 49 | result.is_buffer.Assign(0); |
| 46 | result.is_shadow.Assign(0); | 50 | result.is_shadow.Assign(0); |
| 47 | return result; | 51 | return result; |
| 48 | } | 52 | case Tegra::Texture::TextureType::Texture3D: |
| 49 | case Tegra::Texture::TextureType::Texture3D: { | ||
| 50 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture3D); | 53 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture3D); |
| 51 | result.is_array.Assign(0); | 54 | result.is_array.Assign(0); |
| 52 | result.is_buffer.Assign(0); | 55 | result.is_buffer.Assign(0); |
| 53 | result.is_shadow.Assign(0); | 56 | result.is_shadow.Assign(0); |
| 54 | return result; | 57 | return result; |
| 55 | } | 58 | case Tegra::Texture::TextureType::TextureCubemap: |
| 56 | case Tegra::Texture::TextureType::TextureCubemap: { | ||
| 57 | result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); | 59 | result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); |
| 58 | result.is_array.Assign(0); | 60 | result.is_array.Assign(0); |
| 59 | result.is_buffer.Assign(0); | 61 | result.is_buffer.Assign(0); |
| 60 | result.is_shadow.Assign(0); | 62 | result.is_shadow.Assign(0); |
| 61 | return result; | 63 | return result; |
| 62 | } | 64 | case Tegra::Texture::TextureType::Texture1DArray: |
| 63 | case Tegra::Texture::TextureType::Texture1DArray: { | ||
| 64 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); | 65 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
| 65 | result.is_array.Assign(1); | 66 | result.is_array.Assign(1); |
| 66 | result.is_buffer.Assign(0); | 67 | result.is_buffer.Assign(0); |
| 67 | result.is_shadow.Assign(0); | 68 | result.is_shadow.Assign(0); |
| 68 | return result; | 69 | return result; |
| 69 | } | 70 | case Tegra::Texture::TextureType::Texture2DArray: |
| 70 | case Tegra::Texture::TextureType::Texture2DArray: { | ||
| 71 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); | 71 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
| 72 | result.is_array.Assign(1); | 72 | result.is_array.Assign(1); |
| 73 | result.is_buffer.Assign(0); | 73 | result.is_buffer.Assign(0); |
| 74 | result.is_shadow.Assign(0); | 74 | result.is_shadow.Assign(0); |
| 75 | return result; | 75 | return result; |
| 76 | } | ||
| 77 | case Tegra::Texture::TextureType::Texture1DBuffer: { | 76 | case Tegra::Texture::TextureType::Texture1DBuffer: { |
| 78 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); | 77 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
| 79 | result.is_array.Assign(0); | 78 | result.is_array.Assign(0); |
| @@ -81,30 +80,28 @@ struct SamplerDescriptor { | |||
| 81 | result.is_shadow.Assign(0); | 80 | result.is_shadow.Assign(0); |
| 82 | return result; | 81 | return result; |
| 83 | } | 82 | } |
| 84 | case Tegra::Texture::TextureType::Texture2DNoMipmap: { | 83 | case Tegra::Texture::TextureType::Texture2DNoMipmap: |
| 85 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); | 84 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
| 86 | result.is_array.Assign(0); | 85 | result.is_array.Assign(0); |
| 87 | result.is_buffer.Assign(0); | 86 | result.is_buffer.Assign(0); |
| 88 | result.is_shadow.Assign(0); | 87 | result.is_shadow.Assign(0); |
| 89 | return result; | 88 | return result; |
| 90 | } | 89 | case Tegra::Texture::TextureType::TextureCubeArray: |
| 91 | case Tegra::Texture::TextureType::TextureCubeArray: { | ||
| 92 | result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); | 90 | result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); |
| 93 | result.is_array.Assign(1); | 91 | result.is_array.Assign(1); |
| 94 | result.is_buffer.Assign(0); | 92 | result.is_buffer.Assign(0); |
| 95 | result.is_shadow.Assign(0); | 93 | result.is_shadow.Assign(0); |
| 96 | return result; | 94 | return result; |
| 97 | } | 95 | default: |
| 98 | default: { | ||
| 99 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); | 96 | result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
| 100 | result.is_array.Assign(0); | 97 | result.is_array.Assign(0); |
| 101 | result.is_buffer.Assign(0); | 98 | result.is_buffer.Assign(0); |
| 102 | result.is_shadow.Assign(0); | 99 | result.is_shadow.Assign(0); |
| 103 | return result; | 100 | return result; |
| 104 | } | 101 | } |
| 105 | } | ||
| 106 | } | 102 | } |
| 107 | }; | 103 | }; |
| 104 | static_assert(std::is_trivially_copyable_v<SamplerDescriptor>); | ||
| 108 | 105 | ||
| 109 | class ConstBufferEngineInterface { | 106 | class ConstBufferEngineInterface { |
| 110 | public: | 107 | public: |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 6402d6763..7e7aea15f 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -392,7 +392,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar | |||
| 392 | ConstBufferLocker locker(GetEnginesShaderType(program_type), *engine); | 392 | ConstBufferLocker locker(GetEnginesShaderType(program_type), *engine); |
| 393 | program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, | 393 | program = BuildShader(device, unique_identifier, program_type, program_code, program_code_b, |
| 394 | variant, locker); | 394 | variant, locker); |
| 395 | disk_cache.SaveUsage(GetUsage(variant)); | 395 | disk_cache.SaveUsage(GetUsage(variant, locker)); |
| 396 | 396 | ||
| 397 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); | 397 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); |
| 398 | } | 398 | } |
| @@ -408,10 +408,14 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar | |||
| 408 | return {program->handle, base_bindings}; | 408 | return {program->handle, base_bindings}; |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant) const { | 411 | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant, |
| 412 | const ConstBufferLocker& locker) const { | ||
| 412 | ShaderDiskCacheUsage usage; | 413 | ShaderDiskCacheUsage usage; |
| 413 | usage.unique_identifier = unique_identifier; | 414 | usage.unique_identifier = unique_identifier; |
| 414 | usage.variant = variant; | 415 | usage.variant = variant; |
| 416 | usage.keys = locker.GetKeys(); | ||
| 417 | usage.bound_samplers = locker.GetBoundSamplers(); | ||
| 418 | usage.bindless_samplers = locker.GetBindlessSamplers(); | ||
| 415 | return usage; | 419 | return usage; |
| 416 | } | 420 | } |
| 417 | 421 | ||
| @@ -472,6 +476,17 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 472 | } | 476 | } |
| 473 | if (!shader) { | 477 | if (!shader) { |
| 474 | ConstBufferLocker locker(GetEnginesShaderType(unspecialized.program_type)); | 478 | ConstBufferLocker locker(GetEnginesShaderType(unspecialized.program_type)); |
| 479 | for (const auto& key : usage.keys) { | ||
| 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 | } | ||
| 475 | shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, | 490 | shader = BuildShader(device, usage.unique_identifier, unspecialized.program_type, |
| 476 | unspecialized.code, unspecialized.code_b, usage.variant, | 491 | unspecialized.code, unspecialized.code_b, usage.variant, |
| 477 | locker, true); | 492 | locker, true); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 700a83853..2935e6831 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -31,6 +31,10 @@ namespace Core::Frontend { | |||
| 31 | class EmuWindow; | 31 | class EmuWindow; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | namespace VideoCommon::Shader { | ||
| 35 | class ConstBufferLocker; | ||
| 36 | } | ||
| 37 | |||
| 34 | namespace OpenGL { | 38 | namespace OpenGL { |
| 35 | 39 | ||
| 36 | class CachedShader; | 40 | class CachedShader; |
| @@ -92,7 +96,8 @@ private: | |||
| 92 | GLShader::ShaderEntries entries, ProgramCode program_code, | 96 | GLShader::ShaderEntries entries, ProgramCode program_code, |
| 93 | ProgramCode program_code_b); | 97 | ProgramCode program_code_b); |
| 94 | 98 | ||
| 95 | ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant) const; | 99 | ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant, |
| 100 | const VideoCommon::Shader::ConstBufferLocker& locker) const; | ||
| 96 | 101 | ||
| 97 | Core::System& system; | 102 | Core::System& system; |
| 98 | ShaderDiskCacheOpenGL& disk_cache; | 103 | ShaderDiskCacheOpenGL& disk_cache; |
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 ddc19dccd..184a565e6 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -22,6 +22,29 @@ | |||
| 22 | 22 | ||
| 23 | namespace OpenGL { | 23 | namespace OpenGL { |
| 24 | 24 | ||
| 25 | using VideoCommon::Shader::BindlessSamplerMap; | ||
| 26 | using VideoCommon::Shader::BoundSamplerMap; | ||
| 27 | using VideoCommon::Shader::KeyMap; | ||
| 28 | |||
| 29 | namespace { | ||
| 30 | |||
| 31 | struct ConstBufferKey { | ||
| 32 | u32 cbuf; | ||
| 33 | u32 offset; | ||
| 34 | u32 value; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct BoundSamplerKey { | ||
| 38 | u32 offset; | ||
| 39 | Tegra::Engines::SamplerDescriptor sampler; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct BindlessSamplerKey { | ||
| 43 | u32 cbuf; | ||
| 44 | u32 offset; | ||
| 45 | Tegra::Engines::SamplerDescriptor sampler; | ||
| 46 | }; | ||
| 47 | |||
| 25 | using ShaderCacheVersionHash = std::array<u8, 64>; | 48 | using ShaderCacheVersionHash = std::array<u8, 64>; |
| 26 | 49 | ||
| 27 | enum class TransferableEntryKind : u32 { | 50 | enum class TransferableEntryKind : u32 { |
| @@ -33,9 +56,6 @@ constexpr u32 NativeVersion = 5; | |||
| 33 | 56 | ||
| 34 | // Making sure sizes doesn't change by accident | 57 | // Making sure sizes doesn't change by accident |
| 35 | static_assert(sizeof(BaseBindings) == 16); | 58 | static_assert(sizeof(BaseBindings) == 16); |
| 36 | static_assert(sizeof(ShaderDiskCacheUsage) == 40); | ||
| 37 | |||
| 38 | namespace { | ||
| 39 | 59 | ||
| 40 | ShaderCacheVersionHash GetShaderCacheVersionHash() { | 60 | ShaderCacheVersionHash GetShaderCacheVersionHash() { |
| 41 | ShaderCacheVersionHash hash{}; | 61 | ShaderCacheVersionHash hash{}; |
| @@ -121,13 +141,13 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 121 | u32 version{}; | 141 | u32 version{}; |
| 122 | if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { | 142 | if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { |
| 123 | LOG_ERROR(Render_OpenGL, | 143 | LOG_ERROR(Render_OpenGL, |
| 124 | "Failed to get transferable cache version for title id={} - skipping", | 144 | "Failed to get transferable cache version for title id={}, skipping", |
| 125 | GetTitleID()); | 145 | GetTitleID()); |
| 126 | return {}; | 146 | return {}; |
| 127 | } | 147 | } |
| 128 | 148 | ||
| 129 | if (version < NativeVersion) { | 149 | if (version < NativeVersion) { |
| 130 | LOG_INFO(Render_OpenGL, "Transferable shader cache is old - removing"); | 150 | LOG_INFO(Render_OpenGL, "Transferable shader cache is old, removing"); |
| 131 | file.Close(); | 151 | file.Close(); |
| 132 | InvalidateTransferable(); | 152 | InvalidateTransferable(); |
| 133 | is_usable = true; | 153 | is_usable = true; |
| @@ -135,17 +155,18 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 135 | } | 155 | } |
| 136 | if (version > NativeVersion) { | 156 | if (version > NativeVersion) { |
| 137 | LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version " | 157 | LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version " |
| 138 | "of the emulator - skipping"); | 158 | "of the emulator, skipping"); |
| 139 | return {}; | 159 | return {}; |
| 140 | } | 160 | } |
| 141 | 161 | ||
| 142 | // Version is valid, load the shaders | 162 | // Version is valid, load the shaders |
| 163 | constexpr const char error_loading[] = "Failed to load transferable raw entry, skipping"; | ||
| 143 | std::vector<ShaderDiskCacheRaw> raws; | 164 | std::vector<ShaderDiskCacheRaw> raws; |
| 144 | std::vector<ShaderDiskCacheUsage> usages; | 165 | std::vector<ShaderDiskCacheUsage> usages; |
| 145 | while (file.Tell() < file.GetSize()) { | 166 | while (file.Tell() < file.GetSize()) { |
| 146 | TransferableEntryKind kind{}; | 167 | TransferableEntryKind kind{}; |
| 147 | if (file.ReadBytes(&kind, sizeof(u32)) != sizeof(u32)) { | 168 | if (file.ReadBytes(&kind, sizeof(u32)) != sizeof(u32)) { |
| 148 | LOG_ERROR(Render_OpenGL, "Failed to read transferable file - skipping"); | 169 | LOG_ERROR(Render_OpenGL, "Failed to read transferable file, skipping"); |
| 149 | return {}; | 170 | return {}; |
| 150 | } | 171 | } |
| 151 | 172 | ||
| @@ -153,7 +174,7 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 153 | case TransferableEntryKind::Raw: { | 174 | case TransferableEntryKind::Raw: { |
| 154 | ShaderDiskCacheRaw entry; | 175 | ShaderDiskCacheRaw entry; |
| 155 | if (!entry.Load(file)) { | 176 | if (!entry.Load(file)) { |
| 156 | LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry - skipping"); | 177 | LOG_ERROR(Render_OpenGL, error_loading); |
| 157 | return {}; | 178 | return {}; |
| 158 | } | 179 | } |
| 159 | transferable.insert({entry.GetUniqueIdentifier(), {}}); | 180 | transferable.insert({entry.GetUniqueIdentifier(), {}}); |
| @@ -161,16 +182,45 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 161 | break; | 182 | break; |
| 162 | } | 183 | } |
| 163 | case TransferableEntryKind::Usage: { | 184 | case TransferableEntryKind::Usage: { |
| 164 | ShaderDiskCacheUsage usage{}; | 185 | ShaderDiskCacheUsage usage; |
| 165 | if (file.ReadBytes(&usage, sizeof(usage)) != sizeof(usage)) { | 186 | |
| 166 | LOG_ERROR(Render_OpenGL, "Failed to load transferable usage entry - skipping"); | 187 | u32 num_keys{}; |
| 188 | u32 num_bound_samplers{}; | ||
| 189 | u32 num_bindless_samplers{}; | ||
| 190 | if (file.ReadArray(&usage.unique_identifier, 1) != 1 || | ||
| 191 | file.ReadArray(&usage.variant, 1) != 1 || file.ReadArray(&num_keys, 1) != 1 || | ||
| 192 | file.ReadArray(&num_bound_samplers, 1) != 1 || | ||
| 193 | file.ReadArray(&num_bindless_samplers, 1) != 1) { | ||
| 194 | LOG_ERROR(Render_OpenGL, error_loading); | ||
| 195 | return {}; | ||
| 196 | } | ||
| 197 | |||
| 198 | std::vector<ConstBufferKey> keys(num_keys); | ||
| 199 | std::vector<BoundSamplerKey> bound_samplers(num_bound_samplers); | ||
| 200 | std::vector<BindlessSamplerKey> bindless_samplers(num_bindless_samplers); | ||
| 201 | if (file.ReadArray(keys.data(), keys.size()) != keys.size() || | ||
| 202 | file.ReadArray(bound_samplers.data(), bound_samplers.size()) != | ||
| 203 | bound_samplers.size() || | ||
| 204 | file.ReadArray(bindless_samplers.data(), bindless_samplers.size()) != | ||
| 205 | bindless_samplers.size()) { | ||
| 206 | LOG_ERROR(Render_OpenGL, error_loading); | ||
| 167 | return {}; | 207 | return {}; |
| 168 | } | 208 | } |
| 209 | for (const auto& key : keys) { | ||
| 210 | usage.keys.insert({{key.cbuf, key.offset}, key.value}); | ||
| 211 | } | ||
| 212 | for (const auto& key : bound_samplers) { | ||
| 213 | usage.bound_samplers.emplace(key.offset, key.sampler); | ||
| 214 | } | ||
| 215 | for (const auto& key : bindless_samplers) { | ||
| 216 | usage.bindless_samplers.insert({{key.cbuf, key.offset}, key.sampler}); | ||
| 217 | } | ||
| 218 | |||
| 169 | usages.push_back(std::move(usage)); | 219 | usages.push_back(std::move(usage)); |
| 170 | break; | 220 | break; |
| 171 | } | 221 | } |
| 172 | default: | 222 | default: |
| 173 | LOG_ERROR(Render_OpenGL, "Unknown transferable shader cache entry kind={} - skipping", | 223 | LOG_ERROR(Render_OpenGL, "Unknown transferable shader cache entry kind={}, skipping", |
| 174 | static_cast<u32>(kind)); | 224 | static_cast<u32>(kind)); |
| 175 | return {}; | 225 | return {}; |
| 176 | } | 226 | } |
| @@ -197,7 +247,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiled() { | |||
| 197 | const auto result = LoadPrecompiledFile(file); | 247 | const auto result = LoadPrecompiledFile(file); |
| 198 | if (!result) { | 248 | if (!result) { |
| 199 | LOG_INFO(Render_OpenGL, | 249 | LOG_INFO(Render_OpenGL, |
| 200 | "Failed to load precompiled cache for game with title id={} - removing", | 250 | "Failed to load precompiled cache for game with title id={}, removing", |
| 201 | GetTitleID()); | 251 | GetTitleID()); |
| 202 | file.Close(); | 252 | file.Close(); |
| 203 | InvalidatePrecompiled(); | 253 | InvalidatePrecompiled(); |
| @@ -228,10 +278,35 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { | |||
| 228 | 278 | ||
| 229 | ShaderDumpsMap dumps; | 279 | ShaderDumpsMap dumps; |
| 230 | while (precompiled_cache_virtual_file_offset < precompiled_cache_virtual_file.GetSize()) { | 280 | while (precompiled_cache_virtual_file_offset < precompiled_cache_virtual_file.GetSize()) { |
| 281 | u32 num_keys{}; | ||
| 282 | u32 num_bound_samplers{}; | ||
| 283 | u32 num_bindless_samplers{}; | ||
| 231 | ShaderDiskCacheUsage usage; | 284 | ShaderDiskCacheUsage usage; |
| 232 | if (!LoadObjectFromPrecompiled(usage)) { | 285 | if (!LoadObjectFromPrecompiled(usage.unique_identifier) || |
| 286 | !LoadObjectFromPrecompiled(usage.variant) || !LoadObjectFromPrecompiled(num_keys) || | ||
| 287 | !LoadObjectFromPrecompiled(num_bound_samplers) || | ||
| 288 | !LoadObjectFromPrecompiled(num_bindless_samplers)) { | ||
| 233 | return {}; | 289 | return {}; |
| 234 | } | 290 | } |
| 291 | std::vector<ConstBufferKey> keys(num_keys); | ||
| 292 | std::vector<BoundSamplerKey> bound_samplers(num_bound_samplers); | ||
| 293 | std::vector<BindlessSamplerKey> bindless_samplers(num_bindless_samplers); | ||
| 294 | if (!LoadArrayFromPrecompiled(keys.data(), keys.size()) || | ||
| 295 | !LoadArrayFromPrecompiled(bound_samplers.data(), bound_samplers.size()) != | ||
| 296 | bound_samplers.size() || | ||
| 297 | !LoadArrayFromPrecompiled(bindless_samplers.data(), bindless_samplers.size()) != | ||
| 298 | bindless_samplers.size()) { | ||
| 299 | return {}; | ||
| 300 | } | ||
| 301 | for (const auto& key : keys) { | ||
| 302 | usage.keys.insert({{key.cbuf, key.offset}, key.value}); | ||
| 303 | } | ||
| 304 | for (const auto& key : bound_samplers) { | ||
| 305 | usage.bound_samplers.emplace(key.offset, key.sampler); | ||
| 306 | } | ||
| 307 | for (const auto& key : bindless_samplers) { | ||
| 308 | usage.bindless_samplers.insert({{key.cbuf, key.offset}, key.sampler}); | ||
| 309 | } | ||
| 235 | 310 | ||
| 236 | ShaderDiskCacheDump dump; | 311 | ShaderDiskCacheDump dump; |
| 237 | if (!LoadObjectFromPrecompiled(dump.binary_format)) { | 312 | if (!LoadObjectFromPrecompiled(dump.binary_format)) { |
| @@ -248,7 +323,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { | |||
| 248 | return {}; | 323 | return {}; |
| 249 | } | 324 | } |
| 250 | 325 | ||
| 251 | dumps.emplace(usage, dump); | 326 | dumps.emplace(std::move(usage), dump); |
| 252 | } | 327 | } |
| 253 | return dumps; | 328 | return dumps; |
| 254 | } | 329 | } |
| @@ -282,10 +357,11 @@ void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { | |||
| 282 | } | 357 | } |
| 283 | 358 | ||
| 284 | FileUtil::IOFile file = AppendTransferableFile(); | 359 | FileUtil::IOFile file = AppendTransferableFile(); |
| 285 | if (!file.IsOpen()) | 360 | if (!file.IsOpen()) { |
| 286 | return; | 361 | return; |
| 362 | } | ||
| 287 | if (file.WriteObject(TransferableEntryKind::Raw) != 1 || !entry.Save(file)) { | 363 | if (file.WriteObject(TransferableEntryKind::Raw) != 1 || !entry.Save(file)) { |
| 288 | LOG_ERROR(Render_OpenGL, "Failed to save raw transferable cache entry - removing"); | 364 | LOG_ERROR(Render_OpenGL, "Failed to save raw transferable cache entry, removing"); |
| 289 | file.Close(); | 365 | file.Close(); |
| 290 | InvalidateTransferable(); | 366 | InvalidateTransferable(); |
| 291 | return; | 367 | return; |
| @@ -311,13 +387,40 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { | |||
| 311 | FileUtil::IOFile file = AppendTransferableFile(); | 387 | FileUtil::IOFile file = AppendTransferableFile(); |
| 312 | if (!file.IsOpen()) | 388 | if (!file.IsOpen()) |
| 313 | return; | 389 | return; |
| 314 | 390 | const auto Close = [&] { | |
| 315 | if (file.WriteObject(TransferableEntryKind::Usage) != 1 || file.WriteObject(usage) != 1) { | 391 | LOG_ERROR(Render_OpenGL, "Failed to save usage transferable cache entry, removing"); |
| 316 | LOG_ERROR(Render_OpenGL, "Failed to save usage transferable cache entry - removing"); | ||
| 317 | file.Close(); | 392 | file.Close(); |
| 318 | InvalidateTransferable(); | 393 | InvalidateTransferable(); |
| 394 | }; | ||
| 395 | |||
| 396 | if (file.WriteObject(TransferableEntryKind::Usage) != 1 || | ||
| 397 | file.WriteObject(usage.unique_identifier) != 1 || file.WriteObject(usage.variant) != 1 || | ||
| 398 | file.WriteObject(static_cast<u32>(usage.keys.size())) != 1 || | ||
| 399 | file.WriteObject(static_cast<u32>(usage.bound_samplers.size())) != 1 || | ||
| 400 | file.WriteObject(static_cast<u32>(usage.bindless_samplers.size())) != 1) { | ||
| 401 | Close(); | ||
| 319 | return; | 402 | return; |
| 320 | } | 403 | } |
| 404 | for (const auto& [pair, value] : usage.keys) { | ||
| 405 | const auto [cbuf, offset] = pair; | ||
| 406 | if (file.WriteObject(ConstBufferKey{cbuf, offset, value}) != 1) { | ||
| 407 | Close(); | ||
| 408 | return; | ||
| 409 | } | ||
| 410 | } | ||
| 411 | for (const auto& [offset, sampler] : usage.bound_samplers) { | ||
| 412 | if (file.WriteObject(BoundSamplerKey{offset, sampler}) != 1) { | ||
| 413 | Close(); | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | for (const auto& [pair, sampler] : usage.bindless_samplers) { | ||
| 418 | const auto [cbuf, offset] = pair; | ||
| 419 | if (file.WriteObject(BindlessSamplerKey{cbuf, offset, sampler}) != 1) { | ||
| 420 | Close(); | ||
| 421 | return; | ||
| 422 | } | ||
| 423 | } | ||
| 321 | } | 424 | } |
| 322 | 425 | ||
| 323 | void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { | 426 | void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { |
| @@ -339,15 +442,45 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p | |||
| 339 | std::vector<u8> binary(binary_length); | 442 | std::vector<u8> binary(binary_length); |
| 340 | glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); | 443 | glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); |
| 341 | 444 | ||
| 342 | if (!SaveObjectToPrecompiled(usage) || | 445 | const auto Close = [&] { |
| 343 | !SaveObjectToPrecompiled(static_cast<u32>(binary_format)) || | 446 | LOG_ERROR(Render_OpenGL, "Failed to save binary program file in shader={:016X}, removing", |
| 344 | !SaveObjectToPrecompiled(static_cast<u32>(binary_length)) || | ||
| 345 | !SaveArrayToPrecompiled(binary.data(), binary.size())) { | ||
| 346 | LOG_ERROR(Render_OpenGL, "Failed to save binary program file in shader={:016x} - removing", | ||
| 347 | usage.unique_identifier); | 447 | usage.unique_identifier); |
| 348 | InvalidatePrecompiled(); | 448 | InvalidatePrecompiled(); |
| 449 | }; | ||
| 450 | |||
| 451 | if (!SaveObjectToPrecompiled(usage.unique_identifier) || | ||
| 452 | !SaveObjectToPrecompiled(usage.variant) || | ||
| 453 | !SaveObjectToPrecompiled(static_cast<u32>(usage.keys.size())) || | ||
| 454 | !SaveObjectToPrecompiled(static_cast<u32>(usage.bound_samplers.size())) || | ||
| 455 | !SaveObjectToPrecompiled(static_cast<u32>(usage.bindless_samplers.size()))) { | ||
| 456 | Close(); | ||
| 349 | return; | 457 | return; |
| 350 | } | 458 | } |
| 459 | for (const auto& [pair, value] : usage.keys) { | ||
| 460 | const auto [cbuf, offset] = pair; | ||
| 461 | if (SaveObjectToPrecompiled(ConstBufferKey{cbuf, offset, value}) != 1) { | ||
| 462 | Close(); | ||
| 463 | return; | ||
| 464 | } | ||
| 465 | } | ||
| 466 | for (const auto& [offset, sampler] : usage.bound_samplers) { | ||
| 467 | if (SaveObjectToPrecompiled(BoundSamplerKey{offset, sampler}) != 1) { | ||
| 468 | Close(); | ||
| 469 | return; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | for (const auto& [pair, sampler] : usage.bindless_samplers) { | ||
| 473 | const auto [cbuf, offset] = pair; | ||
| 474 | if (SaveObjectToPrecompiled(BindlessSamplerKey{cbuf, offset, sampler}) != 1) { | ||
| 475 | Close(); | ||
| 476 | return; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | if (!SaveObjectToPrecompiled(static_cast<u32>(binary_format)) || | ||
| 480 | !SaveObjectToPrecompiled(static_cast<u32>(binary_length)) || | ||
| 481 | !SaveArrayToPrecompiled(binary.data(), binary.size())) { | ||
| 482 | Close(); | ||
| 483 | } | ||
| 351 | } | 484 | } |
| 352 | 485 | ||
| 353 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { | 486 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { |
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 61b46d728..db23ada93 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <tuple> | 10 | #include <tuple> |
| 11 | #include <type_traits> | ||
| 11 | #include <unordered_map> | 12 | #include <unordered_map> |
| 12 | #include <unordered_set> | 13 | #include <unordered_set> |
| 13 | #include <utility> | 14 | #include <utility> |
| @@ -19,6 +20,7 @@ | |||
| 19 | #include "common/common_types.h" | 20 | #include "common/common_types.h" |
| 20 | #include "core/file_sys/vfs_vector.h" | 21 | #include "core/file_sys/vfs_vector.h" |
| 21 | #include "video_core/renderer_opengl/gl_shader_gen.h" | 22 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 23 | #include "video_core/shader/const_buffer_locker.h" | ||
| 22 | 24 | ||
| 23 | namespace Core { | 25 | namespace Core { |
| 24 | class System; | 26 | class System; |
| @@ -53,6 +55,7 @@ struct BaseBindings { | |||
| 53 | return !operator==(rhs); | 55 | return !operator==(rhs); |
| 54 | } | 56 | } |
| 55 | }; | 57 | }; |
| 58 | static_assert(std::is_trivially_copyable_v<BaseBindings>); | ||
| 56 | 59 | ||
| 57 | /// Describes the different variants a single program can be compiled. | 60 | /// Describes the different variants a single program can be compiled. |
| 58 | struct ProgramVariant { | 61 | struct ProgramVariant { |
| @@ -70,13 +73,20 @@ struct ProgramVariant { | |||
| 70 | } | 73 | } |
| 71 | }; | 74 | }; |
| 72 | 75 | ||
| 76 | static_assert(std::is_trivially_copyable_v<ProgramVariant>); | ||
| 77 | |||
| 73 | /// Describes how a shader is used. | 78 | /// Describes how a shader is used. |
| 74 | struct ShaderDiskCacheUsage { | 79 | struct ShaderDiskCacheUsage { |
| 75 | u64 unique_identifier{}; | 80 | u64 unique_identifier{}; |
| 76 | ProgramVariant variant; | 81 | ProgramVariant variant; |
| 82 | VideoCommon::Shader::KeyMap keys; | ||
| 83 | VideoCommon::Shader::BoundSamplerMap bound_samplers; | ||
| 84 | VideoCommon::Shader::BindlessSamplerMap bindless_samplers; | ||
| 77 | 85 | ||
| 78 | bool operator==(const ShaderDiskCacheUsage& rhs) const { | 86 | bool operator==(const ShaderDiskCacheUsage& rhs) const { |
| 79 | return std::tie(unique_identifier, variant) == std::tie(rhs.unique_identifier, rhs.variant); | 87 | return std::tie(unique_identifier, variant, keys, bound_samplers, bindless_samplers) == |
| 88 | std::tie(rhs.unique_identifier, rhs.variant, rhs.keys, rhs.bound_samplers, | ||
| 89 | rhs.bindless_samplers); | ||
| 80 | } | 90 | } |
| 81 | 91 | ||
| 82 | bool operator!=(const ShaderDiskCacheUsage& rhs) const { | 92 | bool operator!=(const ShaderDiskCacheUsage& rhs) const { |
diff --git a/src/video_core/shader/const_buffer_locker.cpp b/src/video_core/shader/const_buffer_locker.cpp index ebeba102d..fda9e3c38 100644 --- a/src/video_core/shader/const_buffer_locker.cpp +++ b/src/video_core/shader/const_buffer_locker.cpp | |||
| @@ -90,14 +90,14 @@ bool ConstBufferLocker::IsConsistent() const { | |||
| 90 | [this](const auto& sampler) { | 90 | [this](const auto& sampler) { |
| 91 | const auto [key, value] = sampler; | 91 | const auto [key, value] = sampler; |
| 92 | const auto other_value = engine->AccessBoundSampler(stage, key); | 92 | const auto other_value = engine->AccessBoundSampler(stage, key); |
| 93 | return value.raw == other_value.raw; | 93 | return value == other_value; |
| 94 | }) && | 94 | }) && |
| 95 | std::all_of( | 95 | std::all_of( |
| 96 | bindless_samplers.begin(), bindless_samplers.end(), [this](const auto& sampler) { | 96 | bindless_samplers.begin(), bindless_samplers.end(), [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 | const auto other_value = engine->AccessBindlessSampler(stage, cbuf, offset); |
| 100 | return value.raw == other_value.raw; | 100 | return value == other_value; |
| 101 | }); | 101 | }); |
| 102 | } | 102 | } |
| 103 | 103 | ||