Implement Anisotropic Texture filtering support

Bug=297
Authored-by: Conor Dickinson, Cloud Party, Inc.
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/trunk@1219 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/AUTHORS b/AUTHORS
index 5bde284..d7ecb4a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,3 +13,5 @@
 
 3DLabs Inc. Ltd.
 
+Cloud Party, Inc.
+
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index da15506..212784d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -44,6 +44,9 @@
  Alexandru Chiculita

  Max Vujovic

 

+Cloud Party, Inc.

+ Conor Dickinson

+

 Aitor Moreno <aitormoreno at gmail.com>

 Jim Hauxwell <james at dattrax.co.uk>

 ddefrostt

diff --git a/src/common/version.h b/src/common/version.h
index a1028be..f1a98a9 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,7 +1,7 @@
 #define MAJOR_VERSION 1
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 1217
+#define BUILD_REVISION 1219
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/libEGL/Display.cpp b/src/libEGL/Display.cpp
index e1e4e16..3ef90a2 100644
--- a/src/libEGL/Display.cpp
+++ b/src/libEGL/Display.cpp
@@ -1089,6 +1089,16 @@
     return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
 }
 
+float Display::getTextureFilterAnisotropySupport() const
+{
+    // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
+    if ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2))
+    {
+        return mDeviceCaps.MaxAnisotropy;
+    }
+    return 1.0f;
+}
+
 D3DPOOL Display::getBufferPool(DWORD usage) const
 {
     if (mD3d9Ex != NULL)
diff --git a/src/libEGL/Display.h b/src/libEGL/Display.h
index 4f7dbd0..3bd71d6 100644
--- a/src/libEGL/Display.h
+++ b/src/libEGL/Display.h
@@ -81,6 +81,7 @@
     virtual bool getDepthTextureSupport() const;
     virtual bool getOcclusionQuerySupport() const;
     virtual bool getInstancingSupport() const;
+    virtual float getTextureFilterAnisotropySupport() const;
     virtual D3DPOOL getBufferPool(DWORD usage) const;
     virtual D3DPOOL getTexturePool(DWORD usage) const;
 
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 7946011..1c2179e 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -274,8 +274,9 @@
         mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
         mMaxRenderbufferDimension = mMaxTextureDimension;
         mMaxTextureLevel = log2(mMaxTextureDimension) + 1;
-        TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d",
-              mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel);
+        mMaxTextureAnisotropy = mDisplay->getTextureFilterAnisotropySupport();
+        TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f",
+              mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy);
 
         const D3DFORMAT renderBufferFormats[] =
         {
@@ -313,6 +314,7 @@
         mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport();
         mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport();
         mSupportsDepthTextures = mDisplay->getDepthTextureSupport();
+        mSupportsTextureFilterAnisotropy = mMaxTextureAnisotropy >= 2.0f;
 
         mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
 
@@ -1425,6 +1427,13 @@
         params[2] = mState.blendColor.blue;
         params[3] = mState.blendColor.alpha;
         break;
+      case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+        if (!supportsTextureFilterAnisotropy())
+        {
+            return false;
+        }
+        *params = mMaxTextureAnisotropy;
+        break;
       default:
         return false;
     }
@@ -1833,6 +1842,14 @@
             *numParams = 4;
         }
         break;
+      case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+        if (!supportsTextureFilterAnisotropy())
+        {
+            return false;
+        }
+        *type = GL_FLOAT;
+        *numParams = 1;
+        break;
       default:
         return false;
     }
@@ -2383,15 +2400,21 @@
                         GLenum wrapT = texture->getWrapT();
                         GLenum minFilter = texture->getMinFilter();
                         GLenum magFilter = texture->getMagFilter();
+                        float maxAnisotropy = texture->getMaxAnisotropy();
 
                         mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
                         mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
 
-                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter, maxAnisotropy));
                         D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
-                        es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
+                        es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter, maxAnisotropy);
                         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
                         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+
+                        if (supportsTextureFilterAnisotropy())
+                        {
+                            mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)maxAnisotropy);
+                        }
                     }
 
                     if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyImages())
