From dfdbfa69e5290239b839a3c1600e171c15e86290 Mon Sep 17 00:00:00 2001
From: Rodolfo Bogado <rodolfoosvaldobogado@gmail.com>
Date: Fri, 23 Nov 2018 12:11:21 -0300
Subject: [PATCH] Implement depth clamp

---
 src/video_core/engines/maxwell_3d.h           | 10 +++++-
 .../renderer_opengl/gl_rasterizer.cpp         | 16 ++++++++++
 .../renderer_opengl/gl_rasterizer.h           |  4 +++
 src/video_core/renderer_opengl/gl_state.cpp   | 32 +++++++++++++------
 src/video_core/renderer_opengl/gl_state.h     |  6 ++++
 5 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 9324d9710..20e2ea8d7 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -902,8 +902,15 @@ public:
 
                 u32 viewport_transform_enabled;
 
-                INSERT_PADDING_WORDS(0x25);
+                INSERT_PADDING_WORDS(0x3);
 
+                union {
+                    BitField<0, 1, u32> depth_range_0_1;
+                    BitField<3, 1, u32> depth_clamp_near;
+                    BitField<4, 1, u32> depth_clamp_far;
+                } view_volume_clip_control;
+
+                INSERT_PADDING_WORDS(0x21);
                 struct {
                     u32 enable;
                     LogicOperation operation;
@@ -1224,6 +1231,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
 ASSERT_REG_POSITION(cull, 0x646);
 ASSERT_REG_POSITION(pixel_center_integer, 0x649);
 ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
+ASSERT_REG_POSITION(view_volume_clip_control, 0x64F);
 ASSERT_REG_POSITION(logic_op, 0x671);
 ASSERT_REG_POSITION(clear_buffers, 0x674);
 ASSERT_REG_POSITION(color_mask, 0x680);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 98fb5a9aa..92d8203b3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -113,10 +113,24 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
 
     LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
+    CheckExtensions();
 }
 
 RasterizerOpenGL::~RasterizerOpenGL() {}
 
+void RasterizerOpenGL::CheckExtensions() {
+    if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) {
+        LOG_WARNING(
+            Render_OpenGL,
+            "Anisotropic filter is not supported! This can cause graphical issues in some games.");
+    }
+    if (!GLAD_GL_ARB_buffer_storage) {
+        LOG_WARNING(
+            Render_OpenGL,
+            "Buffer storage control is not supported! This can cause performance degradation.");
+    }
+}
+
 void RasterizerOpenGL::SetupVertexFormat() {
     auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
     const auto& regs = gpu.regs;
@@ -1007,6 +1021,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
         viewport.depth_range_far = regs.viewports[i].depth_range_far;
         viewport.depth_range_near = regs.viewports[i].depth_range_near;
     }
+    state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
+    state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
 }
 
 void RasterizerOpenGL::SyncClipEnabled() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index dfb4616f2..7ec9746b1 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -189,6 +189,10 @@ private:
     /// Check asserts for alpha testing.
     void CheckAlphaTests();
 
+    /// Check for extension that are not strictly required
+    /// but are needed for correct emulation
+    void CheckExtensions();
+
     bool has_ARB_direct_state_access = false;
     bool has_ARB_multi_bind = false;
 
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b3bfad6a0..dc0a5ed5e 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -92,7 +92,8 @@ OpenGLState::OpenGLState() {
 
     point.size = 1;
     fragment_color_clamp.enabled = false;
-
+    depth_clamp.far_plane = false;
+    depth_clamp.near_plane = false;
     polygon_offset.fill_enable = false;
     polygon_offset.line_enable = false;
     polygon_offset.point_enable = false;
@@ -147,7 +148,7 @@ void OpenGLState::ApplyCulling() const {
 }
 
 void OpenGLState::ApplyColorMask() const {
-    if (GLAD_GL_ARB_viewport_array && independant_blend.enabled) {
+    if (independant_blend.enabled) {
         for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
             const auto& updated = color_mask[i];
             const auto& current = cur_state.color_mask[i];
@@ -264,7 +265,7 @@ void OpenGLState::EmulateViewportWithScissor() {
 }
 
 void OpenGLState::ApplyViewport() const {
-    if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
+    if (geometry_shaders.enabled) {
         for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports);
              i++) {
             const auto& current = cur_state.viewports[i];
@@ -525,6 +526,21 @@ void OpenGLState::ApplyVertexBufferState() const {
     }
 }
 
+void OpenGLState::ApplyDepthClamp() const {
+    if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
+        depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
+        return;
+    }
+    if (depth_clamp.far_plane != depth_clamp.near_plane) {
+        UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!");
+    }
+    if (depth_clamp.far_plane || depth_clamp.near_plane) {
+        glEnable(GL_DEPTH_CLAMP);
+    } else {
+        glDisable(GL_DEPTH_CLAMP);
+    }
+}
+
 void OpenGLState::Apply() const {
     ApplyFramebufferState();
     ApplyVertexBufferState();
@@ -556,11 +572,9 @@ void OpenGLState::Apply() const {
     if (point.size != cur_state.point.size) {
         glPointSize(point.size);
     }
-    if (GLAD_GL_ARB_color_buffer_float) {
-        if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) {
-            glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
-                         fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
-        }
+    if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) {
+        glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
+                     fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
     }
     if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) {
         if (multisample_control.alpha_to_coverage) {
@@ -576,7 +590,7 @@ void OpenGLState::Apply() const {
             glDisable(GL_SAMPLE_ALPHA_TO_ONE);
         }
     }
-
+    ApplyDepthClamp();
     ApplyColorMask();
     ApplyViewport();
     ApplyStencilTest();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 0bf19ed07..a486d1654 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -48,6 +48,11 @@ public:
         bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
     } fragment_color_clamp;
 
+    struct {
+        bool far_plane;
+        bool near_plane;
+    } depth_clamp; // GL_DEPTH_CLAMP
+
     struct {
         bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
     } geometry_shaders;
@@ -235,6 +240,7 @@ private:
     void ApplyLogicOp() const;
     void ApplyTextures() const;
     void ApplySamplers() const;
+    void ApplyDepthClamp() const;
     void ApplyPolygonOffset() const;
 };