Separate out the texture matrix from the coord-system change matrix in GrSamplerState. This is a step towards moving texture matrix to GrCustomStage.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6721047

git-svn-id: http://skia.googlecode.com/svn/trunk@5973 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index be0f573..4fd6026 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -10,17 +10,20 @@
 #ifndef GrContext_DEFINED
 #define GrContext_DEFINED
 
-#include "GrConfig.h"
-#include "GrPaint.h"
+#include "GrColor.h"
 #include "GrAARectRenderer.h"
 #include "GrClipData.h"
+#include "GrMatrix.h"
+#include "GrPaint.h"
 // not strictly needed but requires WK change in LayerTextureUpdaterCanvas to
 // remove.
 #include "GrRenderTarget.h"
-#include "SkClipStack.h"
+#include "GrRefCnt.h"
+#include "GrTexture.h"
 
 class GrAutoScratchTexture;
 class GrCacheKey;
+class GrCustomStage;
 class GrDrawState;
 class GrDrawTarget;
 class GrFontCache;
@@ -33,6 +36,7 @@
 class GrResourceEntry;
 class GrResourceCache;
 class GrStencilBuffer;
+class GrTextureParams;
 class GrVertexBuffer;
 class GrVertexBufferAllocPool;
 class GrSoftwarePathRenderer;
