From 758ad3f75d49be811237c297265038f80c16ee8c Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 29 Dec 2019 01:28:53 -0300
Subject: [PATCH] gl_state_tracker: Add dirty flags for buffers and divisors

---
 .../renderer_opengl/gl_rasterizer.cpp         | 51 +++++++++++--------
 .../renderer_opengl/gl_state_tracker.cpp      | 21 ++++++++
 .../renderer_opengl/gl_state_tracker.h        |  4 ++
 .../renderer_opengl/renderer_opengl.cpp       |  2 +
 4 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 211b11489b..bb89985ccb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -164,12 +164,22 @@ void RasterizerOpenGL::SetupVertexFormat() {
 
 void RasterizerOpenGL::SetupVertexBuffer() {
     auto& gpu = system.GPU().Maxwell3D();
-    const auto& regs = gpu.regs;
+    auto& flags = gpu.dirty.flags;
+    if (!flags[Dirty::VertexBuffers]) {
+        return;
+    }
+    flags[Dirty::VertexBuffers] = false;
 
     MICROPROFILE_SCOPE(OpenGL_VB);
 
     // Upload all guest vertex arrays sequentially to our buffer
-    for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
+    const auto& regs = gpu.regs;
+    for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
+        if (!flags[Dirty::VertexBuffer0 + index]) {
+            continue;
+        }
+        flags[Dirty::VertexBuffer0 + index] = false;
+
         const auto& vertex_array = regs.vertex_array[index];
         if (!vertex_array.IsEnabled()) {
             continue;
@@ -183,33 +193,30 @@ void RasterizerOpenGL::SetupVertexBuffer() {
         const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size);
 
         // Bind the vertex array to the buffer at the current offset.
-        vertex_array_pushbuffer.SetVertexBuffer(index, vertex_buffer, vertex_buffer_offset,
-                                                vertex_array.stride);
-
-        if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) {
-            // Enable vertex buffer instancing with the specified divisor.
-            glVertexBindingDivisor(index, vertex_array.divisor);
-        } else {
-            // Disable the vertex buffer instancing.
-            glVertexBindingDivisor(index, 0);
-        }
+        vertex_array_pushbuffer.SetVertexBuffer(static_cast<GLuint>(index), vertex_buffer,
+                                                vertex_buffer_offset, vertex_array.stride);
     }
 }
 
 void RasterizerOpenGL::SetupVertexInstances() {
     auto& gpu = system.GPU().Maxwell3D();
-    const auto& regs = gpu.regs;
+    auto& flags = gpu.dirty.flags;
+    if (!flags[Dirty::VertexInstances]) {
+        return;
+    }
+    flags[Dirty::VertexInstances] = false;
 
-    // Upload all guest vertex arrays sequentially to our buffer
-    for (u32 index = 0; index < 16; ++index) {
-        if (regs.instanced_arrays.IsInstancingEnabled(index) &&
-            regs.vertex_array[index].divisor != 0) {
-            // Enable vertex buffer instancing with the specified divisor.
-            glVertexBindingDivisor(index, regs.vertex_array[index].divisor);
-        } else {
-            // Disable the vertex buffer instancing.
-            glVertexBindingDivisor(index, 0);
+    const auto& regs = gpu.regs;
+    for (std::size_t index = 0; index < 16; ++index) {
+        if (!flags[Dirty::VertexInstance0 + index]) {
+            continue;
         }
+        flags[Dirty::VertexInstance0 + index] = false;
+
+        const auto gl_index = static_cast<GLuint>(index);
+        const bool instancing_enabled = regs.instanced_arrays.IsInstancingEnabled(gl_index);
+        const GLuint divisor = instancing_enabled ? regs.vertex_array[index].divisor : 0;
+        glVertexBindingDivisor(gl_index, divisor);
     }
 }
 
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
index 319fd825bb..7150b9247f 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.cpp
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -71,6 +71,26 @@ void SetupDirtyColorMasks(Tables& tables) {
     FillBlock(tables[1], OFF(color_mask), NUM(color_mask), ColorMasks);
 }
 
+void SetupDirtyVertexArrays(Tables& tables) {
+    static constexpr std::size_t num_array = 3;
+    static constexpr std::size_t instance_base_offset = 3;
+    for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) {
+        const std::size_t array_offset = OFF(vertex_array) + i * NUM(vertex_array[0]);
+        const std::size_t limit_offset = OFF(vertex_array_limit) + i * NUM(vertex_array_limit[0]);
+
+        FillBlock(tables, array_offset, num_array, VertexBuffer0 + i, VertexBuffers);
+        FillBlock(tables, limit_offset, NUM(vertex_array_limit), VertexBuffer0 + i, VertexBuffers);
+
+        const std::size_t instance_array_offset = array_offset + instance_base_offset;
+        tables[0][instance_array_offset] = static_cast<u8>(VertexInstance0 + i);
+        tables[1][instance_array_offset] = VertexInstances;
+
+        const std::size_t instance_offset = OFF(instanced_arrays) + i;
+        tables[0][instance_offset] = static_cast<u8>(VertexInstance0 + i);
+        tables[1][instance_offset] = VertexInstances;
+    }
+}
+
 void SetupDirtyVertexFormat(Tables& tables) {
     for (std::size_t i = 0; i < Regs::NumVertexAttributes; ++i) {
         const std::size_t offset = OFF(vertex_attrib_format) + i * NUM(vertex_attrib_format[0]);
@@ -115,6 +135,7 @@ void StateTracker::Initialize() {
     SetupDirtyColorMasks(tables);
     SetupDirtyViewports(tables);
     SetupDirtyScissors(tables);
+    SetupDirtyVertexArrays(tables);
     SetupDirtyVertexFormat(tables);
 
     auto& store = dirty.on_write_stores;
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h
index a368aefd75..85667cee1e 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.h
+++ b/src/video_core/renderer_opengl/gl_state_tracker.h
@@ -78,6 +78,10 @@ public:
 
         flags[OpenGL::Dirty::VertexBuffers] = true;
         flags[OpenGL::Dirty::VertexBuffer0] = true;
+
+        flags[OpenGL::Dirty::VertexInstances] = true;
+        flags[OpenGL::Dirty::VertexInstance0 + 0] = true;
+        flags[OpenGL::Dirty::VertexInstance0 + 1] = true;
     }
 
     void NotifyViewport0() {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index caa193c50b..cbe9164884 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -611,6 +611,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
 
     glEnableVertexAttribArray(PositionLocation);
     glEnableVertexAttribArray(TexCoordLocation);
+    glVertexAttribDivisor(PositionLocation, 0);
+    glVertexAttribDivisor(TexCoordLocation, 0);
     glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
                          offsetof(ScreenRectVertex, position));
     glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,