From ec28f037e6cfe42c3285866572af075e1e72b3e9 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 30 Aug 2015 08:41:28 -0300
Subject: [PATCH] OpenGL: Add support for Sampler Objects to state tracker

---
 .../renderer_opengl/gl_resource_manager.h     | 24 +++++++++++++++++++
 src/video_core/renderer_opengl/gl_state.cpp   | 20 ++++++++++++----
 src/video_core/renderer_opengl/gl_state.h     |  2 ++
 3 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 68fc1e6d3..65034d40d 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -37,6 +37,30 @@ public:
     GLuint handle = 0;
 };
 
+class OGLSampler : private NonCopyable {
+public:
+    OGLSampler() = default;
+    OGLSampler(OGLSampler&& o) { std::swap(handle, o.handle); }
+    ~OGLSampler() { Release(); }
+    OGLSampler& operator=(OGLSampler&& o) { std::swap(handle, o.handle); return *this; }
+
+    /// Creates a new internal OpenGL resource and stores the handle
+    void Create() {
+        if (handle != 0) return;
+        glGenSamplers(1, &handle);
+    }
+
+    /// Deletes the internal OpenGL resource
+    void Release() {
+        if (handle == 0) return;
+        glDeleteSamplers(1, &handle);
+        OpenGLState::ResetSampler(handle);
+        handle = 0;
+    }
+
+    GLuint handle = 0;
+};
+
 class OGLShader : private NonCopyable {
 public:
     OGLShader() = default;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index ba47ce8b8..e02c27fbf 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -44,6 +44,7 @@ OpenGLState::OpenGLState() {
 
     for (auto& texture_unit : texture_units) {
         texture_unit.texture_2d = 0;
+        texture_unit.sampler = 0;
     }
 
     draw.framebuffer = 0;
@@ -154,10 +155,13 @@ void OpenGLState::Apply() {
     }
 
     // Textures
-    for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
-        if (texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
-            glActiveTexture(GL_TEXTURE0 + texture_index);
-            glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
+    for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
+        if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
+            glActiveTexture(GL_TEXTURE0 + i);
+            glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
+        }
+        if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
+            glBindSampler(i, texture_units[i].sampler);
         }
     }
 
@@ -192,6 +196,14 @@ void OpenGLState::ResetTexture(GLuint id) {
     }
 }
 
+void OpenGLState::ResetSampler(GLuint id) {
+    for (auto& unit : cur_state.texture_units) {
+        if (unit.sampler == id) {
+            unit.sampler = 0;
+        }
+    }
+}
+
 void OpenGLState::ResetProgram(GLuint id) {
     if (cur_state.draw.shader_program == id) {
         cur_state.draw.shader_program = 0;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 43aa29a81..6ecbedbb4 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -57,6 +57,7 @@ public:
     // 3 texture units - one for each that is used in PICA fragment shader emulation
     struct {
         GLuint texture_2d; // GL_TEXTURE_BINDING_2D
+        GLuint sampler; // GL_SAMPLER_BINDING
     } texture_units[3];
 
     struct {
@@ -77,6 +78,7 @@ public:
     void Apply();
 
     static void ResetTexture(GLuint id);
+    static void ResetSampler(GLuint id);
     static void ResetProgram(GLuint id);
     static void ResetBuffer(GLuint id);
     static void ResetVertexArray(GLuint id);