Use coverage stages for supersample AA resolve, edgeAA, and glyph masks. Expose a mask stage through GrPaint

Review URL: http://codereview.appspot.com/4548048/



git-svn-id: http://skia.googlecode.com/svn/trunk@1356 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index c29526a..2fecca5 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -579,11 +579,6 @@
     GrPathRenderer* getPathRenderer(const GrDrawTarget*, const GrPath&, GrPathFill);
 
     struct OffscreenRecord;
-    // we currently only expose stage 0 through the paint so use stage 1. We
-    // use stage 1 for the offscreen.
-    enum {
-        kOffscreenStage = 1,
-    };
 
     bool doOffscreenAA(GrDrawTarget* target, 
                        const GrPaint& paint,
@@ -602,6 +597,15 @@
                           const GrIRect& boundRect,
                           OffscreenRecord* record);
     
+    // computes vertex layout bits based on the paint. If paint expresses
+    // a texture for a stage, the stage coords will be bound to postitions
+    // unless hasTexCoords[s]==true in which case stage s's input coords
+    // are bound to tex coord index s. hasTexCoords == NULL is a shortcut
+    // for an array where all the values are false.
+    static int PaintStageVertexLayoutBits(
+                                    const GrPaint& paint,
+                                    const bool hasTexCoords[GrPaint::kTotalStages]);
+    
 };
 
 /**
diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h
index fae4e92..c79a191 100644
--- a/gpu/include/GrContext_impl.h
+++ b/gpu/include/GrContext_impl.h
@@ -40,19 +40,15 @@
                                           const COL_SRC* colorSrc,
                                           const IDX_SRC* idxSrc) {
 
-    GrVertexLayout layout = 0;
-
     GrDrawTarget::AutoReleaseGeometry geo;
 
     GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
 
-    if (NULL != paint.getTexture()) {
-        if (NULL != texCoordSrc) {
-            layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
-        } else {
-            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
-        }
-    }
+    bool hasTexCoords[GrPaint::kTotalStages] = {
+        NULL != texCoordSrc, // texCoordSrc provides explicit stage 0 coords
+        0                    // remaining stages use positions
+    };
+    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
 
     if (NULL != colorSrc) {
         layout |= GrDrawTarget::kColor_VertexLayoutBit;
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 9a00b57..985cca7 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -50,7 +50,7 @@
      * or not.
      */
     enum {
-        kNumStages = 2,
+        kNumStages = 3,
         kMaxTexCoords = kNumStages
     };
 
@@ -147,6 +147,7 @@
 
             // default stencil setting should be disabled
             GrAssert(fStencilSettings.isDisabled());
+            fFirstCoverageStage = kNumStages;
         }
         uint32_t                fFlagBits;
         GrBlendCoeff            fSrcBlend;
