Make GrDrawState::AutoRestoreViewMatrix handle sampler matrices.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@5853 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index ef59ca5..d702031 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -800,9 +800,7 @@
         GrDrawState::AutoViewMatrixRestore avmr;
         if (NULL != matrix) {
             GrDrawState* drawState = target->drawState();
-            avmr.set(drawState);
-            drawState->preConcatViewMatrix(*matrix);
-            drawState->preConcatSamplerMatrices(*matrix);
+            avmr.set(drawState, *matrix);
         }
 
         target->drawNonIndexed(primType, 0, vertCount);
@@ -815,7 +813,6 @@
             }
             target->setVertexSourceToBuffer(0, sqVB);
             GrDrawState* drawState = target->drawState();
-            GrDrawState::AutoViewMatrixRestore avmr(drawState);
             GrMatrix m;
             m.setAll(rect.width(),    0,             rect.fLeft,
                         0,            rect.height(), rect.fTop,
@@ -824,8 +821,7 @@
             if (NULL != matrix) {
                 m.postConcat(*matrix);
             }
-            drawState->preConcatViewMatrix(m);
-            drawState->preConcatSamplerMatrices(m);
+            GrDrawState::AutoViewMatrixRestore avmr(drawState, m);
 
             target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
 #else
@@ -852,7 +848,6 @@
 #if GR_STATIC_RECT_VB
     GrDrawState::AutoStageDisable atr(fDrawState);
     GrDrawState* drawState = target->drawState();
-    GrDrawState::AutoViewMatrixRestore avmr(drawState);
 
     GrMatrix m;
 
@@ -862,15 +857,11 @@
     if (NULL != dstMatrix) {
         m.postConcat(*dstMatrix);
     }
-    drawState->preConcatViewMatrix(m);
 
-    // we explicitly setup the correct coords for the first stage. The others
-    // must know about the view matrix change.
-    for (int s = 1; s < GrPaint::kTotalStages; ++s) {
-        if (drawState->isStageEnabled(s)) {
-            drawState->sampler(s)->preConcatMatrix(m);
-        }
-    }
+    // The first color stage's coords come from srcRect rather than applying a matrix to dstRect.
+    // We explicitly compute a matrix for that stage below, no need to adjust here.
+    static const uint32_t kExplicitCoordMask = 1 << GrPaint::kFirstColorStage;
+    GrDrawState::AutoViewMatrixRestore avmr(drawState, m, kExplicitCoordMask);
 
     m.setAll(srcRect.width(), 0,                srcRect.fLeft,
              0,               srcRect.height(), srcRect.fTop,
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index b9b708e..b0bbd06 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -49,11 +49,64 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrDrawState::AutoDeviceCoordDraw::AutoDeviceCoordDraw(GrDrawState* drawState,
-                                                      uint32_t explicitCoordStageMask) {
-    GrAssert(NULL != drawState);
+void GrDrawState::AutoViewMatrixRestore::restore() {
+    if (NULL != fDrawState) {
+        fDrawState->setViewMatrix(fViewMatrix);
+        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+            if (fRestoreMask & (1 << s)) {
+                *fDrawState->sampler(s)->matrix() = fSamplerMatrices[s];
+            }
+        }
+    }
+    fDrawState = NULL;
+}
+
+void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
+                                             const GrMatrix& preconcatMatrix,
+                                             uint32_t explicitCoordStageMask) {
+    this->restore();
 
     fDrawState = drawState;
+    if (NULL == drawState) {
+        return;
+    }
+
+    fRestoreMask = 0;
+    fViewMatrix = drawState->getViewMatrix();
+    drawState->preConcatViewMatrix(preconcatMatrix);
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
+            fRestoreMask |= (1 << s);
+            drawState->sampler(s)->preConcatMatrix(preconcatMatrix);
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawState::AutoDeviceCoordDraw::restore() {
+    if (NULL != fDrawState) {
+        fDrawState->setViewMatrix(fViewMatrix);
+        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+            if (fRestoreMask & (1 << s)) {
+                *fDrawState->sampler(s)->matrix() = fSamplerMatrices[s];
+            }
+        }
+    }
+    fDrawState = NULL;
+}
+
+bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState,
+                                           uint32_t explicitCoordStageMask) {
+    GrAssert(NULL != drawState);
+
+    this->restore();
+
+    fDrawState = drawState;
+    if (NULL == fDrawState) {
+        return false;
+    } 
+
     fViewMatrix = drawState->getViewMatrix();
     fRestoreMask = 0;
     GrMatrix invVM;
@@ -64,7 +117,7 @@
             if (!inverted && !fViewMatrix.invert(&invVM)) {
                 // sad trombone sound
                 fDrawState = NULL;
-                return;
+                return false;
             } else {
                 inverted = true;
             }
@@ -75,15 +128,5 @@
         }
     }
     drawState->viewMatrix()->reset();
