From 752faff2bcfa536a9efc81416156b1d42d05a2cc Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Wed, 19 Sep 2018 01:18:20 -0400
Subject: [PATCH] Implemented Depth Compare and Shadow Samplers

---
 .../renderer_opengl/gl_rasterizer.cpp         |  18 ++
 .../renderer_opengl/gl_rasterizer.h           |   2 +
 .../renderer_opengl/gl_shader_decompiler.cpp  | 217 +++++++++++++-----
 .../renderer_opengl/gl_shader_gen.h           |  14 +-
 .../renderer_opengl/maxwell_to_gl.h           |  25 ++
 src/video_core/textures/texture.h             |  13 +-
 6 files changed, 224 insertions(+), 65 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 587d9dffb1..cc07b47213 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -601,10 +601,13 @@ void RasterizerOpenGL::SamplerInfo::Create() {
     sampler.Create();
     mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
     wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap;
+    uses_depth_compare = false;
+    depth_compare_func = Tegra::Texture::DepthCompareFunc::Never;
 
     // default is GL_LINEAR_MIPMAP_LINEAR
     glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     // Other attributes have correct defaults
+    glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
 }
 
 void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
@@ -632,6 +635,21 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
         glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p));
     }
 
+    if (uses_depth_compare != (config.depth_compare_enabled == 1)) {
+        uses_depth_compare = (config.depth_compare_enabled == 1);
+        if (uses_depth_compare) {
+            glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+        } else {
+            glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+        }
+    }
+
+    if (depth_compare_func != config.depth_compare_func) {
+        depth_compare_func = config.depth_compare_func;
+        glSamplerParameteri(s, GL_TEXTURE_COMPARE_FUNC,
+                            MaxwellToGL::DepthCompareFunc(depth_compare_func));
+    }
+
     if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border ||
         wrap_p == Tegra::Texture::WrapMode::Border) {
         const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 4c8ecbd1c1..987c4f4fb2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -94,6 +94,8 @@ private:
         Tegra::Texture::WrapMode wrap_u;
         Tegra::Texture::WrapMode wrap_v;
         Tegra::Texture::WrapMode wrap_p;
+        bool uses_depth_compare;
+        Tegra::Texture::DepthCompareFunc depth_compare_func;
         GLvec4 border_color;
     };
 
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index d73234ec3c..7e57de78aa 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -508,7 +508,7 @@ public:
     /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
     /// necessary.
     std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
-                              bool is_array) {
+                              bool is_array, bool is_shadow) {
         const std::size_t offset = static_cast<std::size_t>(sampler.index.Value());
 
         // If this sampler has already been used, return the existing mapping.
@@ -517,13 +517,14 @@ public:
                          [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
 
         if (itr != used_samplers.end()) {
-            ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
+            ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
+                   itr->IsShadow() == is_shadow);
             return itr->GetName();
         }
 
         // Otherwise create a new mapping for this sampler
         const std::size_t next_index = used_samplers.size();
-        const SamplerEntry entry{stage, offset, next_index, type, is_array};
+        const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow};
         used_samplers.emplace_back(entry);
         return entry.GetName();
     }
@@ -747,8 +748,9 @@ private:
     }
 
     /// Generates code representing a texture sampler.