@@ -250,6 +251,18 @@
     }
 
     /**
+     * Shortcut for preConcatSamplerMatrix on all stages in mask with same 
+     * matrix
+     */
+    void preConcatSamplerMatrices(int stageMask, const GrMatrix& matrix) {
+        for (int i = 0; i < kNumStages; ++i) {
+            if ((1 << i) & stageMask) {
+                this->preConcatSamplerMatrix(i, matrix);
+            }
+        }
+    }
+
+    /**
      * Gets the matrix of a stage's sampler
      *
      * @param stage     the stage to of sampler to get
diff --git a/gpu/include/GrPaint.h b/gpu/include/GrPaint.h
index 3035ca1..f7ca34c 100644
--- a/gpu/include/GrPaint.h
+++ b/gpu/include/GrPaint.h
@@ -25,12 +25,17 @@
 
 /**
  * The paint describes how pixels are colored when the context draws to
- * them.
+ * them. TODO: Make this a "real" class with getters and setters, default
+ * values, and documentation.
  */
 class GrPaint {
 public:
+    enum {
+        kMaxTextures = 1,
+        kMaxMasks    = 1,
+    };
 
-    // All the paint fields are public except texture (it's ref-counted)
+    // All the paint fields are public except textures/samplers
     GrBlendCoeff                fSrcBlendCoeff;
     GrBlendCoeff                fDstBlendCoeff;
     bool                        fAntiAlias;
@@ -38,22 +43,75 @@
 
     GrColor                     fColor;
 
-    GrSamplerState              fSampler;
-
     GrColor                     fColorFilterColor;
     SkXfermode::Mode            fColorFilterXfermode;
 
-    void setTexture(GrTexture* texture) {
+    void setTexture(int i, GrTexture* texture) {
+        GrAssert((unsigned)i < kMaxTextures);
         GrSafeRef(texture);
-        GrSafeUnref(fTexture);
-        fTexture = texture;
+        GrSafeUnref(fTextures[i]);
+        fTextures[i] = texture;
     }
 
-    GrTexture* getTexture() const { return fTexture; }
+    GrTexture* getTexture(int i) const { 
+        GrAssert((unsigned)i < kMaxTextures);
+        return fTextures[i]; 
+    }
+
+    GrSamplerState* getTextureSampler(int i) {
+        GrAssert((unsigned)i < kMaxTextures);
+        return fTextureSamplers + i;
+    }
+
+    const GrSamplerState* getTextureSampler(int i) const {
+        GrAssert((unsigned)i < kMaxTextures);
+        return fTextureSamplers + i;
+    }
+
+    // The mask can be alpha-only or per channel. It is applied
+    // after the colorfilter
+    void setMask(int i, GrTexture* mask) {
+        GrAssert((unsigned)i < kMaxMasks);
+        GrSafeRef(mask);
+        GrSafeUnref(fMaskTextures[i]);
+        fMaskTextures[i] = mask;
+    }
+
+    GrTexture* getMask(int i) const { 
+        GrAssert((unsigned)i < kMaxMasks);
+        return fMaskTextures[i]; 
+    }
+
+    // mask's sampler matrix is always applied to the positions
+    // (i.e. no explicit texture coordinates)
+    GrSamplerState* getMaskSampler(int i) {
+        GrAssert((unsigned)i < kMaxMasks);
+        return fMaskSamplers + i;
+    }
+
+    const GrSamplerState* getMaskSampler(int i) const {
+        GrAssert((unsigned)i < kMaxMasks);
+        return fMaskSamplers + i;
+    }
+
+    // pre-concats sampler matrices for non-NULL textures and masks
+    void preConcatActiveSamplerMatrices(const GrMatrix& matrix) {
+        for (int i = 0; i < kMaxTextures; ++i) {
+            fTextureSamplers[i].preConcatMatrix(matrix);
+        }
+        for (int i = 0; i < kMaxMasks; ++i) {
+            fMaskSamplers[i].preConcatMatrix(matrix);
+        }
+    }
 
     // uninitialized
     GrPaint() {
-        fTexture = NULL;
+        for (int i = 0; i < kMaxTextures; ++i) {
+            fTextures[i] = NULL;
+        }
+        for (int i = 0; i < kMaxMasks; ++i) {
+            fMaskTextures[i] = NULL;
+        }
     }
 
     GrPaint(const GrPaint& paint) {
@@ -67,22 +125,35 @@
         fColorFilterColor = paint.fColorFilterColor;
         fColorFilterXfermode = paint.fColorFilterXfermode;
 
-        fSampler = paint.fSampler;
-        fTexture = paint.fTexture;
-        GrSafeRef(fTexture);
+        for (int i = 0; i < kMaxTextures; ++i) {
+            fTextureSamplers[i] = paint.fTextureSamplers[i];
+            fTextures[i] = paint.fTextures[i];
+            GrSafeRef(fTextures[i]);
+        }
+        for (int i = 0; i < kMaxMasks; ++i) {
+            fMaskSamplers[i] = paint.fMaskSamplers[i];
+            fMaskTextures[i] = paint.fMaskTextures[i];
+            GrSafeRef(fMaskTextures[i]);
+        }
     }
 
     ~GrPaint() {
-        GrSafeUnref(fTexture);
+        for (int i = 0; i < kMaxTextures; ++i) {
+            GrSafeUnref(fTextures[i]);
+        }
+        for (int i = 0; i < kMaxMasks; ++i) {
+            GrSafeUnref(fMaskTextures[i]);
+        }
     }
 
-    // sets paint to src-over, solid white, no texture
+    // sets paint to src-over, solid white, no texture, no mask
     void reset() {
-        resetBlend();
-        resetOptions();
-        resetColor();
-        resetTexture();
-        resetColorFilter();
+        this->resetBlend();
+        this->resetOptions();
+        this->resetColor();
+        this->resetTextures();
+        this->resetColorFilter();
+        this->resetMasks();
     }
 
     void resetColorFilter() {
@@ -90,8 +161,60 @@
         fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
     }
 
+    bool hasTexture() const {
+        return 0 != this->getActiveTextureStageMask();
+    }
+
+    bool hasMask() const {
+        return 0 != this->getActiveMaskStageMask();
+    }
+
+    bool hasTextureOrMask() const {
+        return this->hasTexture() || this->hasMask();
+    }
+
+    // helpers for GrContext, GrTextContext
+    int getActiveTextureStageMask() const {
+        int mask = 0;
+        for (int i = 0; i < kMaxTextures; ++i) {
+            if (NULL != fTextures[i]) {
+                mask |= 1 << (i + kFirstTextureStage);
+            }
+        }
+        return mask;
+    }
+
+    int getActiveMaskStageMask() const {
+        int mask;
+        for (int i = 0; i < kMaxMasks; ++i) {
+            if (NULL != fMaskTextures[i]) {
+                mask |= 1 << (i + kFirstMaskStage);
+            }
+        }
+        return mask;
+    }
+    
+    int getActiveStageMask() const {
+        return this->getActiveTextureStageMask() |
+                this->getActiveMaskStageMask();
+    }
+
+    // internal use
+    // GrPaint's textures and masks map to the first N stages
+    // of GrDrawTarget in that order (textures followed by masks)
+    enum {
+        kFirstTextureStage = 0,
+        kFirstMaskStage = kMaxTextures,
+        kTotalStages = kMaxTextures + kMaxMasks,
+    };
+
 private:
-    GrTexture*      fTexture;
+
+    GrSamplerState              fTextureSamplers[kMaxTextures];
+    GrSamplerState              fMaskSamplers[kMaxMasks];
+
+    GrTexture*      fTextures[kMaxTextures];
+    GrTexture*      fMaskTextures[kMaxMasks];
 
     void resetBlend() {
         fSrcBlendCoeff = kOne_BlendCoeff;
@@ -107,11 +230,19 @@
         fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
     }
 
-    void resetTexture() {
-        setTexture(NULL);
-        fSampler.setClampNoFilter();
+    void resetTextures() {
+        for (int i = 0; i < kMaxTextures; ++i) {
+            this->setTexture(i, NULL);
+            fTextureSamplers[i].setClampNoFilter();
+        }
     }
 
+    void resetMasks() {
+        for (int i = 0; i < kMaxMasks; ++i) {
+            this->setMask(i, NULL);
+            fMaskSamplers[i].setClampNoFilter();
+        }
+    }
 };
 
 #endif