diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 9d33c11210..a41dc68ee4 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -98,7 +98,20 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE)); shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".glshadercache"); // Actually precompiled by IsReady() since we're single-threaded. - shaderManagerGL_->Load(shaderCachePath_); + File::IOFile f(shaderCachePath_, "rb"); + if (f.IsOpen()) { + if (shaderManagerGL_->LoadCacheFlags(f, &drawEngine_)) { + if (drawEngineCommon_->EverUsedExactEqualDepth()) { + sawExactEqualDepth_ = true; + } + gstate_c.SetUseFlags(CheckGPUFeatures()); + // We're compiling now, clear if they changed. + gstate_c.useFlagsChanged = false; + + if (shaderManagerGL_->LoadCache(f)) + NOTICE_LOG(G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str()); + } + } } else { INFO_LOG(G3D, "Shader cache disabled. Not loading."); } @@ -125,7 +138,7 @@ GPU_GLES::~GPU_GLES() { if (shaderCachePath_.Valid() && draw_) { if (g_Config.bShaderCache) { - shaderManagerGL_->Save(shaderCachePath_); + shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_); } else { INFO_LOG(G3D, "Shader cache disabled. Not saving."); } @@ -297,7 +310,7 @@ void GPU_GLES::BeginFrame() { // Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often. if (shaderCachePath_.Valid() && (gpuStats.numFlips & 4095) == 0) { - shaderManagerGL_->Save(shaderCachePath_); + shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_); } shaderManagerGL_->DirtyShader(); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 6bc869c860..e66c31f9be 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -936,30 +936,48 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // If things like GPU supported features have changed since the last time, we discard the cache // as sometimes these features might have an effect on the ID bits. +enum class CacheDetectFlags { + EQUAL_DEPTH = 1, +}; + #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 20 +#define CACHE_VERSION 21 struct CacheHeader { uint32_t magic; uint32_t version; uint32_t useFlags; - uint32_t reserved; + uint32_t detectFlags; int numVertexShaders; int numFragmentShaders; int numLinkedPrograms; }; -void ShaderManagerGLES::Load(const Path &filename) { - File::IOFile f(filename, "rb"); - u64 sz = f.GetSize(); - if (!f.IsOpen()) { - return; - } +bool ShaderManagerGLES::LoadCacheFlags(File::IOFile &f, DrawEngineGLES *drawEngine) { CacheHeader header; if (!f.ReadArray(&header, 1)) { - return; + return false; } - if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.GetUseFlags()) { - return; + if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION) { + return false; + } + + if ((header.detectFlags & (uint32_t)CacheDetectFlags::EQUAL_DEPTH) != 0) { + drawEngine->SetEverUsedExactEqualDepth(true); + } + + return true; +} + +bool ShaderManagerGLES::LoadCache(File::IOFile &f) { + u64 sz = f.GetSize(); + f.Seek(0, SEEK_SET); + CacheHeader header; + if (!f.ReadArray(&header, 1)) { + return false; + } + // We don't recheck the version, done in LoadCacheFlags(). + if (header.useFlags != gstate_c.GetUseFlags()) { + return false; } diskCachePending_.start = time_now_d(); diskCachePending_.Clear(); @@ -967,7 +985,7 @@ void ShaderManagerGLES::Load(const Path &filename) { // Sanity check the file contents if (header.numFragmentShaders > 1000 || header.numVertexShaders > 1000 || header.numLinkedPrograms > 1000) { ERROR_LOG(G3D, "Corrupt shader cache file header, aborting."); - return; + return false; } // Also make sure the size makes sense, in case there's corruption. @@ -977,37 +995,37 @@ void ShaderManagerGLES::Load(const Path &filename) { expectedSize += header.numLinkedPrograms * (sizeof(VShaderID) + sizeof(FShaderID)); if (sz != expectedSize) { ERROR_LOG(G3D, "Shader cache file is wrong size: %lld instead of %lld", sz, expectedSize); - return; + return false; } diskCachePending_.vert.resize(header.numVertexShaders); if (!f.ReadArray(&diskCachePending_.vert[0], header.numVertexShaders)) { diskCachePending_.vert.clear(); - return; + return false; } diskCachePending_.frag.resize(header.numFragmentShaders); if (!f.ReadArray(&diskCachePending_.frag[0], header.numFragmentShaders)) { diskCachePending_.vert.clear(); diskCachePending_.frag.clear(); - return; + return false; } for (int i = 0; i < header.numLinkedPrograms; i++) { VShaderID vsid; FShaderID fsid; if (!f.ReadArray(&vsid, 1)) { - return; + return false; } if (!f.ReadArray(&fsid, 1)) { - return; + return false; } diskCachePending_.link.emplace_back(vsid, fsid); } // Actual compilation happens in ContinuePrecompile(), called by GPU_GLES's IsReady. - NOTICE_LOG(G3D, "Precompiling the shader cache from '%s'", filename.c_str()); diskCacheDirty_ = false; + return true; } bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) { @@ -1096,7 +1114,7 @@ void ShaderManagerGLES::CancelPrecompile() { diskCachePending_.Clear(); } -void ShaderManagerGLES::Save(const Path &filename) { +void ShaderManagerGLES::SaveCache(const Path &filename, DrawEngineGLES *drawEngine) { if (!diskCacheDirty_) { return; } @@ -1113,7 +1131,9 @@ void ShaderManagerGLES::Save(const Path &filename) { CacheHeader header; header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; - header.reserved = 0; + header.detectFlags = 0; + if (drawEngine->EverUsedExactEqualDepth()) + header.detectFlags |= (uint32_t)CacheDetectFlags::EQUAL_DEPTH; header.useFlags = gstate_c.GetUseFlags(); header.numVertexShaders = GetNumVertexShaders(); header.numFragmentShaders = GetNumFragmentShaders(); diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 05f168d036..6520b1e4ad 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -27,9 +27,14 @@ #include "GPU/Common/VertexShaderGenerator.h" #include "GPU/Common/FragmentShaderGenerator.h" +class DrawEngineGLES; class Shader; struct ShaderLanguageDesc; +namespace File { +class IOFile; +} + class LinkedShader { public: LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading = false); @@ -177,10 +182,11 @@ public: std::vector DebugGetShaderIDs(DebugShaderType type); std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType); - void Load(const Path &filename); + bool LoadCacheFlags(File::IOFile &f, DrawEngineGLES *drawEngine); + bool LoadCache(File::IOFile &f); bool ContinuePrecompile(float sliceTime = 1.0f / 60.0f); void CancelPrecompile(); - void Save(const Path &filename); + void SaveCache(const Path &filename, DrawEngineGLES *drawEngine); private: void Clear(); diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 18b3cdcf4d..3c3002a337 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -580,8 +580,9 @@ struct GPUStateCache { } void SetUseFlags(u32 newFlags) { if (newFlags != useFlags_) { + if (useFlags_ != 0) + useFlagsChanged = true; useFlags_ = newFlags; - useFlagsChanged = true; } } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 549b760503..5be600da88 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -552,14 +552,7 @@ bool ShaderManagerVulkan::LoadCacheFlags(FILE *f, DrawEngineVulkan *drawEngine) bool ShaderManagerVulkan::LoadCache(FILE *f) { VulkanCacheHeader header{}; bool success = fread(&header, sizeof(header), 1, f) == 1; - if (!success || header.magic != CACHE_HEADER_MAGIC) { - WARN_LOG(G3D, "Shader cache magic mismatch"); - return false; - } - if (header.version != CACHE_VERSION) { - WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); - return false; - } + // We don't need to validate magic/version again, done in LoadCacheFlags(). if (header.useFlags != gstate_c.GetUseFlags()) { // This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run.