From 69ad6279e45db408ba3add0b540660ae34ba8e3f Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sat, 28 Dec 2019 23:08:40 -0300
Subject: [PATCH] gl_state_tracker: Implement dirty flags for vertex formats

---
 .../renderer_opengl/gl_rasterizer.cpp         | 28 +++++++++++++------
 .../renderer_opengl/gl_state_tracker.cpp      | 10 +++++++
 .../renderer_opengl/gl_state_tracker.h        | 12 ++++++++
 .../renderer_opengl/renderer_opengl.cpp       |  3 ++
 4 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b4cec274da..211b11489b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -120,7 +120,11 @@ void RasterizerOpenGL::CheckExtensions() {
 
 void RasterizerOpenGL::SetupVertexFormat() {
     auto& gpu = system.GPU().Maxwell3D();
-    const auto& regs = gpu.regs;
+    auto& flags = gpu.dirty.flags;
+    if (!flags[Dirty::VertexFormats]) {
+        return;
+    }
+    flags[Dirty::VertexFormats] = false;
 
     MICROPROFILE_SCOPE(OpenGL_VAO);
 
@@ -130,25 +134,31 @@ void RasterizerOpenGL::SetupVertexFormat() {
     // avoid OpenGL errors.
     // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
     // assume every shader uses them all.
-    for (u32 index = 0; index < 16; ++index) {
-        const auto& attrib = regs.vertex_attrib_format[index];
+    for (std::size_t index = 0; index < 16; ++index) {
+        if (!flags[Dirty::VertexFormat0 + index]) {
+            continue;
+        }
+        flags[Dirty::VertexFormat0 + index] = false;
+
+        const auto attrib = gpu.regs.vertex_attrib_format[index];
+        const auto gl_index = static_cast<GLuint>(index);
 
         // Ignore invalid attributes.
         if (!attrib.IsValid()) {
-            glDisableVertexAttribArray(index);
+            glDisableVertexAttribArray(gl_index);
             continue;
         }
-        glEnableVertexAttribArray(index);
+        glEnableVertexAttribArray(gl_index);
 
         if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt ||
             attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) {
-            glVertexAttribIFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
-                                  attrib.offset);
+            glVertexAttribIFormat(gl_index, attrib.ComponentCount(),
+                                  MaxwellToGL::VertexType(attrib), attrib.offset);
         } else {
-            glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
+            glVertexAttribFormat(gl_index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
                                  attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
         }
-        glVertexAttribBinding(index, attrib.buffer);
+        glVertexAttribBinding(gl_index, attrib.buffer);
     }
 }
 
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
index 3c6231d588..572a438566 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.cpp
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -71,6 +71,15 @@ void SetupDirtyColorMasks(Tables& tables) {
     FillBlock(tables[1], OFF(color_mask), NUM(color_mask), ColorMasks);
 }
 
+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]);
+        FillBlock(tables[0], offset, NUM(vertex_attrib_format[0]), VertexFormat0 + i);
+    }
+
+    FillBlock(tables[1], OFF(vertex_attrib_format), Regs::NumVertexAttributes, VertexFormats);
+}
+
 void SetupDirtyViewports(Tables& tables) {
     for (std::size_t i = 0; i < Regs::NumViewports; ++i) {
         const std::size_t transf_offset = OFF(viewport_transform) + i * NUM(viewport_transform[0]);
@@ -117,6 +126,7 @@ void StateTracker::Initialize() {
     SetupDirtyColorMasks(tables);
     SetupDirtyViewports(tables);
     SetupDirtyScissors(tables);
+    SetupDirtyVertexFormat(tables);
 }
 
 } // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h
index 0ad7c349a4..7add22d888 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.h
+++ b/src/video_core/renderer_opengl/gl_state_tracker.h
@@ -20,6 +20,8 @@ enum : u8 {
     First = VideoCommon::Dirty::LastCommonEntry,
 
     VertexFormats,
+    VertexFormat0,
+    VertexFormat31 = VertexFormat0 + 31,
 
     VertexBuffers,
     VertexBuffer0,
@@ -66,6 +68,16 @@ public:
 
     void Initialize();
 
+    void NotifyScreenDrawVertexArray() {
+        auto& flags = system.GPU().Maxwell3D().dirty.flags;
+        flags[OpenGL::Dirty::VertexFormats] = true;
+        flags[OpenGL::Dirty::VertexFormat0 + 0] = true;
+        flags[OpenGL::Dirty::VertexFormat0 + 1] = true;
+
+        flags[OpenGL::Dirty::VertexBuffers] = true;
+        flags[OpenGL::Dirty::VertexBuffer0] = true;
+    }
+
     void NotifyViewport0() {
         auto& flags = system.GPU().Maxwell3D().dirty.flags;
         flags[OpenGL::Dirty::Viewports] = true;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3ff7c8fb14..caa193c50b 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -576,6 +576,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
     glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
 
     // TODO: Signal state tracker about these changes
+    state_tracker.NotifyScreenDrawVertexArray();
     state_tracker.NotifyViewport0();
     state_tracker.NotifyScissor0();
     state_tracker.NotifyColorMask0();
@@ -608,6 +609,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
                        static_cast<GLfloat>(layout.height));
     glDepthRangeIndexed(0, 0.0, 0.0);
 
+    glEnableVertexAttribArray(PositionLocation);
+    glEnableVertexAttribArray(TexCoordLocation);
     glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
                          offsetof(ScreenRectVertex, position));
     glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,