From 0ab17ab4062278ceed3a3dc28796493280e6d0a1 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 6 Jan 2019 03:58:43 -0300
Subject: [PATCH] gl_shader_cache: Use dirty flags for shaders

---
 src/video_core/engines/maxwell_3d.cpp              | 8 ++++++++
 src/video_core/engines/maxwell_3d.h                | 3 +++
 src/video_core/renderer_opengl/gl_rasterizer.cpp   | 4 +++-
 src/video_core/renderer_opengl/gl_shader_cache.cpp | 6 +++++-
 src/video_core/renderer_opengl/gl_shader_cache.h   | 4 ++++
 5 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index b19b3a75a..0ed7bc5d8 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -135,6 +135,14 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
 
     if (regs.reg_array[method_call.method] != method_call.argument) {
         regs.reg_array[method_call.method] = method_call.argument;
+        // Shader
+        constexpr u32 shader_registers_count =
+            sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32);
+        if (method_call.method >= MAXWELL3D_REG_INDEX(shader_config[0]) &&
+            method_call.method < MAXWELL3D_REG_INDEX(shader_config[0]) + shader_registers_count) {
+            dirty_flags.shaders = true;
+        }
+
         // Vertex format
         if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) &&
             method_call.method <
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0faff6fdf..d50e5a126 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1089,10 +1089,13 @@ public:
     MemoryManager& memory_manager;
 
     struct DirtyFlags {
+        bool shaders = true;
+
         bool vertex_attrib_format = true;
         u32 vertex_array = 0xFFFFFFFF;
 
         void OnMemoryWrite() {
+            shaders = true;
             vertex_array = 0xFFFFFFFF;
         }
     };
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 089daf96f..37f01d4f7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -293,7 +293,7 @@ DrawParameters RasterizerOpenGL::SetupDraw() {
 
 void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
     MICROPROFILE_SCOPE(OpenGL_Shader);
-    const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
+    auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
 
     // Next available bindpoints to use when uploading the const buffers and textures to the GLSL
     // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
@@ -376,6 +376,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
     }
 
     SyncClipEnabled(clip_distances);
+
+    gpu.dirty_flags.shaders = false;
 }
 
 void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index aea6bf1af..c785fffa3 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -188,6 +188,10 @@ void CachedShader::CalculateProperties() {
 ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {}
 
 Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
+    if (!Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.shaders) {
+        return last_shaders[static_cast<u32>(program)];
+    }
+
     const VAddr program_addr{GetShaderAddress(program)};
 
     // Look up shader in the cache based on address
@@ -199,7 +203,7 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
         Register(shader);
     }
 
-    return shader;
+    return last_shaders[static_cast<u32>(program)] = shader;
 }
 
 } // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index de3671acf..768747968 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <array>
 #include <map>
 #include <memory>
 
@@ -115,6 +116,9 @@ public:
 
     /// Gets the current specified shader stage program
     Shader GetStageProgram(Maxwell::ShaderProgram program);
+
+private:
+    std::array<Shader, Maxwell::MaxShaderProgram> last_shaders;
 };
 
 } // namespace OpenGL