diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 4f1db6e0c2..3fd3573bb4 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -504,29 +504,7 @@ void ProgramShaderCache::Init() // Read our shader cache, only if supported and enabled if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache) - { - GLint Supported; - glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); - if (!Supported) - { - ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So " - "disable shader cache."); - g_ogl_config.bSupportsGLSLCache = false; - } - else - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string cache_filename = - StringFromFormat("%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str()); - - ProgramShaderCacheInserter inserter; - g_program_disk_cache.OpenAndRead(cache_filename, inserter); - } - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - } + LoadProgramBinaries(); CreateHeader(); @@ -534,47 +512,99 @@ void ProgramShaderCache::Init() last_entry = nullptr; } +void ProgramShaderCache::Reload() +{ + const bool use_cache = g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache; + if (use_cache) + SaveProgramBinaries(); + + g_program_disk_cache.Close(); + DestroyShaders(); + + if (use_cache) + LoadProgramBinaries(); + + CurrentProgram = 0; + last_entry = nullptr; + last_uid = {}; +} + void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk - if (g_ogl_config.bSupportsGLSLCache) + if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache) + SaveProgramBinaries(); + g_program_disk_cache.Close(); + + DestroyShaders(); + s_buffer.reset(); +} + +void ProgramShaderCache::LoadProgramBinaries() +{ + GLint Supported; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); + if (!Supported) { - for (auto& entry : pshaders) + ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So " + "disable shader cache."); + g_ogl_config.bSupportsGLSLCache = false; + } + else + { + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string host_part = g_ActiveConfig.GetHostConfigFilename(); + std::string cache_filename = + StringFromFormat("%sogl-%s-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().GetGameID().c_str(), host_part.c_str()); + + ProgramShaderCacheInserter inserter; + g_program_disk_cache.OpenAndRead(cache_filename, inserter); + } + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); +} + +void ProgramShaderCache::SaveProgramBinaries() +{ + for (auto& entry : pshaders) + { + // Clear any prior error code + glGetError(); + + if (entry.second.in_cache) { - // Clear any prior error code - glGetError(); - - if (entry.second.in_cache) - { - continue; - } - - GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; - glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); - glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); - glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); - if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || - !binary_size) - { - continue; - } - - std::vector data(binary_size + sizeof(GLenum)); - u8* binary = &data[sizeof(GLenum)]; - GLenum* prog_format = (GLenum*)&data[0]; - glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); - if (glGetError() != GL_NO_ERROR) - { - continue; - } - - g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); + continue; } - g_program_disk_cache.Sync(); - g_program_disk_cache.Close(); + GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; + glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); + glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); + glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); + if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || + !binary_size) + { + continue; + } + + std::vector data(binary_size + sizeof(GLenum)); + u8* binary = &data[sizeof(GLenum)]; + GLenum* prog_format = (GLenum*)&data[0]; + glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); + if (glGetError() != GL_NO_ERROR) + { + continue; + } + + g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); } + g_program_disk_cache.Sync(); +} + +void ProgramShaderCache::DestroyShaders() +{ glUseProgram(0); for (auto& entry : pshaders) @@ -582,8 +612,6 @@ void ProgramShaderCache::Shutdown() entry.second.Destroy(); } pshaders.clear(); - - s_buffer.reset(); } void ProgramShaderCache::CreateHeader() diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index 7af4a2c38e..7b29c24314 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -72,6 +72,7 @@ public: static void UploadConstants(); static void Init(); + static void Reload(); static void Shutdown(); static void CreateHeader(); @@ -82,6 +83,10 @@ private: void Read(const SHADERUID& key, const u8* value, u32 value_size) override; }; + static void LoadProgramBinaries(); + static void SaveProgramBinaries(); + static void DestroyShaders(); + typedef std::map PCache; static PCache pshaders; static PCacheEntry* last_entry; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 3282489369..50a3d366cc 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -688,6 +688,7 @@ Renderer::Renderer() s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + m_last_host_config_bits = g_ActiveConfig.GetHostConfigBits(); // Handle VSync on/off s_vsync = g_ActiveConfig.IsVSync(); @@ -1469,6 +1470,15 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, UpdateActiveConfig(); g_texture_cache->OnConfigChanged(g_ActiveConfig); + // Invalidate shader cache when the host config changes. + u32 new_host_config_bits = g_ActiveConfig.GetHostConfigBits(); + if (new_host_config_bits != m_last_host_config_bits) + { + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + ProgramShaderCache::Reload(); + m_last_host_config_bits = new_host_config_bits; + } + // For testing zbuffer targets. // Renderer::SetZBufferRender(); // SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget, diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 8ec6a21e0d..dd1de56b6a 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -148,5 +148,8 @@ private: std::array m_last_frame_height = {}; bool m_last_frame_exported = false; AVIDump::Frame m_last_frame_state; + + // last host config state + u32 m_last_host_config_bits = 0; }; }