Added support for TEXTURE_COMPARE_MODE and TEXTURE_COMPARE_FUNC sampler states.

TRAC #23394
Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Author: Geoff Lang
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 09315ba..31b0079 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -36,8 +36,10 @@
     mSamplerState.wrapR = GL_REPEAT;
     mSamplerState.maxAnisotropy = 1.0f;
     mSamplerState.lodOffset = 0;
+    mSamplerState.compareMode = GL_NONE;
+    mSamplerState.compareFunc = GL_LEQUAL;
     mUsage = GL_NONE;
-    
+
     mDirtyImages = true;
 
     mImmutable = false;
@@ -138,6 +140,40 @@
     return true;
 }
 
+bool Texture::setCompareMode(GLenum mode)
+{
+    // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
+    switch (mode)
+    {
+      case GL_NONE:
+      case GL_COMPARE_REF_TO_TEXTURE:
+        mSamplerState.compareMode = mode;
+        return true;
+      default:
+        return false;
+    }
+}
+
+bool Texture::setCompareFunc(GLenum func)
+{
+    // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
+    switch (func)
+    {
+      case GL_LEQUAL:
+      case GL_GEQUAL:
+      case GL_LESS:
+      case GL_GREATER:
+      case GL_EQUAL:
+      case GL_NOTEQUAL:
+      case GL_ALWAYS:
+      case GL_NEVER:
+        mSamplerState.compareFunc = func;
+        return true;
+      default:
+        return false;
+    }
+}
+
 // Returns true on successful usage state update (valid enum parameter)
 bool Texture::setUsage(GLenum usage)
 {
@@ -672,6 +708,23 @@
         }
     }
 
+    // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
+    // The internalformat specified for the texture arrays is a sized internal depth or
+    // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
+    // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
+    // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
+    if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
+    {
+        if (mSamplerState.compareMode == GL_NONE)
+        {
+            if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
+                mSamplerState.magFilter != GL_NEAREST)
+            {
+                return false;
+            }
+        }
+    }
+
     return true;
 }
 
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index b3a43d8..28ce151 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -74,6 +74,8 @@
     bool setWrapT(GLenum wrap);
     bool setWrapR(GLenum wrap);
     bool setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy);
+    bool setCompareMode(GLenum mode);
+    bool setCompareFunc(GLenum func);
     bool setUsage(GLenum usage);
 
     GLenum getMinFilter() const;
diff --git a/src/libGLESv2/angletypes.h b/src/libGLESv2/angletypes.h
index c744d71..4bbad24 100644
--- a/src/libGLESv2/angletypes.h
+++ b/src/libGLESv2/angletypes.h
@@ -143,6 +143,9 @@
     GLenum wrapR;
     float maxAnisotropy;
     int lodOffset;
+
+    GLenum compareMode;
+    GLenum compareFunc;
 };
 
 struct ClearParameters
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index b12cb1e..16e5c93 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -7057,6 +7057,28 @@
                 UNIMPLEMENTED();
                 break;
 
+              case GL_TEXTURE_COMPARE_MODE:
+                if (context->getClientVersion() < 3)
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                if (!texture->setCompareMode((GLenum)param))
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                break;
+
+              case GL_TEXTURE_COMPARE_FUNC:
+                if (context->getClientVersion() < 3)
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                if (!texture->setCompareFunc((GLenum)param))
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                break;
+
               default:
                 return gl::error(GL_INVALID_ENUM);
             }
@@ -7166,8 +7188,6 @@
               case GL_TEXTURE_SWIZZLE_A:
               case GL_TEXTURE_BASE_LEVEL:
               case GL_TEXTURE_MAX_LEVEL:
-              case GL_TEXTURE_COMPARE_MODE:
-              case GL_TEXTURE_COMPARE_FUNC:
                 if (context->getClientVersion() < 3)
                 {
                     return gl::error(GL_INVALID_ENUM);
@@ -7175,6 +7195,28 @@
                 UNIMPLEMENTED();
                 break;
 
+              case GL_TEXTURE_COMPARE_MODE:
+                if (context->getClientVersion() < 3)
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                if (!texture->setCompareMode((GLenum)param))
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                break;
+
+              case GL_TEXTURE_COMPARE_FUNC:
+                if (context->getClientVersion() < 3)
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                if (!texture->setCompareFunc((GLenum)param))
+                {
+                    return gl::error(GL_INVALID_ENUM);
+                }
+                break;
+
               default:
                 return gl::error(GL_INVALID_ENUM);
             }
diff --git a/src/libGLESv2/renderer/RenderStateCache.cpp b/src/libGLESv2/renderer/RenderStateCache.cpp
index 970f379..e84769b 100644
--- a/src/libGLESv2/renderer/RenderStateCache.cpp
+++ b/src/libGLESv2/renderer/RenderStateCache.cpp
@@ -375,13 +375,14 @@
         }
 
         D3D11_SAMPLER_DESC samplerDesc;
-        samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy);
+        samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter,
+                                                     samplerState.maxAnisotropy, samplerState.compareMode);
         samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS);
         samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
         samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR);
         samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset);
         samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy;
-        samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+        samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc);
         samplerDesc.BorderColor[0] = 0.0f;
         samplerDesc.BorderColor[1] = 0.0f;
         samplerDesc.BorderColor[2] = 0.0f;
diff --git a/src/libGLESv2/renderer/renderer11_utils.cpp b/src/libGLESv2/renderer/renderer11_utils.cpp
index 4861f82..68792ee 100644
--- a/src/libGLESv2/renderer/renderer11_utils.cpp
+++ b/src/libGLESv2/renderer/renderer11_utils.cpp
@@ -155,11 +155,13 @@
     return d3dStencilOp;
 }
 
-D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy)
+D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode)
 {
+    bool comparison = comparisonMode != GL_NONE;
+
     if (maxAnisotropy > 1.0f)
     {
-        return D3D11_ENCODE_ANISOTROPIC_FILTER(false);
+        return D3D11_ENCODE_ANISOTROPIC_FILTER(comparison);
     }
     else
     {
@@ -184,7 +186,7 @@
           default:         UNREACHABLE();
         }
 
-        return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, false);
+        return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, comparison);
     }
 }
 
diff --git a/src/libGLESv2/renderer/renderer11_utils.h b/src/libGLESv2/renderer/renderer11_utils.h
index cb35b74..ecdad94 100644
--- a/src/libGLESv2/renderer/renderer11_utils.h
+++ b/src/libGLESv2/renderer/renderer11_utils.h
@@ -29,7 +29,7 @@
 UINT8 ConvertStencilMask(GLuint stencilmask);
 D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp);
 
-D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
+D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode);
 D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap);
 FLOAT ConvertMinLOD(GLenum minFilter, unsigned int lodOffset);
 FLOAT ConvertMaxLOD(GLenum minFilter, unsigned int lodOffset);