@@ -711,7 +715,7 @@
             this->restore();
 
             if (NULL != paint) {
-                if (!paint->preConcatSamplerMatricesWithInverse(context->getMatrix())) {
+                if (!paint->sourceCoordChangeByInverse(context->getMatrix())) {
                     return false;
                 }
             }
@@ -749,7 +753,7 @@
          */
         void preConcat(const GrMatrix& preConcat, GrPaint* paint = NULL) {
             if (NULL != paint) {
-                paint->preConcatSamplerMatrices(preConcat);
+                paint->sourceCoordChange(preConcat);
             }
             fContext->concatMatrix(preConcat);
         }
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 3c29662..843a934 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -10,7 +10,6 @@
 #ifndef GrPaint_DEFINED
 #define GrPaint_DEFINED
 
-#include "GrTexture.h"
 #include "GrColor.h"
 #include "GrSamplerState.h"
 
@@ -189,47 +188,49 @@
     bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
 
     /**
-     * Preconcats the matrix of all enabled stages with the inverse of a matrix. If the matrix
-     * inverse cannot be computed (and there is at least one enabled stage) then false is returned.
+     * Called when the source coord system is changing. preConcatInverse is the inverse of the
+     * transformation from the old coord system to the new coord system. Returns false if the matrix
+     * cannot be inverted.
      */
-    bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
+    bool sourceCoordChangeByInverse(const GrMatrix& preConcatInverse) {
         GrMatrix inv;
         bool computed = false;
         for (int i = 0; i < kMaxColorStages; ++i) {
             if (this->isColorStageEnabled(i)) {
-                if (!computed && !matrix.invert(&inv)) {
+                if (!computed && !preConcatInverse.invert(&inv)) {
                     return false;
                 } else {
                     computed = true;
                 }
-                fColorSamplers[i].preConcatMatrix(inv);
+                fColorSamplers[i].preConcatCoordChange(inv);
             }
         }
         for (int i = 0; i < kMaxCoverageStages; ++i) {
             if (this->isCoverageStageEnabled(i)) {
-                if (!computed && !matrix.invert(&inv)) {
+                if (!computed && !preConcatInverse.invert(&inv)) {
                     return false;
                 } else {
                     computed = true;
                 }
-                fCoverageSamplers[i].preConcatMatrix(inv);
+                fCoverageSamplers[i].preConcatCoordChange(inv);
             }
         }
         return true;
     }
 
     /**
-     * Preconcats the matrix of all stages with a matrix.
+     * Called when the source coord system is changing. preConcat gives the transformation from the
+     * old coord system to the new coord system.
      */
-    void preConcatSamplerMatrices(const GrMatrix& matrix) {
+    void sourceCoordChange(const GrMatrix& preConcat) {
         for (int i = 0; i < kMaxColorStages; ++i) {
             if (this->isColorStageEnabled(i)) {
-                fColorSamplers[i].preConcatMatrix(matrix);
+                fColorSamplers[i].preConcatCoordChange(preConcat);
             }
         }
         for (int i = 0; i < kMaxCoverageStages; ++i) {
             if (this->isCoverageStageEnabled(i)) {
-                fCoverageSamplers[i].preConcatMatrix(matrix);
+                fCoverageSamplers[i].preConcatCoordChange(preConcat);
             }
         }
     }
diff --git a/include/gpu/GrSamplerState.h b/include/gpu/GrSamplerState.h
index da52e95..bb7e42a 100644
--- a/include/gpu/GrSamplerState.h
+++ b/include/gpu/GrSamplerState.h
@@ -22,79 +22,125 @@
 
     GrSamplerState()
     : fCustomStage (NULL) {
-        memset(this, 0, sizeof(GrSamplerState));
-        this->reset();
+        GR_DEBUGCODE(fSavedCoordChangeCnt = 0;)
     }
 
     ~GrSamplerState() {
         GrSafeUnref(fCustomStage);
+        GrAssert(0 == fSavedCoordChangeCnt);
     }
 
-    bool operator ==(const GrSamplerState& s) const {
-        /* We must be bit-identical as far as the CustomStage;
-           there may be multiple CustomStages that will produce
-           the same shader code and so are equivalent.
-           Can't take the address of fWrapX because it's :8 */
-        int bitwiseRegion = (intptr_t) &fCustomStage - (intptr_t) this;
-        GrAssert(sizeof(GrSamplerState) ==
-                 bitwiseRegion + sizeof(fCustomStage));
-        return !memcmp(this, &s, bitwiseRegion) &&
-               ((fCustomStage == s.fCustomStage) ||
-                (fCustomStage && s.fCustomStage &&
-                 (fCustomStage->getFactory() ==
-                     s.fCustomStage->getFactory()) &&
-                 fCustomStage->isEqual(*s.fCustomStage)));
+    bool operator ==(const GrSamplerState& other) const {
+        // first handle cases where one or the other has no custom stage
+        if (NULL == fCustomStage) {
+            return NULL == other.fCustomStage;
+        } else if (NULL == other.fCustomStage) {
+            return false;
+        }
+
+        if (fCustomStage->getFactory() != other.fCustomStage->getFactory()) {
+            return false;
+        }
+
+        if (!fCustomStage->isEqual(*other.fCustomStage)) {
+            return false;
+        }
+
+        return fMatrix == other.fMatrix && fCoordChangeMatrix == other.fCoordChangeMatrix;
     }
+
     bool operator !=(const GrSamplerState& s) const { return !(*this == s); }
 
-    GrSamplerState& operator =(const GrSamplerState& s) {
-        fMatrix = s.fMatrix;
-        GrSafeAssign(fCustomStage, s.fCustomStage);
+    GrSamplerState& operator =(const GrSamplerState& other) {
+        GrSafeAssign(fCustomStage, other.fCustomStage);
+        if (NULL != fCustomStage) {
+            fMatrix = other.fMatrix;
+            fCoordChangeMatrix = other.fCoordChangeMatrix;
+        }
         return *this;
     }
 
+    /**
+     * This is called when the coordinate system in which the geometry is specified will change.
+     *
+     * @param matrix    The transformation from the old coord system to the new one. 
+     */
+    void preConcatCoordChange(const GrMatrix& matrix) { fCoordChangeMatrix.preConcat(matrix); }
+
+    class SavedCoordChange {
+    private:
+        GrMatrix fCoordChangeMatrix;
+        GR_DEBUGCODE(mutable SkAutoTUnref<GrCustomStage> fCustomStage;)
+
+        friend class GrSamplerState;
+    };
+
+    /**
+     * This gets the current coordinate system change. It is the accumulation of
+     * preConcatCoordChange calls since the custom stage was installed. It is used when then caller
+     * wants to temporarily change the source geometry coord system, draw something, and then
+     * restore the previous coord system (e.g. temporarily draw in device coords).s
+     */
+    void saveCoordChange(SavedCoordChange* savedCoordChange) const {
+        savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix;
+        GrAssert(NULL == savedCoordChange->fCustomStage.get());
+        GR_DEBUGCODE(GrSafeRef(fCustomStage);)
+        GR_DEBUGCODE(savedCoordChange->fCustomStage.reset(fCustomStage);)
+        GR_DEBUGCODE(++fSavedCoordChangeCnt);
+    }
+
+    /**
+     * This balances the saveCoordChange call.
+     */
+    void restoreCoordChange(const SavedCoordChange& savedCoordChange) {
+        fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix;
+        GrAssert(savedCoordChange.fCustomStage.get() == fCustomStage);
+        GR_DEBUGCODE(--fSavedCoordChangeCnt);
+        GR_DEBUGCODE(savedCoordChange.fCustomStage.reset(NULL);)
+    }
+
+    /**
+     * Gets the texture matrix. This is will be removed soon and be managed by GrCustomStage.
+     */
     const GrMatrix& getMatrix() const { return fMatrix; }
 
     /**
-     *  Multiplies the current sampler matrix  a matrix
-     *
-     *  After this call M' = M*m where M is the old matrix, m is the parameter
-     *  to this function, and M' is the new matrix. (We consider points to
-     *  be column vectors so tex cood vector t is transformed by matrix X as
-     *  t' = X*t.)
-     *
-     *  @param matrix   the matrix used to modify the matrix.
+     * Gets the matrix to apply at draw time. This is the original texture matrix combined with
+     * any coord system changes.
      */
-    void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); }
-
-    /**
-     * Do not call this function. It will be removed soon.
-     */
-    void setMatrixDeprecated(const GrMatrix& matrix) { fMatrix = matrix; }
+    void getTotalMatrix(GrMatrix* matrix) const {
+        *matrix = fMatrix;
+        matrix->preConcat(fCoordChangeMatrix);
+    }
 
     void reset() {
-        fMatrix.reset();
         GrSafeSetNull(fCustomStage);
     }
 
     GrCustomStage* setCustomStage(GrCustomStage* stage) {
+        GrAssert(0 == fSavedCoordChangeCnt);
         GrSafeAssign(fCustomStage, stage);
         fMatrix.reset();
+        fCoordChangeMatrix.reset();
         return stage;
     }
 
     GrCustomStage* setCustomStage(GrCustomStage* stage, const GrMatrix& matrix) {
+        GrAssert(0 == fSavedCoordChangeCnt);
         GrSafeAssign(fCustomStage, stage);
         fMatrix = matrix;
+        fCoordChangeMatrix.reset();
         return stage;
     }
 
     const GrCustomStage* getCustomStage() const { return fCustomStage; }
 
 private:
-    GrMatrix            fMatrix;
-
+    GrMatrix            fCoordChangeMatrix;
+    GrMatrix            fMatrix; // TODO: remove this, store in GrCustomStage
     GrCustomStage*      fCustomStage;
+
+    GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;)
 };
 
 #endif
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 4f725af..2b9179f 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -450,6 +450,7 @@
                 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
             }
             GrRect bounds;
+            GrDrawState::AutoDeviceCoordDraw adcd;
             if (reverse) {
                 GrAssert(NULL != drawState->getRenderTarget());
                 // draw over the whole world.
@@ -462,12 +463,7 @@
                     drawState->getViewInverse(&vmi)) {
                     vmi.mapRect(&bounds);
                 } else {
-                    const GrMatrix& vm = drawState->getViewMatrix();
-                    if (!drawState->preConcatSamplerMatricesWithInverse(vm)) {
-                        GrPrintf("Could not invert matrix.\n");
-                        return false;
-                    }
-                    drawState->viewMatrix()->reset();
+                    adcd.set(drawState);
                 }
             } else {
                 bounds = path.getBounds();
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index cc11f6c..c95049a 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -54,7 +54,7 @@
         fDrawState->setViewMatrix(fViewMatrix);
         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
             if (fRestoreMask & (1 << s)) {
-                fDrawState->sampler(s)->setMatrixDeprecated(fSamplerMatrices[s]);
+                fDrawState->sampler(s)->restoreCoordChange(fSavedCoordChanges[s]);
             }
         }
     }
