Make GPU coord transforms automatic

Adds a GrCoordTransform class and updates the framework to handle
coord transforms similar to how it handles textures with
GrTextureAccess. Renames GrGLEffectMatrix to GrGLCoordTransform and
slightly repurposes it to be used by the framework instead of effects.

R=bsalomon@google.com, robertphillips@google.com

Review URL: https://codereview.chromium.org/24853002

git-svn-id: http://skia.googlecode.com/svn/trunk/include@11569 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/GrBackendEffectFactory.h b/gpu/GrBackendEffectFactory.h
index 6f5cb3b..b3f52fb 100644
--- a/gpu/GrBackendEffectFactory.h
+++ b/gpu/GrBackendEffectFactory.h
@@ -33,15 +33,15 @@
     typedef uint32_t EffectKey;
     enum {
         kNoEffectKey = 0,
-        kEffectKeyBits = 15,
+        kEffectKeyBits = 10,
         /**
-         * Some aspects of the generated code may be determined by the particular textures that are
-         * associated with the effect. These manipulations are performed by GrGLShaderBuilder beyond
-         * GrGLEffects' control. So there is a dedicated part of the key which is combined
-         * automatically with the bits produced by GrGLEffect::GenKey().
+         * The framework automatically includes coord transforms and texture accesses in their
+         * effect's EffectKey, so effects don't need to account for them in GenKey().
          */
         kTextureKeyBits = 4,
-        kAttribKeyBits = 6
+        kTransformKeyBits = 6,
+        kAttribKeyBits = 6,
+        kClassIDBits = 6
     };
 
     virtual EffectKey glEffectKey(const GrDrawEffect&, const GrGLCaps&) const = 0;
@@ -56,6 +56,10 @@
 
     virtual const char* name() const = 0;
 