-}
-
-GrDrawState::AutoDeviceCoordDraw::~AutoDeviceCoordDraw() {
-    if (NULL != fDrawState) {
-        fDrawState->setViewMatrix(fViewMatrix);
-        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            if (fRestoreMask & (1 << s)) {
-                *fDrawState->sampler(s)->matrix() = fSamplerMatrices[s];
-            }
-        }
-    }
+    return true;
 }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index ea8f418..5dccb15 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -467,70 +467,72 @@
     ////////////////////////////////////////////////////////////////////////////
 
     /**
-     * TODO: Automatically handle stage matrices.
+     * Preconcats the current view matrix and restores the previous view matrix in the destructor.
+     * Stage matrices are automatically adjusted to compensate.
      */
     class AutoViewMatrixRestore : public ::GrNoncopyable {
     public:
         AutoViewMatrixRestore() : fDrawState(NULL) {}
-        AutoViewMatrixRestore(GrDrawState* ds, const GrMatrix& newMatrix) {
+
+        AutoViewMatrixRestore(GrDrawState* ds,
+                              const GrMatrix& preconcatMatrix,
+                              uint32_t explicitCoordStageMask = 0) {
             fDrawState = NULL;
-            this->set(ds, newMatrix);
+            this->set(ds, preconcatMatrix, explicitCoordStageMask);
         }
-        AutoViewMatrixRestore(GrDrawState* ds) {
-            fDrawState = NULL;
-            this->set(ds);
-        }
-        ~AutoViewMatrixRestore() {
-            this->set(NULL, GrMatrix::I());
-        }
-        void set(GrDrawState* ds, const GrMatrix& newMatrix) {
-            if (NULL != fDrawState) {
-                fDrawState->setViewMatrix(fSavedMatrix);
-            }
-            if (NULL != ds) {
-                fSavedMatrix = ds->getViewMatrix();
-                ds->setViewMatrix(newMatrix);
-            }
-            fDrawState = ds;
-        }
-        void set(GrDrawState* ds) {
-            if (NULL != fDrawState) {
-                fDrawState->setViewMatrix(fSavedMatrix);
-            }
-            if (NULL != ds) {
-                fSavedMatrix = ds->getViewMatrix();
-            }
-            fDrawState = ds;
-        }
+
+        ~AutoViewMatrixRestore() { this->restore(); }
+
+        void restore();
+        
+        void set(GrDrawState* drawState,
+                 const GrMatrix& preconcatMatrix,
+                 uint32_t explicitCoordStageMask = 0);
+
         bool isSet() const { return NULL != fDrawState; }
+
     private:
-        GrDrawState* fDrawState;
-        GrMatrix fSavedMatrix;
+        GrDrawState*       fDrawState;
+        GrMatrix           fViewMatrix;
+        GrMatrix           fSamplerMatrices[GrDrawState::kNumStages];
+        uint32_t           fRestoreMask;
     };
 
     ////////////////////////////////////////////////////////////////////////////
 
     /**
-     * This sets the view matrix to identity and adjusts stage matrices to
-     * compensate. The destructor undoes the changes, restoring the view matrix
-     * that was set before the constructor.
+     * This sets the view matrix to identity and adjusts stage matrices to compensate. The
+     * destructor undoes the changes, restoring the view matrix that was set before the
+     * constructor. It is similar to passing the inverse of the current view matrix to
+     * AutoViewMatrixRestore, but lazily computes the inverse only if necessary.
      */
     class AutoDeviceCoordDraw : ::GrNoncopyable {
     public:
+        AutoDeviceCoordDraw() : fDrawState(NULL) {}
         /**
-         * If a stage's texture matrix is applied to explicit per-vertex coords,
-         * rather than to positions, then we don't want to modify its matrix.
-         * The explicitCoordStageMask is used to specify such stages.
+         * If a stage's texture matrix is applied to explicit per-vertex coords, rather than to
+         * positions, then we don't want to modify its matrix. The explicitCoordStageMask is used
+         * to specify such stages.
          */
         AutoDeviceCoordDraw(GrDrawState* drawState,
-                            uint32_t explicitCoordStageMask = 0);
+                            uint32_t explicitCoordStageMask = 0) {
+            fDrawState = NULL;
+            this->set(drawState, explicitCoordStageMask);
+        }
+
+        bool set(GrDrawState* drawState, uint32_t explicitCoordStageMask = 0);
+
         bool succeeded() const { return NULL != fDrawState; }
-        ~AutoDeviceCoordDraw();
+
+        void restore();
+
+        ~AutoDeviceCoordDraw() { this->restore(); }
+
     private:
         GrDrawState*       fDrawState;
         GrMatrix           fViewMatrix;
         GrMatrix           fSamplerMatrices[GrDrawState::kNumStages];
-        int                fRestoreMask;
+        uint32_t           fRestoreMask;
     };
 
     /// @}
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index 5a6b9db..a3f57cd 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -66,7 +66,6 @@
     GrAssert(drawState->getStencil().isDisabled());
 
     SkAutoTUnref<GrPath> p(fGpu->createPath(path));
-    GrDrawState::AutoViewMatrixRestore avmr;
 
     GrPathFill nonInvertedFill = GrNonInvertedFill(fill);
     target->stencilPath(p, nonInvertedFill);
@@ -77,6 +76,8 @@
     // fill the path, zero out the stencil
     GrRect bounds = p->getBounds();
     GrScalar bloat = drawState->getViewMatrix().getMaxStretch() * GR_ScalarHalf;
+    GrDrawState::AutoDeviceCoordDraw adcd;
+
     if (nonInvertedFill == fill) {
         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
             kZero_StencilOp,
@@ -107,12 +108,7 @@
             // theoretically could set bloat = 0, instead leave it because of matrix inversion
             // precision.
         } else {
-            avmr.set(drawState);
-            if (!drawState->preConcatSamplerMatricesWithInverse(drawState->getViewMatrix())) {
-                GrPrintf("Could not invert matrix.\n");
-                return false;
-            }
-            drawState->viewMatrix()->reset();
+            adcd.set(drawState);
             bloat = 0;
         }
         *drawState->stencil() = kInvertedStencilPass;