summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp204
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h53
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
412CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( 422CachedProgram 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
107ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) : system{system} {} 106ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system)
107 : system{system}, precompiled_cache_virtual_file_offset{0} {}
108 108
109std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> 109std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>>
110ShaderDiskCacheOpenGL::LoadTransferable() { 110ShaderDiskCacheOpenGL::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() {
208std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, 209std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>,
209 std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>> 210 std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>>
210ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { 211ShaderDiskCacheOpenGL::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
269std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEntry( 281std::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
356bool ShaderDiskCacheOpenGL::SaveDecompiledFile(FileUtil::IOFile& file, u64 unique_identifier, 369bool 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
408void ShaderDiskCacheOpenGL::InvalidateTransferable() const { 428void 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
416void ShaderDiskCacheOpenGL::InvalidatePrecompiled() const { 436void 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
540FileUtil::IOFile ShaderDiskCacheOpenGL::AppendPrecompiledFile() const { 556void 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
565void 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
564bool ShaderDiskCacheOpenGL::EnsureDirectories() const { 584bool 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
193private: 197private:
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};