+    static EffectKey GetTransformKey(EffectKey key) {
+        return key >> (kEffectKeyBits + kTextureKeyBits) & ((1U << kTransformKeyBits) - 1);
+    }
+
 protected:
     enum {
         kIllegalEffectClassID = 0,
diff --git a/gpu/GrCoordTransform.h b/gpu/GrCoordTransform.h
new file mode 100644
index 0000000..afe2e5b
--- /dev/null
+++ b/gpu/GrCoordTransform.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCoordTransform_DEFINED
+#define GrCoordTransform_DEFINED
+
+#include "GrEffect.h"
+#include "SkMatrix.h"
+#include "GrTexture.h"
+#include "GrTypes.h"
+
+/**
+ * Coordinates available to GrEffect subclasses for requesting transformations. Transformed
+ * coordinates are made available in the the portion of fragment shader emitted by the effect.
+ */
+enum GrCoordSet {
+    /**
+     * The user-space coordinates that map to the fragment being rendered. These coords account for
+     * any change of coordinate system done on the CPU by GrContext before rendering, and also are
+     * correct for draws that take explicit local coords rather than inferring them from the
+     * primitive's positions (e.g. drawVertices). These are usually the coords a GrEffect wants.
+     */
+    kLocal_GrCoordSet,
+
+    /**
+     * The actual vertex position. Note that GrContext may not draw using the original view matrix
+     * specified by the caller, as it may have transformed vertices into another space. These are
+     * usually not the coordinates a GrEffect wants.
+     */
+    kPosition_GrCoordSet
+};
+
+/**
+ * A class representing a linear transformation from one of the built-in coordinate sets (local or
+ * position). GrEffects just define these transformations, and the framework does the rest of the
+ * work to make the transformed coordinates available in their fragment shader.
+ */
+class GrCoordTransform : public SkNoncopyable {
+public:
+    GrCoordTransform() {}
+
+    /**
+     * Create a transformation that maps [0, 1] to a texture's boundaries.
+     */
+    GrCoordTransform(GrCoordSet sourceCoords, const GrTexture* texture) {
+        this->reset(sourceCoords, texture);
+    }
+
+    /**
+     * Create a transformation from a matrix. The optional texture parameter is used to infer if the
+     * framework should internally do a y reversal to account for it being upside down by Skia's
+     * coord convention.
+     */
+    GrCoordTransform(GrCoordSet sourceCoords, const SkMatrix& m, const GrTexture* texture = NULL) {
+        this->reset(sourceCoords, m, texture);
+    }
+
+    void reset(GrCoordSet sourceCoords, const GrTexture* texture) {
+        SkASSERT(NULL != texture);
+        this->reset(sourceCoords, GrEffect::MakeDivByTextureWHMatrix(texture), texture);
+    }
+
+    void reset(GrCoordSet sourceCoords, const SkMatrix& m, const GrTexture* texture = NULL) {
+        fSourceCoords = sourceCoords;
+        fMatrix = m;
+        fReverseY = NULL != texture && kBottomLeft_GrSurfaceOrigin == texture->origin();
+    }
+
+    bool operator== (const GrCoordTransform& other) const {
+        return fSourceCoords == other.fSourceCoords &&
+               fMatrix.cheapEqualTo(other.fMatrix) &&
+               fReverseY == other.fReverseY;
+    }
+
+    GrCoordSet sourceCoords() const { return fSourceCoords; }
+    const SkMatrix& getMatrix() const { return fMatrix; }
+    bool reverseY() const { return fReverseY; }
+
+private:
+    GrCoordSet fSourceCoords;
+    SkMatrix   fMatrix;
+    bool       fReverseY;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+#endif
diff --git a/gpu/GrDrawEffect.h b/gpu/GrDrawEffect.h
index 8dae646..9a7a75d 100644
--- a/gpu/GrDrawEffect.h
+++ b/gpu/GrDrawEffect.h
@@ -14,8 +14,7 @@
  * The typical use case is that sometime after an effect was installed a decision was made to draw
  * in device coordinates (i.e. use an identity view-matrix). In such a case the GrDrawEffect's
  * coord-change-matrix would be the inverse of the view matrix that was set when the effect was
- * installed. GrGLEffectMatrix is a handy class that implements a local coordinate matrix that
- * automatically accounts for the coord-change matrix.
+ * installed.
  */
 class GrDrawEffect {
 public:
diff --git a/gpu/GrEffect.h b/gpu/GrEffect.h
index 4dc294b..7875270 100644
--- a/gpu/GrEffect.h
+++ b/gpu/GrEffect.h
@@ -16,6 +16,7 @@
 
 class GrBackendEffectFactory;
 class GrContext;
+class GrCoordTransform;
 class GrEffect;
 class GrVertexEffect;
 class SkString;
@@ -83,16 +84,6 @@
 public:
     SK_DECLARE_INST_COUNT(GrEffect)
 
-    /**
-     * The types of vertex coordinates available to an effect in the vertex shader. Effects can
-     * require their own vertex attribute but these coordinates are made available by the framework
-     * in all programs.
-     */
-    enum CoordsType {
-        kLocal_CoordsType,
-        kPosition_CoordsType,
-    };
-
     virtual ~GrEffect();
 
     /**
@@ -138,6 +129,12 @@
         in generated shader code. */
     const char* name() const;
 
+    int numTransforms() const { return fCoordTransforms.count(); }
+
+    /** Returns the coordinate transformation at index. index must be valid according to
+        numTransforms(). */
+    const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
+
     int numTextures() const { return fTextureAccesses.count(); }
 
     /** Returns the access pattern for the texture at index. index must be valid according to
@@ -205,9 +202,18 @@
 
 protected:
     /**
+     * Subclasses call this from their constructor to register coordinate transformations. The
+     * effect subclass manages the lifetime of the transformations (this function only stores a
+     * pointer). The GrCoordTransform is typically a member field of the GrEffect subclass. When the
+     * matrix has perspective, the transformed coordinates will have 3 components. Otherwise they'll
+     * have 2. This must only be called from the constructor because GrEffects are immutable.
+     */
+    void addCoordTransform(const GrCoordTransform* coordTransform);
+
+    /**
      * Subclasses call this from their constructor to register GrTextureAccesses. The effect
      * subclass manages the lifetime of the accesses (this function only stores a pointer). The
-     * GrTextureAccess is typically a member field of the GrEffet subclass. This must only be
+     * GrTextureAccess is typically a member field of the GrEffect subclass. This must only be
      * called from the constructor because GrEffects are immutable.
      */
     void addTextureAccess(const GrTextureAccess* textureAccess);
@@ -289,15 +295,14 @@
         bool result = this->onIsEqual(other);
 #ifdef SK_DEBUG
         if (result) {
-            SkASSERT(this->numTextures() == other.numTextures());
-            for (int i = 0; i < this->numTextures(); ++i) {
-                SkASSERT(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
-            }
+            this->assertEquality(other);
         }
 #endif
         return result;
     }
 
+    SkDEBUGCODE(void assertEquality(const GrEffect& other) const;)
+
     /** Subclass implements this to support isEqual(). It will only be called if it is known that
         the two effects are of the same subclass (i.e. they return the same object from
         getFactory()).*/
@@ -311,6 +316,7 @@
                                  // to inc/dec deferred ref counts.
     friend class GrVertexEffect; // to set fHasVertexCode and build fVertexAttribTypes.
 
+    SkSTArray<4, const GrCoordTransform*, true>  fCoordTransforms;
     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
     SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
     bool                                         fWillReadDstColor;
diff --git a/gpu/GrTBackendEffectFactory.h b/gpu/GrTBackendEffectFactory.h
index 1a01e1c..9528f8a 100644
--- a/gpu/GrTBackendEffectFactory.h
+++ b/gpu/GrTBackendEffectFactory.h
@@ -35,19 +35,29 @@
         SkASSERT(kIllegalEffectClassID != fEffectClassID);
         EffectKey effectKey = GLEffect::GenKey(drawEffect, caps);
         EffectKey textureKey = GLEffect::GenTextureKey(drawEffect, caps);
+        EffectKey transformKey = GLEffect::GenTransformKey(drawEffect);
         EffectKey attribKey = GLEffect::GenAttribKey(drawEffect);
 #ifdef SK_DEBUG
-        static const EffectKey kIllegalIDMask = (uint16_t) (~((1U << kEffectKeyBits) - 1));
-        SkASSERT(!(kIllegalIDMask & effectKey));
+        static const EffectKey kIllegalEffectKeyMask = (uint16_t) (~((1U << kEffectKeyBits) - 1));
+        SkASSERT(!(kIllegalEffectKeyMask & effectKey));
 
         static const EffectKey kIllegalTextureKeyMask = (uint16_t) (~((1U << kTextureKeyBits) - 1));
         SkASSERT(!(kIllegalTextureKeyMask & textureKey));
 
+        static const EffectKey kIllegalTransformKeyMask = (uint16_t) (~((1U << kTransformKeyBits) - 1));
+        SkASSERT(!(kIllegalTransformKeyMask & transformKey));
+
         static const EffectKey kIllegalAttribKeyMask = (uint16_t) (~((1U << kAttribKeyBits) - 1));
         SkASSERT(!(kIllegalAttribKeyMask & textureKey));
+
+        static const EffectKey kIllegalClassIDMask = (uint16_t) (~((1U << kClassIDBits) - 1));
+        SkASSERT(!(kIllegalClassIDMask & fEffectClassID));
 #endif
-        return fEffectClassID | (attribKey << (kEffectKeyBits+kTextureKeyBits)) |
-               (textureKey << kEffectKeyBits) | effectKey;
+        return (fEffectClassID << (kEffectKeyBits+kTextureKeyBits+kTransformKeyBits+kAttribKeyBits)) |
+               (attribKey << (kEffectKeyBits+kTextureKeyBits+kTransformKeyBits)) |
+               (transformKey << (kEffectKeyBits+kTextureKeyBits)) |
+               (textureKey << kEffectKeyBits) |
+               (effectKey);
     }
 
     /** Returns a new instance of the appropriate *GL* implementation class
@@ -71,7 +81,7 @@
 
 protected:
     GrTBackendEffectFactory() {
-        fEffectClassID = GenID() << (kAttribKeyBits + kEffectKeyBits + kTextureKeyBits) ;
+        fEffectClassID = GenID();
     }
 };