@@ -77,8 +77,8 @@
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
             fRestoreMask |= (1 << s);
-            fSamplerMatrices[s] = drawState->sampler(s)->getMatrix();
-            drawState->sampler(s)->preConcatMatrix(preconcatMatrix);
+            fDrawState->sampler(s)->saveCoordChange(&fSavedCoordChanges[s]);
+            drawState->sampler(s)->preConcatCoordChange(preconcatMatrix);
         }
     }
 }
@@ -90,7 +90,7 @@
         fDrawState->setViewMatrix(fViewMatrix);
         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
             if (fRestoreMask & (1 << s)) {
-                fDrawState->sampler(s)->setMatrixDeprecated(fSamplerMatrices[s]);
+                fDrawState->sampler(s)->restoreCoordChange(fSavedCoordChanges[s]);
             }
         }
     }
@@ -124,8 +124,8 @@
             }
             fRestoreMask |= (1 << s);
             GrSamplerState* sampler = drawState->sampler(s);
-            fSamplerMatrices[s] = sampler->getMatrix();
-            sampler->preConcatMatrix(invVM);
+            sampler->saveCoordChange(&fSavedCoordChanges[s]);
+            sampler->preConcatCoordChange(invVM);
         }
     }
     drawState->viewMatrix()->reset();
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index f3d5e37..7bfb5e5 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -10,7 +10,6 @@
 
 #include "GrColor.h"
 #include "GrMatrix.h"
