diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 204 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 53 |
3 files changed, 168 insertions, 101 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 2a81b1169..dd18052db 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -363,6 +363,10 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 363 | if (stop_loading) | 363 | if (stop_loading) |
| 364 | return; | 364 | return; |
| 365 | 365 | ||
| 366 | // Track if precompiled cache was altered during loading to know if we have to serialize the | ||
| 367 | // virtual precompiled cache file back to the hard drive | ||
| 368 | bool precompiled_cache_altered = false; | ||
| 369 | |||
| 366 | // Build shaders | 370 | // Build shaders |
| 367 | if (callback) | 371 | if (callback) |
| 368 | callback(VideoCore::LoadCallbackStage::Build, 0, usages.size()); | 372 | callback(VideoCore::LoadCallbackStage::Build, 0, usages.size()); |
| @@ -384,6 +388,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 384 | if (!shader) { | 388 | if (!shader) { |
| 385 | // Invalidate the precompiled cache if a shader dumped shader was rejected | 389 | // Invalidate the precompiled cache if a shader dumped shader was rejected |
| 386 | disk_cache.InvalidatePrecompiled(); | 390 | disk_cache.InvalidatePrecompiled(); |
| 391 | precompiled_cache_altered = true; | ||
| 387 | dumps.clear(); | 392 | dumps.clear(); |
| 388 | } | 393 | } |
| 389 | } | 394 | } |
| @@ -405,8 +410,13 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 405 | if (dumps.find(usage) == dumps.end()) { | 410 | if (dumps.find(usage) == dumps.end()) { |
| 406 | const auto& program = precompiled_programs.at(usage); | 411 | const auto& program = precompiled_programs.at(usage); |
| 407 | disk_cache.SaveDump(usage, program->handle); | 412 | disk_cache.SaveDump(usage, program->handle); |
| 413 | precompiled_cache_altered = true; | ||
| 408 | } | 414 | } |
| 409 | } | 415 | } |
| 416 | |||
| 417 | if (precompiled_cache_altered) { | ||
| 418 | disk_cache.SaveVirtualPrecompiledFile(); | ||
| 419 | } | ||
| 410 | } | 420 | } |
| 411 | 421 | ||
| 412 | CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( | 422 | CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( |
| @@ -524,4 +534,4 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | |||
| 524 | return last_shaders[static_cast<u32>(program)] = shader; | 534 | return last_shaders[static_cast<u32>(program)] = shader; |
| 525 | } | 535 | } |
| 526 | 536 | ||
| 527 | } // namespace OpenGL | 537 | } // namespace OpenGL \ No newline at end of file |
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 170d53e83..4c76f943f 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "common/file_util.h" | 11 | #include "common/file_util.h" |
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/scm_rev.h" | 13 | #include "common/scm_rev.h" |
| 14 | #include "common/zstd_compression.h" | ||
| 15 | 14 | ||
| 16 | #include "core/core.h" | 15 | #include "core/core.h" |
| 17 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| @@ -104,7 +103,8 @@ bool ShaderDiskCacheRaw::Save(FileUtil::IOFile& file) const { | |||
| 104 | return true; | 103 | return true; |
| 105 | } | 104 | } |
| 106 | 105 | ||
| 107 | ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) : system{system} {} | 106 | ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) |
| 107 | : system{system}, precompiled_cache_virtual_file_offset{0} {} | ||
| 108 | 108 | ||
| 109 | std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> | 109 | std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> |
| 110 | ShaderDiskCacheOpenGL::LoadTransferable() { | 110 | ShaderDiskCacheOpenGL::LoadTransferable() { |
| @@ -177,6 +177,7 @@ ShaderDiskCacheOpenGL::LoadTransferable() { | |||
| 177 | return {}; | 177 | return {}; |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | |||
| 180 | return {{raws, usages}}; | 181 | return {{raws, usages}}; |
| 181 | } | 182 | } |
| 182 | 183 | ||
| @@ -208,51 +209,62 @@ ShaderDiskCacheOpenGL::LoadPrecompiled() { | |||
| 208 | std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, | 209 | std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, |
| 209 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> | 210 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> |
| 210 | ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { | 211 | ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { |
| 212 | std::vector<u8> precompiled_cache(file.GetSize()); | ||
| 213 | file.ReadBytes(precompiled_cache.data(), precompiled_cache.size()); | ||
| 214 | SaveArrayToPrecompiled(precompiled_cache.data(), precompiled_cache.size()); | ||
| 215 | precompiled_cache_virtual_file_offset = 0; | ||
| 216 | |||
| 211 | ShaderCacheVersionHash file_hash{}; | 217 | ShaderCacheVersionHash file_hash{}; |
| 212 | if (file.ReadArray(file_hash.data(), file_hash.size()) != file_hash.size()) { | 218 | if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) { |
| 219 | precompiled_cache_virtual_file_offset = 0; | ||
| 213 | return {}; | 220 | return {}; |
| 214 | } | 221 | } |
| 215 | if (GetShaderCacheVersionHash() != file_hash) { | 222 | if (GetShaderCacheVersionHash() != file_hash) { |
| 216 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); | 223 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); |
| 224 | precompiled_cache_virtual_file_offset = 0; | ||
| 217 | return {}; | 225 | return {}; |
| 218 | } | 226 | } |
| 219 | 227 | ||
| 220 | std::unordered_map<u64, ShaderDiskCacheDecompiled> decompiled; | 228 | std::unordered_map<u64, ShaderDiskCacheDecompiled> decompiled; |
| 221 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; | 229 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; |
| 222 | while (file.Tell() < file.GetSize()) { | 230 | while (precompiled_cache_virtual_file_offset < precompiled_cache_virtual_file.GetSize()) { |
| 223 | PrecompiledEntryKind kind{}; | 231 | PrecompiledEntryKind kind{}; |
| 224 | if (file.ReadBytes(&kind, sizeof(u32)) != sizeof(u32)) { | 232 | if (!LoadObjectFromPrecompiled(kind)) { |
| 225 | return {}; | 233 | return {}; |
| 226 | } | 234 | } |
| 227 | 235 | ||
| 228 | switch (kind) { | 236 | switch (kind) { |
| 229 | case PrecompiledEntryKind::Decompiled: { | 237 | case PrecompiledEntryKind::Decompiled: { |
| 230 | u64 unique_identifier{}; | 238 | u64 unique_identifier{}; |
| 231 | if (file.ReadBytes(&unique_identifier, sizeof(u64)) != sizeof(u64)) | 239 | if (!LoadObjectFromPrecompiled(unique_identifier)) { |
| 232 | return {}; | 240 | return {}; |
| 241 | } | ||
| 233 | 242 | ||
| 234 | const auto entry = LoadDecompiledEntry(file); | 243 | const auto entry = LoadDecompiledEntry(); |
| 235 | if (!entry) | 244 | if (!entry) { |
| 236 | return {}; | 245 | return {}; |
| 246 | } | ||
| 237 | decompiled.insert({unique_identifier, std::move(*entry)}); | 247 | decompiled.insert({unique_identifier, std::move(*entry)}); |
| 238 | break; | 248 | break; |
| 239 | } | 249 | } |
| 240 | case PrecompiledEntryKind::Dump: { | 250 | case PrecompiledEntryKind::Dump: { |
| 241 | ShaderDiskCacheUsage usage; | 251 | ShaderDiskCacheUsage usage; |
| 242 | if (file.ReadBytes(&usage, sizeof(usage)) != sizeof(usage)) | 252 | if (!LoadObjectFromPrecompiled(usage)) { |
| 243 | return {}; | 253 | return {}; |
| 254 | } | ||
| 244 | 255 | ||
| 245 | ShaderDiskCacheDump dump; | 256 | ShaderDiskCacheDump dump; |
| 246 | if (file.ReadBytes(&dump.binary_format, sizeof(u32)) != sizeof(u32)) | 257 | if (!LoadObjectFromPrecompiled(dump.binary_format)) { |
| 247 | return {}; | 258 | return {}; |
| 259 | } | ||
| 248 | 260 | ||
| 249 | u32 binary_length{}; | 261 | u32 binary_length{}; |
| 250 | if (file.ReadBytes(&binary_length, sizeof(u32)) != sizeof(u32)) { | 262 | if (!LoadObjectFromPrecompiled(binary_length)) { |
| 251 | return {}; | 263 | return {}; |
| 252 | } | 264 | } |
| 253 | 265 | ||
| 254 | dump.binary.resize(binary_length); | 266 | dump.binary.resize(binary_length); |
| 255 | if (file.ReadArray(dump.binary.data(), binary_length) != binary_length) { | 267 | if (!LoadArrayFromPrecompiled(dump.binary.data(), dump.binary.size())) { |
| 256 | return {}; | 268 | return {}; |
| 257 | } | 269 | } |
| 258 | 270 | ||
| @@ -266,15 +278,14 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { | |||
| 266 | return {{decompiled, dumps}}; | 278 | return {{decompiled, dumps}}; |
| 267 | } | 279 | } |
| 268 | 280 | ||
| 269 | std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEntry( | 281 | std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEntry() { |
| 270 | FileUtil::IOFile& file) { | ||
| 271 | u32 code_size{}; | 282 | u32 code_size{}; |
| 272 | if (file.ReadBytes(&code_size, sizeof(u32)) != sizeof(u32)) { | 283 | if (!LoadObjectFromPrecompiled(code_size)) { |
| 273 | return {}; | 284 | return {}; |
| 274 | } | 285 | } |
| 275 | 286 | ||
| 276 | std::vector<u8> code(code_size); | 287 | std::vector<u8> code(code_size); |
| 277 | if (file.ReadArray(code.data(), code.size()) != code_size) { | 288 | if (!LoadArrayFromPrecompiled(code.data(), code.size())) { |
| 278 | return {}; | 289 | return {}; |
| 279 | } | 290 | } |
| 280 | 291 | ||
| @@ -282,23 +293,26 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 282 | entry.code = std::string(reinterpret_cast<const char*>(code.data()), code_size); | 293 | entry.code = std::string(reinterpret_cast<const char*>(code.data()), code_size); |
| 283 | 294 | ||
| 284 | u32 const_buffers_count{}; | 295 | u32 const_buffers_count{}; |
| 285 | if (file.ReadBytes(&const_buffers_count, sizeof(u32)) != sizeof(u32)) | 296 | if (!LoadObjectFromPrecompiled(const_buffers_count)) { |
| 286 | return {}; | 297 | return {}; |
| 298 | } | ||
| 299 | |||
| 287 | for (u32 i = 0; i < const_buffers_count; ++i) { | 300 | for (u32 i = 0; i < const_buffers_count; ++i) { |
| 288 | u32 max_offset{}; | 301 | u32 max_offset{}; |
| 289 | u32 index{}; | 302 | u32 index{}; |
| 290 | u8 is_indirect{}; | 303 | u8 is_indirect{}; |
| 291 | if (file.ReadBytes(&max_offset, sizeof(u32)) != sizeof(u32) || | 304 | if (!LoadObjectFromPrecompiled(max_offset) || !LoadObjectFromPrecompiled(index) || |
| 292 | file.ReadBytes(&index, sizeof(u32)) != sizeof(u32) || | 305 | !LoadObjectFromPrecompiled(is_indirect)) { |
| 293 | file.ReadBytes(&is_indirect, sizeof(u8)) != sizeof(u8)) { | ||
| 294 | return {}; | 306 | return {}; |
| 295 | } | 307 | } |
| 296 | entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); | 308 | entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); |
| 297 | } | 309 | } |
| 298 | 310 | ||
| 299 | u32 samplers_count{}; | 311 | u32 samplers_count{}; |
| 300 | if (file.ReadBytes(&samplers_count, sizeof(u32)) != sizeof(u32)) | 312 | if (!LoadObjectFromPrecompiled(samplers_count)) { |
| 301 | return {}; | 313 | return {}; |
| 314 | } | ||
| 315 | |||
| 302 | for (u32 i = 0; i < samplers_count; ++i) { | 316 | for (u32 i = 0; i < samplers_count; ++i) { |
| 303 | u64 offset{}; | 317 | u64 offset{}; |
| 304 | u64 index{}; | 318 | u64 index{}; |
| @@ -306,12 +320,9 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 306 | u8 is_array{}; | 320 | u8 is_array{}; |
| 307 | u8 is_shadow{}; | 321 | u8 is_shadow{}; |
| 308 | u8 is_bindless{}; | 322 | u8 is_bindless{}; |
| 309 | if (file.ReadBytes(&offset, sizeof(u64)) != sizeof(u64) || | 323 | if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || |
| 310 | file.ReadBytes(&index, sizeof(u64)) != sizeof(u64) || | 324 | !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_array) || |
| 311 | file.ReadBytes(&type, sizeof(u32)) != sizeof(u32) || | 325 | !LoadObjectFromPrecompiled(is_shadow) || !LoadObjectFromPrecompiled(is_bindless)) { |
| 312 | file.ReadBytes(&is_array, sizeof(u8)) != sizeof(u8) || | ||
| 313 | file.ReadBytes(&is_shadow, sizeof(u8)) != sizeof(u8) || | ||
| 314 | file.ReadBytes(&is_bindless, sizeof(u8)) != sizeof(u8)) { | ||
| 315 | return {}; | 326 | return {}; |
| 316 | } | 327 | } |
| 317 | entry.entries.samplers.emplace_back(static_cast<std::size_t>(offset), | 328 | entry.entries.samplers.emplace_back(static_cast<std::size_t>(offset), |
| @@ -321,17 +332,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 321 | } | 332 | } |
| 322 | 333 | ||
| 323 | u32 global_memory_count{}; | 334 | u32 global_memory_count{}; |
| 324 | if (file.ReadBytes(&global_memory_count, sizeof(u32)) != sizeof(u32)) | 335 | if (!LoadObjectFromPrecompiled(global_memory_count)) { |
| 325 | return {}; | 336 | return {}; |
| 337 | } | ||
| 338 | |||
| 326 | for (u32 i = 0; i < global_memory_count; ++i) { | 339 | for (u32 i = 0; i < global_memory_count; ++i) { |
| 327 | u32 cbuf_index{}; | 340 | u32 cbuf_index{}; |
| 328 | u32 cbuf_offset{}; | 341 | u32 cbuf_offset{}; |
| 329 | u8 is_read{}; | 342 | u8 is_read{}; |
| 330 | u8 is_written{}; | 343 | u8 is_written{}; |
| 331 | if (file.ReadBytes(&cbuf_index, sizeof(u32)) != sizeof(u32) || | 344 | if (!LoadObjectFromPrecompiled(cbuf_index) || !LoadObjectFromPrecompiled(cbuf_offset) || |
| 332 | file.ReadBytes(&cbuf_offset, sizeof(u32)) != sizeof(u32) || | 345 | !LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) { |
| 333 | file.ReadBytes(&is_read, sizeof(u8)) != sizeof(u8) || | ||
| 334 | file.ReadBytes(&is_written, sizeof(u8)) != sizeof(u8)) { | ||
| 335 | return {}; | 346 | return {}; |
| 336 | } | 347 | } |
| 337 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset, is_read != 0, | 348 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset, is_read != 0, |
| @@ -340,72 +351,81 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 340 | 351 | ||
| 341 | for (auto& clip_distance : entry.entries.clip_distances) { | 352 | for (auto& clip_distance : entry.entries.clip_distances) { |
| 342 | u8 clip_distance_raw{}; | 353 | u8 clip_distance_raw{}; |
| 343 | if (file.ReadBytes(&clip_distance_raw, sizeof(u8)) != sizeof(u8)) | 354 | if (!LoadObjectFromPrecompiled(clip_distance_raw)) |
| 344 | return {}; | 355 | return {}; |
| 345 | clip_distance = clip_distance_raw != 0; | 356 | clip_distance = clip_distance_raw != 0; |
| 346 | } | 357 | } |
| 347 | 358 | ||
| 348 | u64 shader_length{}; | 359 | u64 shader_length{}; |
| 349 | if (file.ReadBytes(&shader_length, sizeof(u64)) != sizeof(u64)) | 360 | if (!LoadObjectFromPrecompiled(shader_length)) { |
| 350 | return {}; | 361 | return {}; |
| 362 | } | ||
| 363 | |||
| 351 | entry.entries.shader_length = static_cast<std::size_t>(shader_length); | 364 | entry.entries.shader_length = static_cast<std::size_t>(shader_length); |
| 352 | 365 | ||
| 353 | return entry; | 366 | return entry; |
| 354 | } | 367 | } |
| 355 | 368 | ||
| 356 | bool ShaderDiskCacheOpenGL::SaveDecompiledFile(FileUtil::IOFile& file, u64 unique_identifier, | 369 | bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std::string& code, |
| 357 | const std::string& code, | ||
| 358 | const GLShader::ShaderEntries& entries) { | 370 | const GLShader::ShaderEntries& entries) { |
| 359 | if (file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Decompiled)) != 1 || | 371 | if (!SaveObjectToPrecompiled(static_cast<u32>(PrecompiledEntryKind::Decompiled)) || |
| 360 | file.WriteObject(unique_identifier) != 1 || | 372 | !SaveObjectToPrecompiled(unique_identifier) || |
| 361 | file.WriteObject(static_cast<u32>(code.size())) != 1 || | 373 | !SaveObjectToPrecompiled(static_cast<u32>(code.size())) || |
| 362 | file.WriteArray(code.data(), code.size()) != code.size()) { | 374 | !SaveArrayToPrecompiled(code.data(), code.size())) { |
| 363 | return false; | 375 | return false; |
| 364 | } | 376 | } |
| 365 | 377 | ||
| 366 | if (file.WriteObject(static_cast<u32>(entries.const_buffers.size())) != 1) | 378 | if (!SaveObjectToPrecompiled(static_cast<u32>(entries.const_buffers.size()))) { |
| 367 | return false; | 379 | return false; |
| 380 | } | ||
| 368 | for (const auto& cbuf : entries.const_buffers) { | 381 | for (const auto& cbuf : entries.const_buffers) { |
| 369 | if (file.WriteObject(static_cast<u32>(cbuf.GetMaxOffset())) != 1 || | 382 | if (!SaveObjectToPrecompiled(static_cast<u32>(cbuf.GetMaxOffset())) || |
| 370 | file.WriteObject(static_cast<u32>(cbuf.GetIndex())) != 1 || | 383 | !SaveObjectToPrecompiled(static_cast<u32>(cbuf.GetIndex())) || |
| 371 | file.WriteObject(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0)) != 1) { | 384 | !SaveObjectToPrecompiled(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0))) { |
| 372 | return false; | 385 | return false; |
| 373 | } | 386 | } |
| 374 | } | 387 | } |
| 375 | 388 | ||
| 376 | if (file.WriteObject(static_cast<u32>(entries.samplers.size())) != 1) | 389 | if (!SaveObjectToPrecompiled(static_cast<u32>(entries.samplers.size()))) { |
| 377 | return false; | 390 | return false; |
| 391 | } | ||
| 378 | for (const auto& sampler : entries.samplers) { | 392 | for (const auto& sampler : entries.samplers) { |
| 379 | if (file.WriteObject(static_cast<u64>(sampler.GetOffset())) != 1 || | 393 | if (!SaveObjectToPrecompiled(static_cast<u64>(sampler.GetOffset())) || |
| 380 | file.WriteObject(static_cast<u64>(sampler.GetIndex())) != 1 || | 394 | !SaveObjectToPrecompiled(static_cast<u64>(sampler.GetIndex())) || |
| 381 | file.WriteObject(static_cast<u32>(sampler.GetType())) != 1 || | 395 | !SaveObjectToPrecompiled(static_cast<u32>(sampler.GetType())) || |
| 382 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)) != 1 || | 396 | !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsArray() ? 1 : 0)) || |
| 383 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) != 1 || | 397 | !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) || |
| 384 | file.WriteObject(static_cast<u8>(sampler.IsBindless() ? 1 : 0)) != 1) { | 398 | !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsBindless() ? 1 : 0))) { |
| 385 | return false; | 399 | return false; |
| 386 | } | 400 | } |
| 387 | } | 401 | } |
| 388 | 402 | ||
| 389 | if (file.WriteObject(static_cast<u32>(entries.global_memory_entries.size())) != 1) | 403 | if (!SaveObjectToPrecompiled(static_cast<u32>(entries.global_memory_entries.size()))) { |
| 390 | return false; | 404 | return false; |
| 405 | } | ||
| 391 | for (const auto& gmem : entries.global_memory_entries) { | 406 | for (const auto& gmem : entries.global_memory_entries) { |
| 392 | if (file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())) != 1 || | 407 | if (!SaveObjectToPrecompiled(static_cast<u32>(gmem.GetCbufIndex())) || |
| 393 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())) != 1 || | 408 | !SaveObjectToPrecompiled(static_cast<u32>(gmem.GetCbufOffset())) || |
| 394 | file.WriteObject(static_cast<u8>(gmem.IsRead() ? 1 : 0)) != 1 || | 409 | !SaveObjectToPrecompiled(static_cast<u8>(gmem.IsRead() ? 1 : 0)) || |
| 395 | file.WriteObject(static_cast<u8>(gmem.IsWritten() ? 1 : 0)) != 1) { | 410 | !SaveObjectToPrecompiled(static_cast<u8>(gmem.IsWritten() ? 1 : 0))) { |
| 396 | return false; | 411 | return false; |
| 397 | } | 412 | } |
| 398 | } | 413 | } |
| 399 | 414 | ||
| 400 | for (const bool clip_distance : entries.clip_distances) { | 415 | for (const bool clip_distance : entries.clip_distances) { |
| 401 | if (file.WriteObject(static_cast<u8>(clip_distance ? 1 : 0)) != 1) | 416 | if (!SaveObjectToPrecompiled(static_cast<u8>(clip_distance ? 1 : 0))) { |
| 402 | return false; | 417 | return false; |
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { | ||
| 422 | return false; | ||
| 403 | } | 423 | } |
| 404 | 424 | ||
| 405 | return file.WriteObject(static_cast<u64>(entries.shader_length)) == 1; | 425 | return true; |
| 406 | } | 426 | } |
| 407 | 427 | ||
| 408 | void ShaderDiskCacheOpenGL::InvalidateTransferable() const { | 428 | void ShaderDiskCacheOpenGL::InvalidateTransferable() { |
| 409 | if (!FileUtil::Delete(GetTransferablePath())) { | 429 | if (!FileUtil::Delete(GetTransferablePath())) { |
| 410 | LOG_ERROR(Render_OpenGL, "Failed to invalidate transferable file={}", | 430 | LOG_ERROR(Render_OpenGL, "Failed to invalidate transferable file={}", |
| 411 | GetTransferablePath()); | 431 | GetTransferablePath()); |
| @@ -413,7 +433,10 @@ void ShaderDiskCacheOpenGL::InvalidateTransferable() const { | |||
| 413 | InvalidatePrecompiled(); | 433 | InvalidatePrecompiled(); |
| 414 | } | 434 | } |
| 415 | 435 | ||
| 416 | void ShaderDiskCacheOpenGL::InvalidatePrecompiled() const { | 436 | void ShaderDiskCacheOpenGL::InvalidatePrecompiled() { |
| 437 | // Clear virtaul precompiled cache file | ||
| 438 | precompiled_cache_virtual_file.Resize(0); | ||
| 439 | |||
| 417 | if (!FileUtil::Delete(GetPrecompiledPath())) { | 440 | if (!FileUtil::Delete(GetPrecompiledPath())) { |
| 418 | LOG_ERROR(Render_OpenGL, "Failed to invalidate precompiled file={}", GetPrecompiledPath()); | 441 | LOG_ERROR(Render_OpenGL, "Failed to invalidate precompiled file={}", GetPrecompiledPath()); |
| 419 | } | 442 | } |
| @@ -469,15 +492,13 @@ void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::str | |||
| 469 | if (!IsUsable()) | 492 | if (!IsUsable()) |
| 470 | return; | 493 | return; |
| 471 | 494 | ||
| 472 | FileUtil::IOFile file = AppendPrecompiledFile(); | 495 | if (precompiled_cache_virtual_file.GetSize() == 0) { |
| 473 | 496 | SavePrecompiledHeaderToVirtualPrecompiledCache(); | |
| 474 | if (!file.IsOpen()) | 497 | } |
| 475 | return; | ||
| 476 | 498 | ||
| 477 | if (!SaveDecompiledFile(file, unique_identifier, code, entries)) { | 499 | if (!SaveDecompiledFile(unique_identifier, code, entries)) { |
| 478 | LOG_ERROR(Render_OpenGL, | 500 | LOG_ERROR(Render_OpenGL, |
| 479 | "Failed to save decompiled entry to the precompiled file - removing"); | 501 | "Failed to save decompiled entry to the precompiled file - removing"); |
| 480 | file.Close(); | ||
| 481 | InvalidatePrecompiled(); | 502 | InvalidatePrecompiled(); |
| 482 | } | 503 | } |
| 483 | } | 504 | } |
| @@ -493,18 +514,13 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p | |||
| 493 | std::vector<u8> binary(binary_length); | 514 | std::vector<u8> binary(binary_length); |
| 494 | glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); | 515 | glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); |
| 495 | 516 | ||
| 496 | FileUtil::IOFile file = AppendPrecompiledFile(); | 517 | if (!SaveObjectToPrecompiled(static_cast<u32>(PrecompiledEntryKind::Dump)) || |
| 497 | 518 | !SaveObjectToPrecompiled(usage) || | |
| 498 | if (!file.IsOpen()) | 519 | !SaveObjectToPrecompiled(static_cast<u32>(binary_format)) || |
| 499 | return; | 520 | !SaveObjectToPrecompiled(static_cast<u32>(binary_length)) || |
| 500 | 521 | !SaveArrayToPrecompiled(binary.data(), binary.size())) { | |
| 501 | if (file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Dump)) != 1 || | ||
| 502 | file.WriteObject(usage) != 1 || file.WriteObject(static_cast<u32>(binary_format)) != 1 || | ||
| 503 | file.WriteObject(static_cast<u32>(binary_length)) != 1 || | ||
| 504 | file.WriteArray(binary.data(), binary.size()) != binary_length) { | ||
| 505 | LOG_ERROR(Render_OpenGL, "Failed to save binary program file in shader={:016x} - removing", | 522 | LOG_ERROR(Render_OpenGL, "Failed to save binary program file in shader={:016x} - removing", |
| 506 | usage.unique_identifier); | 523 | usage.unique_identifier); |
| 507 | file.Close(); | ||
| 508 | InvalidatePrecompiled(); | 524 | InvalidatePrecompiled(); |
| 509 | return; | 525 | return; |
| 510 | } | 526 | } |
| @@ -537,28 +553,32 @@ FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { | |||
| 537 | return file; | 553 | return file; |
| 538 | } | 554 | } |
| 539 | 555 | ||
| 540 | FileUtil::IOFile ShaderDiskCacheOpenGL::AppendPrecompiledFile() const { | 556 | void ShaderDiskCacheOpenGL::SavePrecompiledHeaderToVirtualPrecompiledCache() { |
| 541 | if (!EnsureDirectories()) | 557 | const auto hash{GetShaderCacheVersionHash()}; |
| 542 | return {}; | 558 | if (!SaveArrayToPrecompiled(hash.data(), hash.size())) { |
| 559 | LOG_ERROR( | ||
| 560 | Render_OpenGL, | ||
| 561 | "Failed to write precompiled cache version hash to virtual precompiled cache file"); | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | void ShaderDiskCacheOpenGL::SaveVirtualPrecompiledFile() { | ||
| 566 | precompiled_cache_virtual_file_offset = 0; | ||
| 567 | const std::vector<u8>& precompiled_cache = precompiled_cache_virtual_file.ReadAllBytes(); | ||
| 543 | 568 | ||
| 544 | const auto precompiled_path{GetPrecompiledPath()}; | 569 | const auto precompiled_path{GetPrecompiledPath()}; |
| 545 | const bool existed = FileUtil::Exists(precompiled_path); | 570 | FileUtil::IOFile file(precompiled_path, "wb"); |
| 546 | 571 | ||
| 547 | FileUtil::IOFile file(precompiled_path, "ab"); | ||
| 548 | if (!file.IsOpen()) { | 572 | if (!file.IsOpen()) { |
| 549 | LOG_ERROR(Render_OpenGL, "Failed to open precompiled cache in path={}", precompiled_path); | 573 | LOG_ERROR(Render_OpenGL, "Failed to open precompiled cache in path={}", precompiled_path); |
| 550 | return {}; | 574 | return; |
| 551 | } | 575 | } |
| 552 | 576 | if (file.WriteBytes(precompiled_cache.data(), precompiled_cache.size()) != | |
| 553 | if (!existed || file.GetSize() == 0) { | 577 | precompiled_cache.size()) { |
| 554 | const auto hash{GetShaderCacheVersionHash()}; | 578 | LOG_ERROR(Render_OpenGL, "Failed to write precompiled cache version in path={}", |
| 555 | if (file.WriteArray(hash.data(), hash.size()) != hash.size()) { | 579 | precompiled_path); |
| 556 | LOG_ERROR(Render_OpenGL, "Failed to write precompiled cache version hash in path={}", | 580 | return; |
| 557 | precompiled_path); | ||
| 558 | return {}; | ||
| 559 | } | ||
| 560 | } | 581 | } |
| 561 | return file; | ||
| 562 | } | 582 | } |
| 563 | 583 | ||
| 564 | bool ShaderDiskCacheOpenGL::EnsureDirectories() const { | 584 | bool ShaderDiskCacheOpenGL::EnsureDirectories() const { |
| @@ -599,4 +619,4 @@ std::string ShaderDiskCacheOpenGL::GetTitleID() const { | |||
| 599 | return fmt::format("{:016X}", system.CurrentProcess()->GetTitleID()); | 619 | return fmt::format("{:016X}", system.CurrentProcess()->GetTitleID()); |
| 600 | } | 620 | } |
| 601 | 621 | ||
| 602 | } // namespace OpenGL | 622 | } // namespace OpenGL \ No newline at end of file |
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 a2864c5e2..0142b2e3b 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include "common/assert.h" | 17 | #include "common/assert.h" |
| 18 | #include "common/common_types.h" | 18 | #include "common/common_types.h" |
| 19 | #include "core/file_sys/vfs_vector.h" | ||
| 19 | #include "video_core/engines/maxwell_3d.h" | 20 | #include "video_core/engines/maxwell_3d.h" |
| 20 | #include "video_core/renderer_opengl/gl_shader_gen.h" | 21 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 21 | 22 | ||
| @@ -172,10 +173,10 @@ public: | |||
| 172 | LoadPrecompiled(); | 173 | LoadPrecompiled(); |
| 173 | 174 | ||
| 174 | /// Removes the transferable (and precompiled) cache file. | 175 | /// Removes the transferable (and precompiled) cache file. |
| 175 | void InvalidateTransferable() const; | 176 | void InvalidateTransferable(); |
| 176 | 177 | ||
| 177 | /// Removes the precompiled cache file. | 178 | /// Removes the precompiled cache file and clears virtual precompiled cache file. |
| 178 | void InvalidatePrecompiled() const; | 179 | void InvalidatePrecompiled(); |
| 179 | 180 | ||
| 180 | /// Saves a raw dump to the transferable file. Checks for collisions. | 181 | /// Saves a raw dump to the transferable file. Checks for collisions. |
| 181 | void SaveRaw(const ShaderDiskCacheRaw& entry); | 182 | void SaveRaw(const ShaderDiskCacheRaw& entry); |
| @@ -190,17 +191,21 @@ public: | |||
| 190 | /// Saves a dump entry to the precompiled file. Does not check for collisions. | 191 | /// Saves a dump entry to the precompiled file. Does not check for collisions. |
| 191 | void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program); | 192 | void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program); |
| 192 | 193 | ||
| 194 | /// Serializes virtual precompiled shader cache file to real file | ||
| 195 | void SaveVirtualPrecompiledFile(); | ||
| 196 | |||
| 193 | private: | 197 | private: |
| 194 | /// Loads the transferable cache. Returns empty on failure. | 198 | /// Loads the transferable cache. Returns empty on failure. |
| 195 | std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, | 199 | std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, |
| 196 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> | 200 | std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> |
| 197 | LoadPrecompiledFile(FileUtil::IOFile& file); | 201 | LoadPrecompiledFile(FileUtil::IOFile& file); |
| 198 | 202 | ||
| 199 | /// Loads a decompiled cache entry from the passed file. Returns empty on failure. | 203 | /// Loads a decompiled cache entry from m_precompiled_cache_virtual_file. Returns empty on |
| 200 | std::optional<ShaderDiskCacheDecompiled> LoadDecompiledEntry(FileUtil::IOFile& file); | 204 | /// failure. |
| 205 | std::optional<ShaderDiskCacheDecompiled> LoadDecompiledEntry(); | ||
| 201 | 206 | ||
| 202 | /// Saves a decompiled entry to the passed file. Returns true on success. | 207 | /// Saves a decompiled entry to the passed file. Returns true on success. |
| 203 | bool SaveDecompiledFile(FileUtil::IOFile& file, u64 unique_identifier, const std::string& code, | 208 | bool SaveDecompiledFile(u64 unique_identifier, const std::string& code, |
| 204 | const GLShader::ShaderEntries& entries); | 209 | const GLShader::ShaderEntries& entries); |
| 205 | 210 | ||
| 206 | /// Returns if the cache can be used | 211 | /// Returns if the cache can be used |
| @@ -209,8 +214,8 @@ private: | |||
| 209 | /// Opens current game's transferable file and write it's header if it doesn't exist | 214 | /// Opens current game's transferable file and write it's header if it doesn't exist |
| 210 | FileUtil::IOFile AppendTransferableFile() const; | 215 | FileUtil::IOFile AppendTransferableFile() const; |
| 211 | 216 | ||
| 212 | /// Opens current game's precompiled file and write it's header if it doesn't exist | 217 | /// Save precompiled header to precompiled_cache_in_memory |
| 213 | FileUtil::IOFile AppendPrecompiledFile() const; | 218 | void SavePrecompiledHeaderToVirtualPrecompiledCache(); |
| 214 | 219 | ||
| 215 | /// Create shader disk cache directories. Returns true on success. | 220 | /// Create shader disk cache directories. Returns true on success. |
| 216 | bool EnsureDirectories() const; | 221 | bool EnsureDirectories() const; |
| @@ -233,10 +238,42 @@ private: | |||
| 233 | /// Get current game's title id | 238 | /// Get current game's title id |
| 234 | std::string GetTitleID() const; | 239 | std::string GetTitleID() const; |
| 235 | 240 | ||
| 241 | template <typename T> | ||
| 242 | bool SaveArrayToPrecompiled(const T* data, std::size_t length) { | ||
| 243 | const std::size_t write_length = precompiled_cache_virtual_file.WriteArray( | ||
| 244 | data, length, precompiled_cache_virtual_file_offset); | ||
| 245 | precompiled_cache_virtual_file_offset += write_length; | ||
| 246 | return write_length == sizeof(T) * length; | ||
| 247 | } | ||
| 248 | |||
| 249 | template <typename T> | ||
| 250 | bool LoadArrayFromPrecompiled(T* data, std::size_t length) { | ||
| 251 | const std::size_t read_length = precompiled_cache_virtual_file.ReadArray( | ||
| 252 | data, length, precompiled_cache_virtual_file_offset); | ||
| 253 | precompiled_cache_virtual_file_offset += read_length; | ||
| 254 | return read_length == sizeof(T) * length; | ||
| 255 | } | ||
| 256 | |||
| 257 | template <typename T> | ||
| 258 | bool SaveObjectToPrecompiled(const T& object) { | ||
| 259 | return SaveArrayToPrecompiled(&object, 1); | ||
| 260 | } | ||
| 261 | |||
| 262 | template <typename T> | ||
| 263 | bool LoadObjectFromPrecompiled(T& object) { | ||
| 264 | return LoadArrayFromPrecompiled(&object, 1); | ||
| 265 | } | ||
| 266 | |||
| 236 | // Copre system | 267 | // Copre system |
| 237 | Core::System& system; | 268 | Core::System& system; |
| 238 | // Stored transferable shaders | 269 | // Stored transferable shaders |
| 239 | std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; | 270 | std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; |
| 271 | // Stores whole precompiled cache which will be read from or saved to the precompiled chache | ||
| 272 | // file | ||
| 273 | FileSys::VectorVfsFile precompiled_cache_virtual_file; | ||
| 274 | // Stores the current offset of the precompiled cache file for IO purposes | ||
| 275 | std::size_t precompiled_cache_virtual_file_offset; | ||
| 276 | |||
| 240 | // The cache has been loaded at boot | 277 | // The cache has been loaded at boot |
| 241 | bool tried_to_load{}; | 278 | bool tried_to_load{}; |
| 242 | }; | 279 | }; |