@@ -3522,6 +3545,16 @@
     return mSupportsInstancing;
 }
 
+bool Context::supportsTextureFilterAnisotropy() const
+{
+    return mSupportsTextureFilterAnisotropy;
+}
+
+float Context::getTextureMaxAnisotropy() const
+{
+    return mMaxTextureAnisotropy;
+}
+
 void Context::detachBuffer(GLuint buffer)
 {
     // [OpenGL ES 2.0.24] section 2.9 page 22:
@@ -3772,6 +3805,11 @@
         mExtensionString += "GL_EXT_texture_compression_dxt1 ";
     }
 
+    if (supportsTextureFilterAnisotropy())
+    {
+        mExtensionString += "GL_EXT_texture_filter_anisotropic ";
+    }
+
     mExtensionString += "GL_EXT_texture_format_BGRA8888 ";
     mExtensionString += "GL_EXT_texture_storage ";
 
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index 2f21a2d..2097fe4 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -500,6 +500,9 @@
     bool supports32bitIndices() const;
     bool supportsNonPower2Texture() const;
     bool supportsInstancing() const;
+    bool supportsTextureFilterAnisotropy() const;
+
+    float getTextureMaxAnisotropy() const;
 
     void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 
                          GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
@@ -605,6 +608,7 @@
     int  mMaxTextureDimension;
     int  mMaxCubeTextureDimension;
     int  mMaxTextureLevel;
+    float mMaxTextureAnisotropy;
     std::map<D3DFORMAT, bool *> mMultiSampleSupport;
     GLsizei mMaxSupportedSamples;
     bool mSupportsEventQueries;
@@ -622,6 +626,7 @@
     bool mSupportsLuminanceAlphaTextures;
     bool mSupportsDepthTextures;
     bool mSupports32bitIndices;
+    bool mSupportsTextureFilterAnisotropy;
     int mNumCompressedTextureFormats;
 
     // state caching flags
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 6ff2453..cd4d637 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -1157,6 +1157,7 @@
     mWrapT = GL_REPEAT;
     mDirtyParameters = true;
     mUsage = GL_NONE;
+    mMaxAnisotropy = 1.0f;
     
     mDirtyImages = true;
 
@@ -1253,6 +1254,22 @@
     }
 }
 
+// Returns true on successful max anisotropy update (valid anisotropy value)
+bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
+{
+    textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
+    if (textureMaxAnisotropy < 1.0f)
+    {
+        return false;
+    }
+    if (mMaxAnisotropy != textureMaxAnisotropy)
+    {
+        mMaxAnisotropy = textureMaxAnisotropy;
+        mDirtyParameters = true;
+    }
+    return true;
+}
+
 // Returns true on successful usage state update (valid enum parameter)
 bool Texture::setUsage(GLenum usage)
 {
@@ -1287,6 +1304,11 @@
     return mWrapT;
 }
 
+float Texture::getMaxAnisotropy() const
+{
+    return mMaxAnisotropy;
+}
+
 GLenum Texture::getUsage() const
 {
     return mUsage;
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 313a162..ccddf57 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -179,12 +179,14 @@
     bool setMagFilter(GLenum filter);
     bool setWrapS(GLenum wrap);
     bool setWrapT(GLenum wrap);
+    bool setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy);
     bool setUsage(GLenum usage);
 
     GLenum getMinFilter() const;
     GLenum getMagFilter() const;
     GLenum getWrapS() const;
     GLenum getWrapT() const;
+    float getMaxAnisotropy() const;
     GLenum getUsage() const;
 
     virtual bool isSamplerComplete() const = 0;
@@ -229,6 +231,7 @@
     GLenum mMagFilter;
     GLenum mWrapS;
     GLenum mWrapT;
+    float mMaxAnisotropy;
     bool mDirtyParameters;
     GLenum mUsage;
 
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index ca4ddff..9f3e591 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -3860,6 +3860,13 @@
               case GL_TEXTURE_USAGE_ANGLE:
                 *params = (GLfloat)texture->getUsage();
                 break;
