From b8f1506aa5e5eb25bfd82f4e0818f1c2c1e6bcb3 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Wed, 26 Sep 2018 21:52:31 -0300
Subject: [PATCH] gl_state: Pack sampler bindings into a single ARB_multi_bind

---
 src/video_core/engines/maxwell_3d.h           |  1 +
 .../renderer_opengl/gl_rasterizer.h           |  2 +-
 .../renderer_opengl/gl_shader_manager.h       |  3 ---
 src/video_core/renderer_opengl/gl_state.cpp   | 24 ++++++++++++++++---
 src/video_core/renderer_opengl/gl_state.h     |  3 ++-
 5 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 16cdfc7e21..cd26c7216c 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -41,6 +41,7 @@ public:
         static constexpr std::size_t NumCBData = 16;
         static constexpr std::size_t NumVertexArrays = 32;
         static constexpr std::size_t NumVertexAttributes = 32;
+        static constexpr std::size_t NumTextureSamplers = 32;
         static constexpr std::size_t MaxShaderProgram = 6;
         static constexpr std::size_t MaxShaderStage = 5;
         // Maximum number of const buffers per shader stage.
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index c3f1e14bfa..b64c93b81f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -184,7 +184,7 @@ private:
              OGLVertexArray>
         vertex_array_cache;
 
-    std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
+    std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
 
     static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
     OGLBufferCache buffer_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b86cd96e8f..3de15ba9bb 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -11,9 +11,6 @@
 
 namespace OpenGL::GLShader {
 
-/// Number of OpenGL texture samplers that can be used in the fragment shader
-static constexpr std::size_t NumTextureSamplers = 32;
-
 using Tegra::Engines::Maxwell3D;
 
 /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index e5173e20aa..e494b3f161 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -205,9 +205,6 @@ void OpenGLState::Apply() const {
             glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
             glBindTexture(texture_unit.target, texture_unit.texture);
         }
-        if (texture_unit.sampler != cur_state_texture_unit.sampler) {
-            glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
-        }
         // Update the texture swizzle
         if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
             texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
@@ -219,6 +216,27 @@ void OpenGLState::Apply() const {
         }
     }
 
+    // Samplers
+    {
+        bool has_delta{};
+        std::size_t first{}, last{};
+        std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
+        for (std::size_t i = 0; i < std::size(samplers); ++i) {
+            samplers[i] = texture_units[i].sampler;
+            if (samplers[i] != cur_state.texture_units[i].sampler) {
+                if (!has_delta) {
+                    first = i;
+                    has_delta = true;
+                }
+                last = i;
+            }
+        }
+        if (has_delta) {
+            glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
+                           samplers.data());
+        }
+    }
+
     // Framebuffer
     if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
         glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9a93029d89..49f30b1112 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -6,6 +6,7 @@
 
 #include <array>
 #include <glad/glad.h>
+#include "video_core/engines/maxwell_3d.h"
 
 namespace OpenGL {
 
@@ -114,7 +115,7 @@ public:
             target = GL_TEXTURE_2D;
         }
     };
-    std::array<TextureUnit, 32> texture_units;
+    std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
 
     struct {
         GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING