diff --git a/Source/Core/VideoCommon/Src/ShaderGenCommon.h b/Source/Core/VideoCommon/Src/ShaderGenCommon.h index 8606a4e5b9..d41a9c6c46 100644 --- a/Source/Core/VideoCommon/Src/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/Src/ShaderGenCommon.h @@ -51,6 +51,11 @@ public: return memcmp(this->values, obj.values, sizeof(values)) == 0; } + bool operator != (const ShaderUid& obj) const + { + return memcmp(this->values, obj.values, sizeof(values)) != 0; + } + // TODO: Store last frame used and order by that? makes much more sense anyway... bool operator < (const ShaderUid& obj) const { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp index 53b0210919..6ce4e1e04c 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp @@ -23,6 +23,9 @@ #include "ImageWrite.h" #include "Render.h" +#include +#include + namespace OGL { @@ -353,14 +356,71 @@ GLuint ProgramShaderCache::CompileSingleShader (GLuint type, const char* code ) return result; } +template UidT GetPartialUid(const SHADERUID& uid); +template<> PixelShaderUid GetPartialUid(const SHADERUID& uid) { return uid.puid; } +template<> VertexShaderUid GetPartialUid(const SHADERUID& uid) { return uid.vuid; } + +template const std::string& GetShaderCode(const SHADER& shader); +template<> const std::string& GetShaderCode(const SHADER& shader) { return shader.strpprog; } +template<> const std::string& GetShaderCode(const SHADER& shader) { return shader.strvprog; } + +template +void CheckForUidMismatch(const ProgramShaderCache::PCache& cache, CodeT& new_code, const UidT& new_uid) +{ + static std::map s_shaders; + static std::vector s_uids; + + bool uid_is_indexed = std::find(s_uids.begin(), s_uids.end(), new_uid) != s_uids.end(); + if (!uid_is_indexed) + { + s_uids.push_back(new_uid); + s_shaders[new_uid] = new_code.GetBuffer(); + } + else + { + // uid is already in the index => check if there's a shader with the same uid but different code + auto& old_code = s_shaders[new_uid]; + if (strcmp(old_code.c_str(), new_code.GetBuffer()) != 0) + { + static int num_failures = 0; + + char szTemp[MAX_PATH]; + sprintf(szTemp, "%s%ssuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), + std::is_same::value ? "p" : std::is_same::value ? "v" : "o", + ++num_failures); + + // TODO: Should also dump uids + std::ofstream file; + OpenFStream(file, szTemp, std::ios_base::out); + file << "Old shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code.GetBuffer(); + file.close(); + + // TODO: Make this more idiot-proof + ERROR_LOG(VIDEO, "%s shader uid mismatch!", + std::is_same::value ? "Pixel" : std::is_same::value ? "Vertex" : "Other"); + } + } +} -void ProgramShaderCache::GetShaderId ( SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components ) +void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components) { GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components); GetVertexShaderUid(uid->vuid, components, API_OPENGL); -} + if (g_ActiveConfig.bEnableShaderDebugging) + { + PixelShaderCode pcode; + VertexShaderCode vcode; + + GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components); + GenerateVertexShaderCode(vcode, components, API_OPENGL); + + CheckForUidMismatch(pshaders, pcode, uid->puid); + CheckForUidMismatch(pshaders, vcode, uid->vuid); + } +} ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram(void)