+              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+                if (!context->supportsTextureFilterAnisotropy())
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                *params = (GLfloat)texture->getMaxAnisotropy();
+                break;
               default:
                 return error(GL_INVALID_ENUM);
             }
@@ -3915,6 +3922,13 @@
               case GL_TEXTURE_USAGE_ANGLE:
                 *params = texture->getUsage();
                 break;
+              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+                if (!context->supportsTextureFilterAnisotropy())
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                *params = (GLint)texture->getMaxAnisotropy();
+                break;
               default:
                 return error(GL_INVALID_ENUM);
             }
@@ -5482,12 +5496,84 @@
 
 void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param)
 {
-    glTexParameteri(target, pname, (GLint)param);
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param);
+
+    try
+    {
+        gl::Context *context = gl::getNonLostContext();
+
+        if (context)
+        {
+            gl::Texture *texture;
+
+            switch (target)
+            {
+              case GL_TEXTURE_2D:
+                texture = context->getTexture2D();
+                break;
+              case GL_TEXTURE_CUBE_MAP:
+                texture = context->getTextureCubeMap();
+                break;
+              default:
+                return error(GL_INVALID_ENUM);
+            }
+
+            switch (pname)
+            {
+              case GL_TEXTURE_WRAP_S:
+                if (!texture->setWrapS((GLenum)param))
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                break;
+              case GL_TEXTURE_WRAP_T:
+                if (!texture->setWrapT((GLenum)param))
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                break;
+              case GL_TEXTURE_MIN_FILTER:
+                if (!texture->setMinFilter((GLenum)param))
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                break;
+              case GL_TEXTURE_MAG_FILTER:
+                if (!texture->setMagFilter((GLenum)param))
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                break;
+              case GL_TEXTURE_USAGE_ANGLE:
+                if (!texture->setUsage((GLenum)param))
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                break;
+              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+                if (!context->supportsTextureFilterAnisotropy())
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return error(GL_INVALID_ENUM);
+            }
+        }
+    }
+    catch(std::bad_alloc&)
+    {
+        return error(GL_OUT_OF_MEMORY);
+    }
 }
 
 void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
 {
-    glTexParameteri(target, pname, (GLint)*params);
+    glTexParameterf(target, pname, (GLfloat)*params);
 }
 
 void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param)
@@ -5546,6 +5632,16 @@
                     return error(GL_INVALID_ENUM);
                 }
                 break;
+              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+                if (!context->supportsTextureFilterAnisotropy())
+                {
+                    return error(GL_INVALID_ENUM);
+                }
+                if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
               default:
                 return error(GL_INVALID_ENUM);
             }
diff --git a/src/libGLESv2/utilities.cpp b/src/libGLESv2/utilities.cpp
index a7c62d9..5cf005d 100644
--- a/src/libGLESv2/utilities.cpp
+++ b/src/libGLESv2/utilities.cpp
@@ -646,8 +646,13 @@
            (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
 }
 
-D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter)
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
 {
+    if (maxAnisotropy > 1.0f)
+    {
+        return D3DTEXF_ANISOTROPIC;
+    }
+
     D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
     switch (magFilter)
     {
@@ -659,7 +664,7 @@
     return d3dMagFilter;
 }
 
-void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter)
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy)
 {
     switch (minFilter)
     {
@@ -692,6 +697,11 @@
         *d3dMipFilter = D3DTEXF_NONE;
         UNREACHABLE();
     }
+
+    if (maxAnisotropy > 1.0f)
+    {
+        *d3dMinFilter = D3DTEXF_ANISOTROPIC;
+    }
 }
 
 bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
diff --git a/src/libGLESv2/utilities.h b/src/libGLESv2/utilities.h
index cf22418..5174680 100644
--- a/src/libGLESv2/utilities.h
+++ b/src/libGLESv2/utilities.h
@@ -63,8 +63,8 @@
 D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace);
 D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace);
 DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
-D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter);
-void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter);
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy);
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy);
 bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
                           D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount);
 D3DFORMAT ConvertRenderbufferFormat(GLenum format);