diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 525 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 30 |
2 files changed, 339 insertions, 216 deletions
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 5157e319a..f8bdb7779 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | 24 | ||
| 25 | namespace OpenGL { | 25 | namespace OpenGL { |
| 26 | 26 | ||
| 27 | using ShaderCacheVersionHash = std::array<u8, 64>; | ||
| 28 | |||
| 27 | enum class TransferableEntryKind : u32 { | 29 | enum class TransferableEntryKind : u32 { |
| 28 | Raw, | 30 | Raw, |
| 29 | Usage, | 31 | Usage, |
| @@ -35,7 +37,6 @@ enum class PrecompiledEntryKind : u32 { | |||
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| 37 | constexpr u32 NativeVersion = 1; | 39 | constexpr u32 NativeVersion = 1; |
| 38 | constexpr u32 ShaderHashSize = 64; | ||
| 39 | 40 | ||
| 40 | // Making sure sizes doesn't change by accident | 41 | // Making sure sizes doesn't change by accident |
| 41 | static_assert(sizeof(BaseBindings) == 12); | 42 | static_assert(sizeof(BaseBindings) == 12); |
| @@ -46,10 +47,11 @@ std::string GetTitleID() { | |||
| 46 | return fmt::format("{:016X}", Core::CurrentProcess()->GetTitleID()); | 47 | return fmt::format("{:016X}", Core::CurrentProcess()->GetTitleID()); |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | std::string GetShaderHash() { | 50 | ShaderCacheVersionHash GetShaderCacheVersionHash() { |
| 50 | std::array<char, ShaderHashSize> hash{}; | 51 | ShaderCacheVersionHash hash{}; |
| 51 | std::strncpy(hash.data(), Common::g_shader_cache_version, ShaderHashSize); | 52 | const std::size_t length = std::min(std::strlen(Common::g_shader_cache_version), hash.size()); |
| 52 | return std::string(hash.data(), hash.size()); | 53 | std::memcpy(hash.data(), Common::g_shader_cache_version, length); |
| 54 | return hash; | ||
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | template <typename T> | 57 | template <typename T> |
| @@ -82,50 +84,64 @@ std::vector<u8> DecompressData(const std::vector<u8>& compressed, std::size_t un | |||
| 82 | } | 84 | } |
| 83 | } // namespace | 85 | } // namespace |
| 84 | 86 | ||
| 85 | ShaderDiskCacheRaw::ShaderDiskCacheRaw(FileUtil::IOFile& file) { | 87 | ShaderDiskCacheRaw::ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, |
| 86 | file.ReadBytes(&unique_identifier, sizeof(u64)); | 88 | u32 program_code_size, u32 program_code_size_b, |
| 87 | file.ReadBytes(&program_type, sizeof(u32)); | 89 | ProgramCode program_code, ProgramCode program_code_b) |
| 90 | : unique_identifier{unique_identifier}, program_type{program_type}, | ||
| 91 | program_code_size{program_code_size}, program_code_size_b{program_code_size_b}, | ||
| 92 | program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} {} | ||
| 93 | |||
| 94 | ShaderDiskCacheRaw::ShaderDiskCacheRaw() = default; | ||
| 88 | 95 | ||
| 96 | ShaderDiskCacheRaw::~ShaderDiskCacheRaw() = default; | ||
| 97 | |||
| 98 | bool ShaderDiskCacheRaw::Load(FileUtil::IOFile& file) { | ||
| 99 | if (file.ReadBytes(&unique_identifier, sizeof(u64)) != sizeof(u64) || | ||
| 100 | file.ReadBytes(&program_type, sizeof(u32)) != sizeof(u32)) { | ||
| 101 | return false; | ||
| 102 | } | ||
| 89 | u32 program_code_size{}; | 103 | u32 program_code_size{}; |
| 90 | u32 program_code_size_b{}; | 104 | u32 program_code_size_b{}; |
| 91 | file.ReadBytes(&program_code_size, sizeof(u32)); | 105 | if (file.ReadBytes(&program_code_size, sizeof(u32)) != sizeof(u32) || |
| 92 | file.ReadBytes(&program_code_size_b, sizeof(u32)); | 106 | file.ReadBytes(&program_code_size_b, sizeof(u32)) != sizeof(u32)) { |
| 107 | return false; | ||
| 108 | } | ||
| 93 | 109 | ||
| 94 | program_code.resize(program_code_size); | 110 | program_code.resize(program_code_size); |
| 95 | program_code_b.resize(program_code_size_b); | 111 | program_code_b.resize(program_code_size_b); |
| 96 | 112 | ||
| 97 | file.ReadArray(program_code.data(), program_code_size); | 113 | if (file.ReadArray(program_code.data(), program_code_size) != program_code_size) |
| 98 | if (HasProgramA()) { | 114 | return false; |
| 99 | file.ReadArray(program_code_b.data(), program_code_size_b); | 115 | |
| 116 | if (HasProgramA() && | ||
| 117 | file.ReadArray(program_code_b.data(), program_code_size_b) != program_code_size_b) { | ||
| 118 | return false; | ||
| 100 | } | 119 | } |
| 120 | return true; | ||
| 101 | } | 121 | } |
| 102 | 122 | ||
| 103 | ShaderDiskCacheRaw::ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, | 123 | bool ShaderDiskCacheRaw::Save(FileUtil::IOFile& file) const { |
| 104 | u32 program_code_size, u32 program_code_size_b, | 124 | if (file.WriteObject(unique_identifier) != 1 || |
| 105 | ProgramCode program_code, ProgramCode program_code_b) | 125 | file.WriteObject(static_cast<u32>(program_type)) != 1 || |
| 106 | : unique_identifier{unique_identifier}, program_type{program_type}, | 126 | file.WriteObject(program_code_size) != 1 || file.WriteObject(program_code_size_b) != 1) { |
| 107 | program_code_size{program_code_size}, program_code_size_b{program_code_size_b}, | 127 | return false; |
| 108 | program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} {} | 128 | } |
| 109 | |||
| 110 | ShaderDiskCacheRaw::~ShaderDiskCacheRaw() = default; | ||
| 111 | 129 | ||
| 112 | void ShaderDiskCacheRaw::Save(FileUtil::IOFile& file) const { | 130 | if (file.WriteArray(program_code.data(), program_code_size) != program_code_size) |
| 113 | file.WriteObject(unique_identifier); | 131 | return false; |
| 114 | file.WriteObject(static_cast<u32>(program_type)); | ||
| 115 | file.WriteObject(program_code_size); | ||
| 116 | file.WriteObject(program_code_size_b); | ||
| 117 | 132 | ||
| 118 | file.WriteArray(program_code.data(), program_code_size); | 133 | if (HasProgramA() && |
| 119 | if (HasProgramA()) { | 134 | file.WriteArray(program_code_b.data(), program_code_size_b) != program_code_size_b) { |
| 120 | file.WriteArray(program_code_b.data(), program_code_size_b); | 135 | return false; |
| 121 | } | 136 | } |
| 137 | return true; | ||
| 122 | } | 138 | } |
| 123 | 139 | ||
| 124 | std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> | 140 | std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> |
| 125 | ShaderDiskCacheOpenGL::LoadTransferable() { | 141 | ShaderDiskCacheOpenGL::LoadTransferable() { |
| 126 | if (!Settings::values.use_disk_shader_cache) { | 142 | if (!Settings::values.use_disk_shader_cache) |
| 127 | return {}; | 143 | return {}; |
| 128 | } | 144 | tried_to_load = true; |
| 129 | 145 | ||
| 130 | FileUtil::IOFile file(GetTransferablePath(), "rb"); | 146 | FileUtil::IOFile file(GetTransferablePath(), "rb"); |
| 131 | if (!file.IsOpen()) { | 147 | if (!file.IsOpen()) { |
| @@ -133,15 +149,19 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 133 | GetTitleID()); | 149 | GetTitleID()); |
| 134 | return {}; | 150 | return {}; |
| 135 | } | 151 | } |
| 136 | const u64 file_size = file.GetSize(); | ||
| 137 | 152 | ||
| 138 | u32 version{}; | 153 | u32 version{}; |
| 139 | file.ReadBytes(&version, sizeof(version)); | 154 | if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { |
| 155 | LOG_ERROR(Render_OpenGL, | ||
| 156 | "Failed to get transferable cache version for title id={} - skipping", | ||
| 157 | GetTitleID()); | ||
| 158 | return {}; | ||
| 159 | } | ||
| 140 | 160 | ||
| 141 | if (version < NativeVersion) { | 161 | if (version < NativeVersion) { |
| 142 | LOG_INFO(Render_OpenGL, "Transferable shader cache is old - removing"); | 162 | LOG_INFO(Render_OpenGL, "Transferable shader cache is old - removing"); |
| 143 | file.Close(); | 163 | file.Close(); |
| 144 | FileUtil::Delete(GetTransferablePath()); | 164 | InvalidateTransferable(); |
| 145 | return {}; | 165 | return {}; |
| 146 | } | 166 | } |
| 147 | if (version > NativeVersion) { | 167 | if (version > NativeVersion) { |
| @@ -153,25 +173,35 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 153 | // Version is valid, load the shaders | 173 | // Version is valid, load the shaders |
| 154 | std::vector<ShaderDiskCacheRaw> raws; | 174 | std::vector<ShaderDiskCacheRaw> raws; |
| 155 | std::vector<ShaderDiskCacheUsage> usages; | 175 | std::vector<ShaderDiskCacheUsage> usages; |
| 156 | while (file.Tell() < file_size) { | 176 | while (file.Tell() < file.GetSize()) { |
| 157 | TransferableEntryKind kind{}; | 177 | TransferableEntryKind kind{}; |
| 158 | file.ReadBytes(&kind, sizeof(u32)); | 178 | if (file.ReadBytes(&kind, sizeof(u32)) != sizeof(u32)) { |
| 179 | LOG_ERROR(Render_OpenGL, "Failed to read transferable file - skipping"); | ||
| 180 | return {}; | ||
| 181 | } | ||
| 159 | 182 | ||
| 160 | switch (kind) { | 183 | switch (kind) { |
| 161 | case TransferableEntryKind::Raw: { | 184 | case TransferableEntryKind::Raw: { |
| 162 | ShaderDiskCacheRaw entry{file}; | 185 | ShaderDiskCacheRaw entry; |
| 186 | if (!entry.Load(file)) { | ||
| 187 | LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry - skipping"); | ||
| 188 | return {}; | ||
| 189 | } | ||
| 163 | transferable.insert({entry.GetUniqueIdentifier(), {}}); | 190 | transferable.insert({entry.GetUniqueIdentifier(), {}}); |
| 164 | raws.push_back(std::move(entry)); | 191 | raws.push_back(std::move(entry)); |
| 165 | break; | 192 | break; |
| 166 | } | 193 | } |
| 167 | case TransferableEntryKind::Usage: { | 194 | case TransferableEntryKind::Usage: { |
| 168 | ShaderDiskCacheUsage usage{}; | 195 | ShaderDiskCacheUsage usage{}; |
| 169 | file.ReadBytes(&usage, sizeof(usage)); | 196 | if (file.ReadBytes(&usage, sizeof(usage)) != sizeof(usage)) { |
| 197 | LOG_ERROR(Render_OpenGL, "Failed to load transferable usage entry - skipping"); | ||
| 198 | return {}; | ||
| 199 | } | ||
| 170 | usages.push_back(std::move(usage)); | 200 | usages.push_back(std::move(usage)); |
| 171 | break; | 201 | break; |
| 172 | } | 202 | } |
| 173 | default: | 203 | default: |
| 174 | LOG_ERROR(Render_OpenGL, "Unknown transferable shader cache entry kind={} - aborting", | 204 | LOG_ERROR(Render_OpenGL, "Unknown transferable shader cache entry kind={} - skipping", |
| 175 | static_cast<u32>(kind)); | 205 | static_cast<u32>(kind)); |
| 176 | return {}; | 206 | return {}; |
| 177 | } | 207 | } |
| @@ -182,9 +212,8 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 182 | std::pair<std::map<u64, ShaderDiskCacheDecompiled>, | 212 | std::pair<std::map<u64, ShaderDiskCacheDecompiled>, |
| 183 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>> | 213 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>> |
| 184 | ShaderDiskCacheOpenGL::LoadPrecompiled() { | 214 | ShaderDiskCacheOpenGL::LoadPrecompiled() { |
| 185 | if (!Settings::values.use_disk_shader_cache) { | 215 | if (!IsUsable()) |
| 186 | return {}; | 216 | return {}; |
| 187 | } | ||
| 188 | 217 | ||
| 189 | FileUtil::IOFile file(GetPrecompiledPath(), "rb"); | 218 | FileUtil::IOFile file(GetPrecompiledPath(), "rb"); |
| 190 | if (!file.IsOpen()) { | 219 | if (!file.IsOpen()) { |
| @@ -192,119 +221,75 @@ ShaderDiskCacheOpenGL::LoadPrecompiled() { | |||
| 192 | GetTitleID()); | 221 | GetTitleID()); |
| 193 | return {}; | 222 | return {}; |
| 194 | } | 223 | } |
| 195 | const u64 file_size = file.GetSize(); | ||
| 196 | 224 | ||
| 197 | char precompiled_hash[ShaderHashSize]; | 225 | const auto result = LoadPrecompiledFile(file); |
| 198 | file.ReadBytes(&precompiled_hash, ShaderHashSize); | 226 | if (!result) { |
| 199 | if (precompiled_hash != GetShaderHash()) { | 227 | LOG_INFO(Render_OpenGL, |
| 200 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of yuzu - removing"); | 228 | "Failed to load precompiled cache for game with title id={} - removing", |
| 229 | GetTitleID()); | ||
| 201 | file.Close(); | 230 | file.Close(); |
| 202 | InvalidatePrecompiled(); | 231 | InvalidatePrecompiled(); |
| 203 | return {}; | 232 | return {}; |
| 204 | } | 233 | } |
| 234 | return *result; | ||
| 235 | } | ||
| 236 | |||
| 237 | std::optional<std::pair<std::map<u64, ShaderDiskCacheDecompiled>, | ||
| 238 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> | ||
| 239 | ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { | ||
| 240 | ShaderCacheVersionHash file_hash{}; | ||
| 241 | if (file.ReadArray(file_hash.data(), file_hash.size()) != file_hash.size()) { | ||
| 242 | return {}; | ||
| 243 | } | ||
| 244 | if (GetShaderCacheVersionHash() != file_hash) { | ||
| 245 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); | ||
| 246 | return {}; | ||
| 247 | } | ||
| 205 | 248 | ||
| 206 | std::map<u64, ShaderDiskCacheDecompiled> decompiled; | 249 | std::map<u64, ShaderDiskCacheDecompiled> decompiled; |
| 207 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; | 250 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; |
| 208 | while (file.Tell() < file_size) { | 251 | while (file.Tell() < file.GetSize()) { |
| 209 | PrecompiledEntryKind kind{}; | 252 | PrecompiledEntryKind kind{}; |
| 210 | file.ReadBytes(&kind, sizeof(u32)); | 253 | if (file.ReadBytes(&kind, sizeof(u32)) != sizeof(u32)) { |
| 254 | return {}; | ||
| 255 | } | ||
| 211 | 256 | ||
| 212 | switch (kind) { | 257 | switch (kind) { |
| 213 | case PrecompiledEntryKind::Decompiled: { | 258 | case PrecompiledEntryKind::Decompiled: { |
| 214 | ShaderDiskCacheDecompiled entry; | ||
| 215 | |||
| 216 | u64 unique_identifier{}; | 259 | u64 unique_identifier{}; |
| 217 | file.ReadBytes(&unique_identifier, sizeof(u64)); | 260 | if (file.ReadBytes(&unique_identifier, sizeof(u64)) != sizeof(u64)) |
| 218 | |||
| 219 | u32 code_size{}; | ||
| 220 | u32 compressed_code_size{}; | ||
| 221 | file.ReadBytes(&code_size, sizeof(u32)); | ||
| 222 | file.ReadBytes(&compressed_code_size, sizeof(u32)); | ||
| 223 | |||
| 224 | std::vector<u8> compressed_code(compressed_code_size); | ||
| 225 | file.ReadArray(compressed_code.data(), compressed_code.size()); | ||
| 226 | |||
| 227 | const std::vector<u8> code = DecompressData(compressed_code, code_size); | ||
| 228 | if (code.empty()) { | ||
| 229 | LOG_ERROR(Render_OpenGL, | ||
| 230 | "Failed to decompress GLSL code in precompiled shader={:016x} - removing", | ||
| 231 | unique_identifier); | ||
| 232 | InvalidatePrecompiled(); | ||
| 233 | return {}; | 261 | return {}; |
| 234 | } | ||
| 235 | entry.code = std::string(reinterpret_cast<const char*>(code.data()), code_size); | ||
| 236 | |||
| 237 | u32 const_buffers_count{}; | ||
| 238 | file.ReadBytes(&const_buffers_count, sizeof(u32)); | ||
| 239 | for (u32 i = 0; i < const_buffers_count; ++i) { | ||
| 240 | u32 max_offset{}, index{}; | ||
| 241 | u8 is_indirect{}; | ||
| 242 | file.ReadBytes(&max_offset, sizeof(u32)); | ||
| 243 | file.ReadBytes(&index, sizeof(u32)); | ||
| 244 | file.ReadBytes(&is_indirect, sizeof(u8)); | ||
| 245 | |||
| 246 | entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); | ||
| 247 | } | ||
| 248 | |||
| 249 | u32 samplers_count{}; | ||
| 250 | file.ReadBytes(&samplers_count, sizeof(u32)); | ||
| 251 | for (u32 i = 0; i < samplers_count; ++i) { | ||
| 252 | u64 offset{}, index{}; | ||
| 253 | u32 type{}; | ||
| 254 | u8 is_array{}, is_shadow{}; | ||
| 255 | file.ReadBytes(&offset, sizeof(u64)); | ||
| 256 | file.ReadBytes(&index, sizeof(u64)); | ||
| 257 | file.ReadBytes(&type, sizeof(u32)); | ||
| 258 | file.ReadBytes(&is_array, sizeof(u8)); | ||
| 259 | file.ReadBytes(&is_shadow, sizeof(u8)); | ||
| 260 | |||
| 261 | entry.entries.samplers.emplace_back( | ||
| 262 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | ||
| 263 | static_cast<Tegra::Shader::TextureType>(type), is_array != 0, is_shadow != 0); | ||
| 264 | } | ||
| 265 | 262 | ||
| 266 | u32 global_memory_count{}; | 263 | const auto entry = LoadDecompiledEntry(file); |
| 267 | file.ReadBytes(&global_memory_count, sizeof(u32)); | 264 | if (!entry) |
| 268 | for (u32 i = 0; i < global_memory_count; ++i) { | 265 | return {}; |
| 269 | u32 cbuf_index{}, cbuf_offset{}; | 266 | decompiled.insert({unique_identifier, std::move(*entry)}); |
| 270 | file.ReadBytes(&cbuf_index, sizeof(u32)); | ||
| 271 | file.ReadBytes(&cbuf_offset, sizeof(u32)); | ||
| 272 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset); | ||
| 273 | } | ||
| 274 | |||
| 275 | for (auto& clip_distance : entry.entries.clip_distances) { | ||
| 276 | u8 clip_distance_raw{}; | ||
| 277 | file.ReadBytes(&clip_distance_raw, sizeof(u8)); | ||
| 278 | clip_distance = clip_distance_raw != 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | u64 shader_length{}; | ||
| 282 | file.ReadBytes(&shader_length, sizeof(u64)); | ||
| 283 | entry.entries.shader_length = static_cast<std::size_t>(shader_length); | ||
| 284 | |||
| 285 | decompiled.insert({unique_identifier, std::move(entry)}); | ||
| 286 | break; | 267 | break; |
| 287 | } | 268 | } |
| 288 | case PrecompiledEntryKind::Dump: { | 269 | case PrecompiledEntryKind::Dump: { |
| 289 | ShaderDiskCacheUsage usage; | 270 | ShaderDiskCacheUsage usage; |
| 290 | file.ReadBytes(&usage, sizeof(usage)); | 271 | if (file.ReadBytes(&usage, sizeof(usage)) != sizeof(usage)) |
| 272 | return {}; | ||
| 291 | 273 | ||
| 292 | ShaderDiskCacheDump dump; | 274 | ShaderDiskCacheDump dump; |
| 293 | file.ReadBytes(&dump.binary_format, sizeof(u32)); | 275 | if (file.ReadBytes(&dump.binary_format, sizeof(u32)) != sizeof(u32)) |
| 276 | return {}; | ||
| 294 | 277 | ||
| 295 | u32 binary_length{}; | 278 | u32 binary_length{}; |
| 296 | u32 compressed_size{}; | 279 | u32 compressed_size{}; |
| 297 | file.ReadBytes(&binary_length, sizeof(u32)); | 280 | if (file.ReadBytes(&binary_length, sizeof(u32)) != sizeof(u32) || |
| 298 | file.ReadBytes(&compressed_size, sizeof(u32)); | 281 | file.ReadBytes(&compressed_size, sizeof(u32)) != sizeof(u32)) { |
| 282 | return {}; | ||
| 283 | } | ||
| 299 | 284 | ||
| 300 | std::vector<u8> compressed_binary(compressed_size); | 285 | std::vector<u8> compressed_binary(compressed_size); |
| 301 | file.ReadArray(compressed_binary.data(), compressed_binary.size()); | 286 | if (file.ReadArray(compressed_binary.data(), compressed_binary.size()) != |
| 287 | compressed_binary.size()) { | ||
| 288 | return {}; | ||
| 289 | } | ||
| 302 | 290 | ||
| 303 | dump.binary = DecompressData(compressed_binary, binary_length); | 291 | dump.binary = DecompressData(compressed_binary, binary_length); |
| 304 | if (dump.binary.empty()) { | 292 | if (dump.binary.empty()) { |
| 305 | LOG_ERROR(Render_OpenGL, | ||
| 306 | "Failed to decompress precompiled binary program - removing"); | ||
| 307 | InvalidatePrecompiled(); | ||
| 308 | return {}; | 293 | return {}; |
| 309 | } | 294 | } |
| 310 | 295 | ||
| @@ -312,28 +297,165 @@ ShaderDiskCacheOpenGL::LoadPrecompiled() { | |||
| 312 | break; | 297 | break; |
| 313 | } | 298 | } |
| 314 | default: | 299 | default: |
| 315 | LOG_ERROR(Render_OpenGL, "Unknown precompiled shader cache entry kind={} - removing", | ||
| 316 | static_cast<u32>(kind)); | ||
| 317 | InvalidatePrecompiled(); | ||
| 318 | return {}; | 300 | return {}; |
| 319 | } | 301 | } |
| 320 | } | 302 | } |
| 321 | return {decompiled, dumps}; | 303 | return {{decompiled, dumps}}; |
| 304 | } | ||
| 305 | |||
| 306 | std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEntry( | ||
| 307 | FileUtil::IOFile& file) { | ||
| 308 | u32 code_size{}; | ||
| 309 | u32 compressed_code_size{}; | ||
| 310 | if (file.ReadBytes(&code_size, sizeof(u32)) != sizeof(u32) || | ||
| 311 | file.ReadBytes(&compressed_code_size, sizeof(u32)) != sizeof(u32)) { | ||
| 312 | return {}; | ||
| 313 | } | ||
| 314 | |||
| 315 | std::vector<u8> compressed_code(compressed_code_size); | ||
| 316 | if (file.ReadArray(compressed_code.data(), compressed_code.size()) != compressed_code.size()) { | ||
| 317 | return {}; | ||
| 318 | } | ||
| 319 | |||
| 320 | const std::vector<u8> code = DecompressData(compressed_code, code_size); | ||
| 321 | if (code.empty()) { | ||
| 322 | return {}; | ||
| 323 | } | ||
| 324 | ShaderDiskCacheDecompiled entry; | ||
| 325 | entry.code = std::string(reinterpret_cast<const char*>(code.data()), code_size); | ||
| 326 | |||
| 327 | u32 const_buffers_count{}; | ||
| 328 | if (file.ReadBytes(&const_buffers_count, sizeof(u32)) != sizeof(u32)) | ||
| 329 | return {}; | ||
| 330 | for (u32 i = 0; i < const_buffers_count; ++i) { | ||
| 331 | u32 max_offset{}; | ||
| 332 | u32 index{}; | ||
| 333 | u8 is_indirect{}; | ||
| 334 | if (file.ReadBytes(&max_offset, sizeof(u32)) != sizeof(u32) || | ||
| 335 | file.ReadBytes(&index, sizeof(u32)) != sizeof(u32) || | ||
| 336 | file.ReadBytes(&is_indirect, sizeof(u8)) != sizeof(u8)) { | ||
| 337 | return {}; | ||
| 338 | } | ||
| 339 | entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); | ||
| 340 | } | ||
| 341 | |||
| 342 | u32 samplers_count{}; | ||
| 343 | if (file.ReadBytes(&samplers_count, sizeof(u32)) != sizeof(u32)) | ||
| 344 | return {}; | ||
| 345 | for (u32 i = 0; i < samplers_count; ++i) { | ||
| 346 | u64 offset{}; | ||
| 347 | u64 index{}; | ||
| 348 | u32 type{}; | ||
| 349 | u8 is_array{}; | ||
| 350 | u8 is_shadow{}; | ||
| 351 | if (file.ReadBytes(&offset, sizeof(u64)) != sizeof(u64) || | ||
| 352 | file.ReadBytes(&index, sizeof(u64)) != sizeof(u64) || | ||
| 353 | file.ReadBytes(&type, sizeof(u32)) != sizeof(u32) || | ||
| 354 | file.ReadBytes(&is_array, sizeof(u8)) != sizeof(u8) || | ||
| 355 | file.ReadBytes(&is_shadow, sizeof(u8)) != sizeof(u8)) { | ||
| 356 | return {}; | ||
| 357 | } | ||
| 358 | entry.entries.samplers.emplace_back( | ||
| 359 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | ||
| 360 | static_cast<Tegra::Shader::TextureType>(type), is_array != 0, is_shadow != 0); | ||
| 361 | } | ||
| 362 | |||
| 363 | u32 global_memory_count{}; | ||
| 364 | if (file.ReadBytes(&global_memory_count, sizeof(u32)) != sizeof(u32)) | ||
| 365 | return {}; | ||
| 366 | for (u32 i = 0; i < global_memory_count; ++i) { | ||
| 367 | u32 cbuf_index{}; | ||
| 368 | u32 cbuf_offset{}; | ||
| 369 | if (file.ReadBytes(&cbuf_index, sizeof(u32)) != sizeof(u32) || | ||
| 370 | file.ReadBytes(&cbuf_offset, sizeof(u32)) != sizeof(u32)) { | ||
| 371 | return {}; | ||
| 372 | } | ||
| 373 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset); | ||
| 374 | } | ||
| 375 | |||
| 376 | for (auto& clip_distance : entry.entries.clip_distances) { | ||
| 377 | u8 clip_distance_raw{}; | ||
| 378 | if (file.ReadBytes(&clip_distance_raw, sizeof(u8)) != sizeof(u8)) | ||
| 379 | return {}; | ||
| 380 | clip_distance = clip_distance_raw != 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | u64 shader_length{}; | ||
| 384 | if (file.ReadBytes(&shader_length, sizeof(u64)) != sizeof(u64)) | ||
| 385 | return {}; | ||
| 386 | entry.entries.shader_length = static_cast<std::size_t>(shader_length); | ||
| 387 | |||
| 388 | return entry; | ||
| 389 | } | ||
| 390 | |||
| 391 | bool ShaderDiskCacheOpenGL::SaveDecompiledFile(FileUtil::IOFile& file, u64 unique_identifier, | ||
| 392 | const std::string& code, | ||
| 393 | const std::vector<u8>& compressed_code, | ||
| 394 | const GLShader::ShaderEntries& entries) { | ||
| 395 | if (file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Decompiled)) != 1 || | ||
| 396 | file.WriteObject(unique_identifier) != 1 || | ||
| 397 | file.WriteObject(static_cast<u32>(code.size())) != 1 || | ||
| 398 | file.WriteObject(static_cast<u32>(compressed_code.size())) != 1 || | ||
| 399 | file.WriteArray(compressed_code.data(), compressed_code.size()) != compressed_code.size()) { | ||
| 400 | return false; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (file.WriteObject(static_cast<u32>(entries.const_buffers.size())) != 1) | ||
| 404 | return false; | ||
| 405 | for (const auto& cbuf : entries.const_buffers) { | ||
| 406 | if (file.WriteObject(static_cast<u32>(cbuf.GetMaxOffset())) != 1 || | ||
| 407 | file.WriteObject(static_cast<u32>(cbuf.GetIndex())) != 1 || | ||
| 408 | file.WriteObject(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0)) != 1) { | ||
| 409 | return false; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | if (file.WriteObject(static_cast<u32>(entries.samplers.size())) != 1) | ||
| 414 | return false; | ||
| 415 | for (const auto& sampler : entries.samplers) { | ||
| 416 | if (file.WriteObject(static_cast<u64>(sampler.GetOffset())) != 1 || | ||
| 417 | file.WriteObject(static_cast<u64>(sampler.GetIndex())) != 1 || | ||
| 418 | file.WriteObject(static_cast<u32>(sampler.GetType())) != 1 || | ||
| 419 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)) != 1 || | ||
| 420 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) != 1) { | ||
| 421 | return false; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | if (file.WriteObject(static_cast<u32>(entries.global_memory_entries.size())) != 1) | ||
| 426 | return false; | ||
| 427 | for (const auto& gmem : entries.global_memory_entries) { | ||
| 428 | if (file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())) != 1 || | ||
| 429 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())) != 1) { | ||
| 430 | return false; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | for (const bool clip_distance : entries.clip_distances) { | ||
| 435 | if (file.WriteObject(static_cast<u8>(clip_distance ? 1 : 0)) != 1) | ||
| 436 | return false; | ||
| 437 | } | ||
| 438 | |||
| 439 | return file.WriteObject(static_cast<u64>(entries.shader_length)) == 1; | ||
| 322 | } | 440 | } |
| 323 | 441 | ||
| 324 | bool ShaderDiskCacheOpenGL::InvalidateTransferable() const { | 442 | void ShaderDiskCacheOpenGL::InvalidateTransferable() const { |
| 325 | const bool success = FileUtil::Delete(GetTransferablePath()); | 443 | if (!FileUtil::Delete(GetTransferablePath())) { |
| 326 | return InvalidatePrecompiled() && success; | 444 | LOG_ERROR(Render_OpenGL, "Failed to invalidate transferable file={}", |
| 445 | GetTransferablePath()); | ||
| 446 | } | ||
| 447 | InvalidatePrecompiled(); | ||
| 327 | } | 448 | } |
| 328 | 449 | ||
| 329 | bool ShaderDiskCacheOpenGL::InvalidatePrecompiled() const { | 450 | void ShaderDiskCacheOpenGL::InvalidatePrecompiled() const { |
| 330 | return FileUtil::Delete(GetPrecompiledPath()); | 451 | if (!FileUtil::Delete(GetPrecompiledPath())) { |
| 452 | LOG_ERROR(Render_OpenGL, "Failed to invalidate precompiled file={}", GetPrecompiledPath()); | ||
| 453 | } | ||
| 331 | } | 454 | } |
| 332 | 455 | ||
| 333 | void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { | 456 | void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { |
| 334 | if (!Settings::values.use_disk_shader_cache) { | 457 | if (!IsUsable()) |
| 335 | return; | 458 | return; |
| 336 | } | ||
| 337 | 459 | ||
| 338 | const u64 id = entry.GetUniqueIdentifier(); | 460 | const u64 id = entry.GetUniqueIdentifier(); |
| 339 | if (transferable.find(id) != transferable.end()) { | 461 | if (transferable.find(id) != transferable.end()) { |
| @@ -342,47 +464,44 @@ void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { | |||
| 342 | } | 464 | } |
| 343 | 465 | ||
| 344 | FileUtil::IOFile file = AppendTransferableFile(); | 466 | FileUtil::IOFile file = AppendTransferableFile(); |
| 345 | if (!file.IsOpen()) { | 467 | if (!file.IsOpen()) |
| 468 | return; | ||
| 469 | if (file.WriteObject(TransferableEntryKind::Raw) != 1 || !entry.Save(file)) { | ||
| 470 | LOG_ERROR(Render_OpenGL, "Failed to save raw transferable cache entry - removing"); | ||
| 471 | file.Close(); | ||
| 472 | InvalidateTransferable(); | ||
| 346 | return; | 473 | return; |
| 347 | } | 474 | } |
| 348 | file.WriteObject(TransferableEntryKind::Raw); | ||
| 349 | entry.Save(file); | ||
| 350 | |||
| 351 | transferable.insert({id, {}}); | 475 | transferable.insert({id, {}}); |
| 352 | } | 476 | } |
| 353 | 477 | ||
| 354 | void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { | 478 | void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { |
| 355 | if (!Settings::values.use_disk_shader_cache) { | 479 | if (!IsUsable()) |
| 356 | return; | 480 | return; |
| 357 | } | ||
| 358 | 481 | ||
| 359 | const auto it = transferable.find(usage.unique_identifier); | 482 | const auto it = transferable.find(usage.unique_identifier); |
| 360 | if (it == transferable.end()) { | 483 | ASSERT_MSG(it != transferable.end(), "Saving shader usage without storing raw previously"); |
| 361 | LOG_CRITICAL(Render_OpenGL, "Saving shader usage without storing raw previously"); | 484 | |
| 362 | UNREACHABLE(); | ||
| 363 | } | ||
| 364 | auto& usages{it->second}; | 485 | auto& usages{it->second}; |
| 365 | ASSERT(usages.find(usage) == usages.end()); | 486 | ASSERT(usages.find(usage) == usages.end()); |
| 366 | usages.insert(usage); | 487 | usages.insert(usage); |
| 367 | 488 | ||
| 368 | FileUtil::IOFile file = AppendTransferableFile(); | 489 | FileUtil::IOFile file = AppendTransferableFile(); |
| 369 | if (!file.IsOpen()) { | 490 | if (!file.IsOpen()) |
| 491 | return; | ||
| 492 | |||
| 493 | if (file.WriteObject(TransferableEntryKind::Usage) != 1 || file.WriteObject(usage) != 1) { | ||
| 494 | LOG_ERROR(Render_OpenGL, "Failed to save usage transferable cache entry - removing"); | ||
| 495 | file.Close(); | ||
| 496 | InvalidateTransferable(); | ||
| 370 | return; | 497 | return; |
| 371 | } | 498 | } |
| 372 | file.WriteObject(TransferableEntryKind::Usage); | ||
| 373 | file.WriteObject(usage); | ||
| 374 | } | 499 | } |
| 375 | 500 | ||
| 376 | void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::string& code, | 501 | void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::string& code, |
| 377 | const GLShader::ShaderEntries& entries) { | 502 | const GLShader::ShaderEntries& entries) { |
| 378 | if (!Settings::values.use_disk_shader_cache) { | 503 | if (!IsUsable()) |
| 379 | return; | 504 | return; |
| 380 | } | ||
| 381 | |||
| 382 | FileUtil::IOFile file = AppendPrecompiledFile(); | ||
| 383 | if (!file.IsOpen()) { | ||
| 384 | return; | ||
| 385 | } | ||
| 386 | 505 | ||
| 387 | const std::vector<u8> compressed_code{CompressData(code.data(), code.size())}; | 506 | const std::vector<u8> compressed_code{CompressData(code.data(), code.size())}; |
| 388 | if (compressed_code.empty()) { | 507 | if (compressed_code.empty()) { |
| @@ -391,52 +510,21 @@ void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::str | |||
| 391 | return; | 510 | return; |
| 392 | } | 511 | } |
| 393 | 512 | ||
| 394 | file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Decompiled)); | 513 | FileUtil::IOFile file = AppendPrecompiledFile(); |
| 395 | 514 | if (!file.IsOpen()) | |
| 396 | file.WriteObject(unique_identifier); | 515 | return; |
| 397 | |||
| 398 | file.WriteObject(static_cast<u32>(code.size())); | ||
| 399 | file.WriteObject(static_cast<u32>(compressed_code.size())); | ||
| 400 | file.WriteArray(compressed_code.data(), compressed_code.size()); | ||
| 401 | |||
| 402 | file.WriteObject(static_cast<u32>(entries.const_buffers.size())); | ||
| 403 | for (const auto& cbuf : entries.const_buffers) { | ||
| 404 | file.WriteObject(static_cast<u32>(cbuf.GetMaxOffset())); | ||
| 405 | file.WriteObject(static_cast<u32>(cbuf.GetIndex())); | ||
| 406 | file.WriteObject(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0)); | ||
| 407 | } | ||
| 408 | |||
| 409 | file.WriteObject(static_cast<u32>(entries.samplers.size())); | ||
| 410 | for (const auto& sampler : entries.samplers) { | ||
| 411 | file.WriteObject(static_cast<u64>(sampler.GetOffset())); | ||
| 412 | file.WriteObject(static_cast<u64>(sampler.GetIndex())); | ||
| 413 | file.WriteObject(static_cast<u32>(sampler.GetType())); | ||
| 414 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)); | ||
| 415 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)); | ||
| 416 | } | ||
| 417 | |||
| 418 | file.WriteObject(static_cast<u32>(entries.global_memory_entries.size())); | ||
| 419 | for (const auto& gmem : entries.global_memory_entries) { | ||
| 420 | file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())); | ||
| 421 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())); | ||
| 422 | } | ||
| 423 | 516 | ||
| 424 | for (const bool clip_distance : entries.clip_distances) { | 517 | if (!SaveDecompiledFile(file, unique_identifier, code, compressed_code, entries)) { |
| 425 | file.WriteObject(static_cast<u8>(clip_distance ? 1 : 0)); | 518 | LOG_ERROR(Render_OpenGL, |
| 519 | "Failed to save decompiled entry to the precompiled file - removing"); | ||
| 520 | file.Close(); | ||
| 521 | InvalidatePrecompiled(); | ||
| 426 | } | 522 | } |
| 427 | |||
| 428 | file.WriteObject(static_cast<u64>(entries.shader_length)); | ||
| 429 | } | 523 | } |
| 430 | 524 | ||
| 431 | void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { | 525 | void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { |
| 432 | if (!Settings::values.use_disk_shader_cache) { | 526 | if (!IsUsable()) |
| 433 | return; | 527 | return; |
| 434 | } | ||
| 435 | |||
| 436 | FileUtil::IOFile file = AppendPrecompiledFile(); | ||
| 437 | if (!file.IsOpen()) { | ||
| 438 | return; | ||
| 439 | } | ||
| 440 | 528 | ||
| 441 | GLint binary_length{}; | 529 | GLint binary_length{}; |
| 442 | glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binary_length); | 530 | glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binary_length); |
| @@ -452,20 +540,31 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p | |||
| 452 | return; | 540 | return; |
| 453 | } | 541 | } |
| 454 | 542 | ||
| 455 | file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Dump)); | 543 | FileUtil::IOFile file = AppendPrecompiledFile(); |
| 544 | if (!file.IsOpen()) | ||
| 545 | return; | ||
| 456 | 546 | ||
| 457 | file.WriteObject(usage); | 547 | if (file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Dump)) != 1 || |
| 548 | file.WriteObject(usage) != 1 || file.WriteObject(static_cast<u32>(binary_format)) != 1 || | ||
| 549 | file.WriteObject(static_cast<u32>(binary_length)) != 1 || | ||
| 550 | file.WriteObject(static_cast<u32>(compressed_binary.size())) != 1 || | ||
| 551 | file.WriteArray(compressed_binary.data(), compressed_binary.size()) != | ||
| 552 | compressed_binary.size()) { | ||
| 553 | LOG_ERROR(Render_OpenGL, "Failed to save binary program file in shader={:016x} - removing", | ||
| 554 | usage.unique_identifier); | ||
| 555 | file.Close(); | ||
| 556 | InvalidatePrecompiled(); | ||
| 557 | return; | ||
| 558 | } | ||
| 559 | } | ||
| 458 | 560 | ||
| 459 | file.WriteObject(static_cast<u32>(binary_format)); | 561 | bool ShaderDiskCacheOpenGL::IsUsable() const { |
| 460 | file.WriteObject(static_cast<u32>(binary_length)); | 562 | return tried_to_load && Settings::values.use_disk_shader_cache; |
| 461 | file.WriteObject(static_cast<u32>(compressed_binary.size())); | ||
| 462 | file.WriteArray(compressed_binary.data(), compressed_binary.size()); | ||
| 463 | } | 563 | } |
| 464 | 564 | ||
| 465 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { | 565 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { |
| 466 | if (!EnsureDirectories()) { | 566 | if (!EnsureDirectories()) |
| 467 | return {}; | 567 | return {}; |
| 468 | } | ||
| 469 | 568 | ||
| 470 | const auto transferable_path{GetTransferablePath()}; | 569 | const auto transferable_path{GetTransferablePath()}; |
| 471 | const bool existed = FileUtil::Exists(transferable_path); | 570 | const bool existed = FileUtil::Exists(transferable_path); |
| @@ -477,15 +576,18 @@ FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { | |||
| 477 | } | 576 | } |
| 478 | if (!existed || file.GetSize() == 0) { | 577 | if (!existed || file.GetSize() == 0) { |
| 479 | // If the file didn't exist, write its version | 578 | // If the file didn't exist, write its version |
| 480 | file.WriteObject(NativeVersion); | 579 | if (file.WriteObject(NativeVersion) != 1) { |
| 580 | LOG_ERROR(Render_OpenGL, "Failed to write transferable cache version in path={}", | ||
| 581 | transferable_path); | ||
| 582 | return {}; | ||
| 583 | } | ||
| 481 | } | 584 | } |
| 482 | return file; | 585 | return file; |
| 483 | } | 586 | } |
| 484 | 587 | ||
| 485 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendPrecompiledFile() const { | 588 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendPrecompiledFile() const { |
| 486 | if (!EnsureDirectories()) { | 589 | if (!EnsureDirectories()) |
| 487 | return {}; | 590 | return {}; |
| 488 | } | ||
| 489 | 591 | ||
| 490 | const auto precompiled_path{GetPrecompiledPath()}; | 592 | const auto precompiled_path{GetPrecompiledPath()}; |
| 491 | const bool existed = FileUtil::Exists(precompiled_path); | 593 | const bool existed = FileUtil::Exists(precompiled_path); |
| @@ -497,9 +599,12 @@ FileUtil::IOFile ShaderDiskCacheOpenGL::AppendPrecompiledFile() const { | |||
| 497 | } | 599 | } |
| 498 | 600 | ||
| 499 | if (!existed || file.GetSize() == 0) { | 601 | if (!existed || file.GetSize() == 0) { |
| 500 | std::array<char, ShaderHashSize> hash{}; | 602 | const auto hash{GetShaderCacheVersionHash()}; |
| 501 | std::strcpy(hash.data(), GetShaderHash().c_str()); | 603 | if (file.WriteArray(hash.data(), hash.size()) != hash.size()) { |
| 502 | file.WriteArray(hash.data(), hash.size()); | 604 | LOG_ERROR(Render_OpenGL, "Failed to write precompiled cache version hash in path={}", |
| 605 | precompiled_path); | ||
| 606 | return {}; | ||
| 607 | } | ||
| 503 | } | 608 | } |
| 504 | return file; | 609 | return file; |
| 505 | } | 610 | } |
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 4bffe4307..ddcd4cf51 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h | |||
| @@ -53,15 +53,15 @@ struct BaseBindings { | |||
| 53 | /// Describes a shader how it's used by the guest GPU | 53 | /// Describes a shader how it's used by the guest GPU |
| 54 | class ShaderDiskCacheRaw { | 54 | class ShaderDiskCacheRaw { |
| 55 | public: | 55 | public: |
| 56 | explicit ShaderDiskCacheRaw(FileUtil::IOFile& file); | ||
| 57 | |||
| 58 | explicit ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, | 56 | explicit ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, |
| 59 | u32 program_code_size, u32 program_code_size_b, | 57 | u32 program_code_size, u32 program_code_size_b, |
| 60 | ProgramCode program_code, ProgramCode program_code_b); | 58 | ProgramCode program_code, ProgramCode program_code_b); |
| 61 | 59 | ShaderDiskCacheRaw(); | |
| 62 | ~ShaderDiskCacheRaw(); | 60 | ~ShaderDiskCacheRaw(); |
| 63 | 61 | ||
| 64 | void Save(FileUtil::IOFile& file) const; | 62 | bool Load(FileUtil::IOFile& file); |
| 63 | |||
| 64 | bool Save(FileUtil::IOFile& file) const; | ||
| 65 | 65 | ||
| 66 | u64 GetUniqueIdentifier() const { | 66 | u64 GetUniqueIdentifier() const { |
| 67 | return unique_identifier; | 67 | return unique_identifier; |
| @@ -158,10 +158,10 @@ public: | |||
| 158 | LoadPrecompiled(); | 158 | LoadPrecompiled(); |
| 159 | 159 | ||
| 160 | /// Removes the transferable (and precompiled) cache file. | 160 | /// Removes the transferable (and precompiled) cache file. |
| 161 | bool InvalidateTransferable() const; | 161 | void InvalidateTransferable() const; |
| 162 | 162 | ||
| 163 | /// Removes the precompiled cache file. | 163 | /// Removes the precompiled cache file. |
| 164 | bool InvalidatePrecompiled() const; | 164 | void InvalidatePrecompiled() const; |
| 165 | 165 | ||
| 166 | /// Saves a raw dump to the transferable file. Checks for collisions. | 166 | /// Saves a raw dump to the transferable file. Checks for collisions. |
| 167 | void SaveRaw(const ShaderDiskCacheRaw& entry); | 167 | void SaveRaw(const ShaderDiskCacheRaw& entry); |
| @@ -177,6 +177,22 @@ public: | |||
| 177 | void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program); | 177 | void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program); |
| 178 | 178 | ||
| 179 | private: | 179 | private: |
| 180 | /// Loads the transferable cache. Returns empty on failure. | ||
| 181 | std::optional<std::pair<std::map<u64, ShaderDiskCacheDecompiled>, | ||
| 182 | std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> | ||
| 183 | LoadPrecompiledFile(FileUtil::IOFile& file); | ||
| 184 | |||
| 185 | /// Loads a decompiled cache entry from the passed file. Returns empty on failure. | ||
| 186 | std::optional<ShaderDiskCacheDecompiled> LoadDecompiledEntry(FileUtil::IOFile& file); | ||
| 187 | |||
| 188 | /// Saves a decompiled entry to the passed file. Returns true on success. | ||
| 189 | bool SaveDecompiledFile(FileUtil::IOFile& file, u64 unique_identifier, const std::string& code, | ||
| 190 | const std::vector<u8>& compressed_code, | ||
| 191 | const GLShader::ShaderEntries& entries); | ||
| 192 | |||
| 193 | /// Returns if the cache can be used | ||
| 194 | bool IsUsable() const; | ||
| 195 | |||
| 180 | /// Opens current game's transferable file and write it's header if it doesn't exist | 196 | /// Opens current game's transferable file and write it's header if it doesn't exist |
| 181 | FileUtil::IOFile AppendTransferableFile() const; | 197 | FileUtil::IOFile AppendTransferableFile() const; |
| 182 | 198 | ||
| @@ -203,6 +219,8 @@ private: | |||
| 203 | 219 | ||
| 204 | // Stored transferable shaders | 220 | // Stored transferable shaders |
| 205 | std::map<u64, std::set<ShaderDiskCacheUsage>> transferable; | 221 | std::map<u64, std::set<ShaderDiskCacheUsage>> transferable; |
| 222 | // The cache has been loaded at boot | ||
| 223 | bool tried_to_load{}; | ||
| 206 | }; | 224 | }; |
| 207 | 225 | ||
| 208 | } // namespace OpenGL \ No newline at end of file | 226 | } // namespace OpenGL \ No newline at end of file |