-    std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
-        return regs.AccessSampler(sampler, type, is_array);
+    std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array,
+                           bool is_shadow) {
+        return regs.AccessSampler(sampler, type, is_array, is_shadow);
     }
 
     /**
@@ -1002,6 +1004,24 @@ private:
         shader.AddLine('}');
     }
 
+    static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
+        switch (texture_type) {
+        case Tegra::Shader::TextureType::Texture1D: {
+            return 1;
+        }
+        case Tegra::Shader::TextureType::Texture2D: {
+            return 2;
+        }
+        case Tegra::Shader::TextureType::TextureCube: {
+            return 3;
+        }
+        default:
+            LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", static_cast<u32>(texture_type));
+            UNREACHABLE();
+            return 0;
+        }
+    }
+
     /*
      * Emits code to push the input target address to the SSY address stack, incrementing the stack
      * top.
@@ -1896,24 +1916,35 @@ private:
                            "NODEP is not implemented");
                 ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
                            "AOFFI is not implemented");
-                ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
-                           "DC is not implemented");
 
-                switch (texture_type) {
-                case Tegra::Shader::TextureType::Texture1D: {
+                const bool depth_compare =
+                    instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+                u32 num_coordinates = TextureCoordinates(texture_type);
+                if (depth_compare)
+                    num_coordinates += 1;
+
+                switch (num_coordinates) {
+                case 1: {
                     const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
                     coord = "float coords = " + x + ';';
                     break;
                 }
-                case Tegra::Shader::TextureType::Texture2D: {
+                case 2: {
                     const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
                     const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
                     coord = "vec2 coords = vec2(" + x + ", " + y + ");";
                     break;
                 }
+                case 3: {
+                    const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
+                    const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
+                    const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
+                    coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
+                    break;
+                }
                 default:
-                    LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
-                                 static_cast<u32>(texture_type));
+                    LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}",
+                                 static_cast<u32>(num_coordinates));
                     UNREACHABLE();
 
                     // Fallback to interpreting as a 2D texture for now
@@ -1924,9 +1955,10 @@ private:
                 }
                 // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
                 // or lod.
-                const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20);
+                std::string op_c;
 
-                const std::string sampler = GetSampler(instr.sampler, texture_type, false);
+                const std::string sampler =
+                    GetSampler(instr.sampler, texture_type, false, depth_compare);
                 // Add an extra scope and declare the texture coords inside to prevent
                 // overwriting them in case they are used as outputs of the texs instruction.
 
@@ -1946,12 +1978,22 @@ private:
                 }
                 case Tegra::Shader::TextureProcessMode::LB:
                 case Tegra::Shader::TextureProcessMode::LBA: {
+                    if (num_coordinates <= 2) {
+                        op_c = regs.GetRegisterAsFloat(instr.gpr20);
+                    } else {
+                        op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
+                    }
                     // TODO: Figure if A suffix changes the equation at all.
                     texture = "texture(" + sampler + ", coords, " + op_c + ')';
                     break;
                 }
                 case Tegra::Shader::TextureProcessMode::LL:
                 case Tegra::Shader::TextureProcessMode::LLA: {
+                    if (num_coordinates <= 2) {
+                        op_c = regs.GetRegisterAsFloat(instr.gpr20);
+                    } else {
+                        op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
+                    }
                     // TODO: Figure if A suffix changes the equation at all.
                     texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
                     break;
@@ -1963,14 +2005,18 @@ private:
                     UNREACHABLE();
                 }
                 }
-                std::size_t dest_elem{};
-                for (std::size_t elem = 0; elem < 4; ++elem) {
-                    if (!instr.tex.IsComponentEnabled(elem)) {
-                        // Skip disabled components
-                        continue;
+                if (!depth_compare) {
+                    std::size_t dest_elem{};
+                    for (std::size_t elem = 0; elem < 4; ++elem) {
+                        if (!instr.tex.IsComponentEnabled(elem)) {
+                            // Skip disabled components
+                            continue;
+                        }
+                        regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
+                        ++dest_elem;
                     }
-                    regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
-                    ++dest_elem;
+                } else {
+                    regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
                 }
                 --shader.scope;
                 shader.AddLine("}");
@@ -1983,11 +2029,15 @@ private:
 
                 ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
                            "NODEP is not implemented");
-                ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
-                           "DC is not implemented");
 
-                switch (texture_type) {
-                case Tegra::Shader::TextureType::Texture2D: {
+                const bool depth_compare =
+                    instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+                u32 num_coordinates = TextureCoordinates(texture_type);
+                if (depth_compare)
+                    num_coordinates += 1;
+
+                switch (num_coordinates) {
+                case 2: {
                     if (is_array) {
                         const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
                         const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
@@ -2000,17 +2050,25 @@ private:
                     }
                     break;
                 }
-                case Tegra::Shader::TextureType::TextureCube: {
-                    ASSERT_MSG(!is_array, "Unimplemented");
-                    std::string x = regs.GetRegisterAsFloat(instr.gpr8);
-                    std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
-                    std::string z = regs.GetRegisterAsFloat(instr.gpr20);
-                    coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
+                case 3: {
+                    if (is_array) {
+                        UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented");
+                        const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
+                        const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
+                        coord = "vec2 coords = vec2(" + x + ", " + y + ");";
+                        texture_type = Tegra::Shader::TextureType::Texture2D;
+                        is_array = false;
+                    } else {
+                        const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
+                        const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
+                        const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
+                        coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
+                    }
                     break;
                 }
                 default:
-                    LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
-                                 static_cast<u32>(texture_type));
+                    LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}",
+                                 static_cast<u32>(num_coordinates));
                     UNREACHABLE();
 
                     // Fallback to interpreting as a 2D texture for now
@@ -2020,9 +2078,9 @@ private:
                     texture_type = Tegra::Shader::TextureType::Texture2D;
                     is_array = false;
                 }
-                const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
+                const std::string sampler =
+                    GetSampler(instr.sampler, texture_type, is_array, depth_compare);
                 std::string texture;
-                const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
                 switch (instr.texs.GetTextureProcessMode()) {
                 case Tegra::Shader::TextureProcessMode::None: {
                     texture = "texture(" + sampler + ", coords)";
@@ -2033,6 +2091,7 @@ private:
                     break;
                 }
                 case Tegra::Shader::TextureProcessMode::LL: {
+                    const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
                     texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
                     break;
                 }
@@ -2043,7 +2102,11 @@ private:
                     UNREACHABLE();
                 }
                 }
-                WriteTexsInstruction(instr, coord, texture);
+                if (!depth_compare) {
+                    WriteTexsInstruction(instr, coord, texture);
+                } else {
+                    WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
+                }
                 break;
             }
             case OpCode::Id::TLDS: {
@@ -2083,7 +2146,8 @@ private:
                                  static_cast<u32>(texture_type));
                     UNREACHABLE();
                 }
-                const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
+                const std::string sampler =
+                    GetSampler(instr.sampler, texture_type, is_array, false);
                 std::string texture = "texelFetch(" + sampler + ", coords, 0)";
                 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr20.Value() + 1);
                 switch (instr.tlds.GetTextureProcessMode()) {
@@ -2114,28 +2178,43 @@ private:
                            "NODEP is not implemented");
                 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
                            "AOFFI is not implemented");
-                ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
-                           "DC is not implemented");
                 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
                            "NDV is not implemented");
                 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP),
                            "PTP is not implemented");
-
-                switch (instr.tld4.texture_type) {
-                case Tegra::Shader::TextureType::Texture2D: {
+                const bool depth_compare =
+                    instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+                auto texture_type = instr.tld4.texture_type.Value();
+                u32 num_coordinates = TextureCoordinates(texture_type);
+                if (depth_compare)
+                    num_coordinates += 1;
+
+                switch (num_coordinates) {
+                case 2: {
                     const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
                     const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
                     coord = "vec2 coords = vec2(" + x + ", " + y + ");";
                     break;
                 }
+                case 3: {
+                    const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
+                    const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
+                    const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
+                    coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
+                    break;
+                }
                 default:
-                    LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
-                                 static_cast<u32>(instr.tld4.texture_type.Value()));
+                    LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}",
+                                 static_cast<u32>(num_coordinates));
                     UNREACHABLE();
+                    const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
+                    const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
+                    coord = "vec2 coords = vec2(" + x + ", " + y + ");";
+                    texture_type = Tegra::Shader::TextureType::Texture2D;
                 }
 
                 const std::string sampler =
-                    GetSampler(instr.sampler, instr.tld4.texture_type, false);
+                    GetSampler(instr.sampler, texture_type, false, depth_compare);
                 // Add an extra scope and declare the texture coords inside to prevent
                 // overwriting them in case they are used as outputs of the texs instruction.
                 shader.AddLine("{");
@@ -2143,15 +2222,18 @@ private:
                 shader.AddLine(coord);
                 const std::string texture = "textureGather(" + sampler + ", coords, " +
                                             std::to_string(instr.tld4.component) + ')';
-
-                std::size_t dest_elem{};
-                for (std::size_t elem = 0; elem < 4; ++elem) {
-                    if (!instr.tex.IsComponentEnabled(elem)) {
-                        // Skip disabled components
-                        continue;
+                if (!depth_compare) {
+                    std::size_t dest_elem{};
+                    for (std::size_t elem = 0; elem < 4; ++elem) {
+                        if (!instr.tex.IsComponentEnabled(elem)) {
+                            // Skip disabled components
+                            continue;
+                        }
+                        regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
+                        ++dest_elem;
                     }
-                    regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
-                    ++dest_elem;
+                } else {
+                    regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
                 }
                 --shader.scope;
                 shader.AddLine("}");
@@ -2162,18 +2244,30 @@ private:
                            "NODEP is not implemented");
                 ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
                            "AOFFI is not implemented");
-                ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
-                           "DC is not implemented");
 
+                const bool depth_compare =
+                    instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
                 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
                 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
                 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
-                const std::string sampler =
-                    GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
-                const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
+                const std::string sampler = GetSampler(
+                    instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
+                std::string coord;
+                if (!depth_compare) {
+                    coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
+                } else {
+                    // Note: TLD4S coordinate encoding works just like TEXS's
+                    const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
+                    coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");";
+                }
                 const std::string texture = "textureGather(" + sampler + ", coords, " +
                                             std::to_string(instr.tld4s.component) + ')';
-                WriteTexsInstruction(instr, coord, texture);
+
+                if (!depth_compare) {
+                    WriteTexsInstruction(instr, coord, texture);
+                } else {
+                    WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
+                }
                 break;
             }
             case OpCode::Id::TXQ: {
@@ -2184,7 +2278,7 @@ private:
                 // Sadly, not all texture instructions specify the type of texture their sampler
                 // uses. This must be fixed at a later instance.
                 const std::string sampler =
-                    GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
+                    GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false);
                 switch (instr.txq.query_type) {
                 case Tegra::Shader::TextureQueryType::Dimension: {
                     const std::string texture = "textureQueryLevels(" + sampler + ')';
@@ -2209,7 +2303,8 @@ private:
                 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
                 const bool is_array = instr.tmml.array != 0;
                 auto texture_type = instr.tmml.texture_type.Value();
-                const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
+                const std::string sampler =
+                    GetSampler(instr.sampler, texture_type, is_array, false);
 
                 // TODO: add coordinates for different samplers once other texture types are
                 // implemented.
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index d53b93ad58..e56f39e788 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -75,8 +75,9 @@ class SamplerEntry {
 
 public:
     SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index,
-                 Tegra::Shader::TextureType type, bool is_array)
-        : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
+                 Tegra::Shader::TextureType type, bool is_array, bool is_shadow)
+        : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array),
+          is_shadow(is_shadow) {}
 
     std::size_t GetOffset() const {
         return offset;
@@ -117,6 +118,8 @@ public:
         }
         if (is_array)
             glsl_type += "Array";
+        if (is_shadow)
+            glsl_type += "Shadow";
         return glsl_type;
     }
 
@@ -128,6 +131,10 @@ public:
         return is_array;
     }
 
+    bool IsShadow() const {
+        return is_shadow;
+    }
+
     u32 GetHash() const {
         return (static_cast<u32>(stage) << 16) | static_cast<u32>(sampler_index);
     }
@@ -147,7 +154,8 @@ private:
     Maxwell::ShaderStage stage;      ///< Shader stage where this sampler was used.
     std::size_t sampler_index;       ///< Value used to index into the generated GLSL sampler array.
     Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
-    bool is_array; ///< Whether the texture is being sampled as an array texture or not.
+    bool is_array;  ///< Whether the texture is being sampled as an array texture or not.
+    bool is_shadow; ///< Whether the texture is being sampled as a depth texture or not.
 };
 
 struct ShaderEntries {
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 67273e1648..3c3bcaae4e 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -159,6 +159,31 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
     return {};
 }
 
+inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
+    switch (func) {
+    case Tegra::Texture::DepthCompareFunc::Never:
+        return GL_NEVER;
+    case Tegra::Texture::DepthCompareFunc::Less:
+        return GL_LESS;
+    case Tegra::Texture::DepthCompareFunc::LessEqual:
+        return GL_LEQUAL;
+    case Tegra::Texture::DepthCompareFunc::Equal:
+        return GL_EQUAL;
+    case Tegra::Texture::DepthCompareFunc::NotEqual:
+        return GL_NOTEQUAL;
+    case Tegra::Texture::DepthCompareFunc::Greater:
+        return GL_GREATER;
+    case Tegra::Texture::DepthCompareFunc::GreaterEqual:
+        return GL_GEQUAL;
+    case Tegra::Texture::DepthCompareFunc::Always:
+        return GL_ALWAYS;
+    }
+    LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}",
+                 static_cast<u32>(func));
+    UNREACHABLE();
+    return {};
+}
+
 inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
     switch (equation) {
     case Maxwell::Blend::Equation::Add:
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index 14aea48383..8f31d825a3 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -227,6 +227,17 @@ enum class WrapMode : u32 {
     MirrorOnceClampOGL = 7,
 };
 
+enum class DepthCompareFunc : u32 {
+    Never = 0,
+    Less = 1,
+    Equal = 2,
+    LessEqual = 3,
+    Greater = 4,
+    NotEqual = 5,
+    GreaterEqual = 6,
+    Always = 7,
+};
+
 enum class TextureFilter : u32 {
     Nearest = 1,
     Linear = 2,
@@ -244,7 +255,7 @@ struct TSCEntry {
         BitField<3, 3, WrapMode> wrap_v;
         BitField<6, 3, WrapMode> wrap_p;
         BitField<9, 1, u32> depth_compare_enabled;
-        BitField<10, 3, u32> depth_compare_func;
+        BitField<10, 3, DepthCompareFunc> depth_compare_func;
     };
     union {
         BitField<0, 2, TextureFilter> mag_filter;
-- 
GitLab