-#include "GrNoncopyable.h"
 #include "GrRefCnt.h"
 #include "GrSamplerState.h"
 #include "GrStencil.h"
@@ -267,32 +266,33 @@
     }
 
     /**
-     * Preconcats the matrix of all samplers of enabled stages with a matrix.
+     * Called when the source coord system is changing. preConcat gives the transformation from the
+     * old coord system to the new coord system.
      */
-    void preConcatSamplerMatrices(const GrMatrix& matrix) {
+    void preConcatSamplerMatrices(const GrMatrix& preConcat) {
         for (int i = 0; i < kNumStages; ++i) {
             if (this->isStageEnabled(i)) {
-                fSamplerStates[i].preConcatMatrix(matrix);
+                fSamplerStates[i].preConcatCoordChange(preConcat);
             }
         }
     }
 
     /**
-     * Preconcats the matrix of all samplers in the mask with the inverse of a
-     * matrix. If the matrix inverse cannot be computed (and there is at least
-     * one enabled stage) then false is returned.
+     * Called when the source coord system is changing. preConcatInverse is the inverse of the
+     * transformation from the old coord system to the new coord system. Returns false if the matrix
+     * cannot be inverted.
      */
-    bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
+    bool preConcatSamplerMatricesWithInverse(const GrMatrix& preConcatInverse) {
         GrMatrix inv;
         bool computed = false;
         for (int i = 0; i < kNumStages; ++i) {
             if (this->isStageEnabled(i)) {
-                if (!computed && !matrix.invert(&inv)) {
+                if (!computed && !preConcatInverse.invert(&inv)) {
                     return false;
                 } else {
                     computed = true;
                 }
-                fSamplerStates[i].preConcatMatrix(inv);
+                fSamplerStates[i].preConcatCoordChange(preConcatInverse);
             }
         }
         return true;
@@ -503,10 +503,10 @@
         bool isSet() const { return NULL != fDrawState; }
 
     private:
-        GrDrawState*       fDrawState;
-        GrMatrix           fViewMatrix;
-        GrMatrix           fSamplerMatrices[GrDrawState::kNumStages];
-        uint32_t           fRestoreMask;
+        GrDrawState*                        fDrawState;
+        GrMatrix                            fViewMatrix;
+        GrSamplerState::SavedCoordChange    fSavedCoordChanges[GrDrawState::kNumStages];
+        uint32_t                            fRestoreMask;
     };
 
     ////////////////////////////////////////////////////////////////////////////
@@ -557,10 +557,10 @@
         void restore();
 
     private:
-        GrDrawState*       fDrawState;
-        GrMatrix           fViewMatrix;
-        GrMatrix           fSamplerMatrices[GrDrawState::kNumStages];
-        uint32_t           fRestoreMask;
+        GrDrawState*                        fDrawState;
+        GrMatrix                            fViewMatrix;
+        GrSamplerState::SavedCoordChange    fSavedCoordChanges[GrDrawState::kNumStages];
+        uint32_t                            fRestoreMask;
     };
 
     /// @}
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index d2a22d0..351ff53 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -151,11 +151,9 @@
     static void AdjustTextureMatrix(const GrGLTexture* texture,
                                     GrMatrix* matrix);
 
-    // subclass may try to take advantage of identity tex matrices.
-    // This helper determines if matrix will be identity after all
-    // adjustments are applied.
-    static bool TextureMatrixIsIdentity(const GrGLTexture* texture,
-                                        const GrSamplerState& sampler);
+    // This helper determines if what optimizations can be applied to the matrix after any coord
+    // adjustments are applied. The return is a bitfield of GrGLProgram::StageDesc::OptFlags.
+    static int TextureMatrixOptFlags(const GrGLTexture* texture, const GrSamplerState& sampler);
 
     static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
 
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 9e3a5d8..e579331 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -177,19 +177,20 @@
     }
 }
 
-bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
-                                      const GrSamplerState& sampler) {
+int GrGpuGL::TextureMatrixOptFlags(const GrGLTexture* texture,
+                                   const GrSamplerState& sampler) {
     GrAssert(NULL != texture);
-    if (!sampler.getMatrix().isIdentity()) {
-        return false;
+    GrMatrix matrix;
+    sampler.getTotalMatrix(&matrix);
+
+    bool canBeIndentity = GrGLTexture::kTopDown_Orientation == texture->orientation();
+
+    if (canBeIndentity && matrix.isIdentity()) {
+        return GrGLProgram::StageDesc::kIdentityMatrix_OptFlagBit;
+    } else if (!matrix.hasPerspective()) {
+        return GrGLProgram::StageDesc::kNoPerspective_OptFlagBit;
     }
-    GrGLTexture::Orientation orientation = texture->orientation();
-    if (GrGLTexture::kBottomUp_Orientation == orientation) {
-        return false;
-    } else {
-        GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
-    }
-    return true;
+    return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -208,7 +209,8 @@
         UniformHandle matrixUni = fCurrentProgram->fUniforms.fStages[s].fTextureMatrixUni;
 
         const GrMatrix& hwMatrix = fCurrentProgram->fTextureMatrices[s];
-        const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix();
+        GrMatrix samplerMatrix;
+        drawState.getSampler(s).getTotalMatrix(&samplerMatrix);
 
         if (kInvalidUniformHandle != matrixUni &&
             (orientationChange || !hwMatrix.cheapEqualTo(samplerMatrix))) {
@@ -238,7 +240,6 @@
     }
 }
 
-
 void GrGpuGL::flushColorMatrix() {
     UniformHandle matrixUni = fCurrentProgram->fUniforms.fColorMatrixUni;
     UniformHandle vecUni = fCurrentProgram->fUniforms.fColorMatrixVecUni;
@@ -701,15 +702,13 @@
             // FIXME: Still assuming one texture per custom stage
             const GrCustomStage* customStage = drawState.getSampler(s).getCustomStage();
             const GrGLTexture* texture = static_cast<const GrGLTexture*>(customStage->texture(0));
+            GrMatrix samplerMatrix;
+            sampler.getTotalMatrix(&samplerMatrix);
             if (NULL != texture) {
                 // We call this helper function rather then simply checking the client-specified
                 // texture matrix. This is because we may have to concat a y-inversion to account
                 // for texture orientation.
-                if (TextureMatrixIsIdentity(texture, sampler)) {
-                    stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
-                } else if (!sampler.getMatrix().hasPerspective()) {
-                    stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
-                }
+                stage.fOptFlags |= TextureMatrixOptFlags(texture, sampler);
             }
 
             setup_custom_stage(&stage, sampler, this->glCaps(), customStages,