GLES: Cache equal flag, load from cache.

This commit is contained in:
Unknown W. Brackets 2022-12-13 22:26:46 -08:00
parent 5749b5a825
commit 06045b9459
5 changed files with 67 additions and 34 deletions

View file

@ -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();

View file

@ -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();

View file

@ -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<std::string> 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();

View file

@ -580,8 +580,9 @@ struct GPUStateCache {
}
void SetUseFlags(u32 newFlags) {
if (newFlags != useFlags_) {
if (useFlags_ != 0)
useFlagsChanged = true;
useFlags_ = newFlags;
useFlagsChanged = true;
}
}

View file

@ -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.