This change will ultimately pull uniform color, and to a much lesser degree uniform...
authorjoshualitt <joshualitt@chromium.org>
Mon, 15 Dec 2014 22:16:27 +0000 (14:16 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 15 Dec 2014 22:16:27 +0000 (14:16 -0800)
BUG=skia:

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

34 files changed:
expectations/gm/ignored-tests.txt
gyp/gpu.gypi
include/core/SkTemplates.h
include/gpu/GrXferProcessor.h
include/gpu/effects/GrPorterDuffXferProcessor.h
src/gpu/GrAAConvexPathRenderer.cpp
src/gpu/GrDefaultGeoProcFactory.cpp
src/gpu/GrGeometryProcessor.cpp [new file with mode: 0644]
src/gpu/GrGeometryProcessor.h
src/gpu/GrInOrderDrawBuffer.cpp
src/gpu/GrInOrderDrawBuffer.h
src/gpu/GrOptDrawState.cpp
src/gpu/GrOptDrawState.h
src/gpu/GrOvalRenderer.cpp
src/gpu/GrProcOptInfo.cpp
src/gpu/GrProcOptInfo.h
src/gpu/GrProcessor.cpp
src/gpu/GrProgramDesc.h
src/gpu/effects/GrBezierEffect.cpp
src/gpu/effects/GrBezierEffect.h
src/gpu/effects/GrBitmapTextGeoProc.cpp
src/gpu/effects/GrBitmapTextGeoProc.h
src/gpu/effects/GrDashingEffect.cpp
src/gpu/effects/GrDistanceFieldTextureEffect.cpp
src/gpu/effects/GrDistanceFieldTextureEffect.h
src/gpu/effects/GrPorterDuffXferProcessor.cpp
src/gpu/gl/GrGLGeometryProcessor.h
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLProgramDesc.cpp
src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp
src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
src/gpu/gl/builders/GrGLProgramBuilder.cpp
src/gpu/gl/builders/GrGLProgramBuilder.h

index a8b19b7..4974daf 100644 (file)
@@ -60,6 +60,9 @@ drawbitmapmatrix
 #junov skbug.com/3176
 pictureimagefilter
 
+#joshualitt
+hairlines
+
 #scroggo skbug.com/3241
 # replacing SkLCGRandom with SkRandom
 beziers
index 1570ab4..d39054e 100644 (file)
@@ -87,6 +87,7 @@
       '<(skia_src_path)/gpu/GrGeometryBuffer.h',
       '<(skia_src_path)/gpu/GrGeometryData.h',
       '<(skia_src_path)/gpu/GrGeometryProcessor.h',
+      '<(skia_src_path)/gpu/GrGeometryProcessor.cpp',
       '<(skia_src_path)/gpu/GrGlyph.h',
       '<(skia_src_path)/gpu/GrGpu.cpp',
       '<(skia_src_path)/gpu/GrGpu.h',
index 5ef28ea..3571af6 100644 (file)
@@ -464,6 +464,7 @@ private:
 template <size_t N> class SkAlignedSStorage : SkNoncopyable {
 public:
     void* get() { return fData; }
+    const void* get() const { return fData; }
 private:
     union {
         void*   fPtr;
index 40629ea..bab6141 100644 (file)
@@ -58,13 +58,13 @@ public:
          */
         kSkipDraw_OptFlag                 = 0x1,
         /**
-         * Clear color stages, remove color vertex attribs, and use input color
+         * GrXferProcessor will ignore color, thus no need to provide
          */
-        kClearColorStages_OptFlag         = 0x2,
+        kIgnoreColor_OptFlag              = 0x2,
         /**
-         * Clear coverage stages, remove coverage vertex attribs, and use input coverage
+         * GrXferProcessor will ignore coverage, thus no need to provide
          */
-        kClearCoverageStages_OptFlag      = 0x4,
+        kIgnoreCoverage_OptFlag           = 0x4,
         /**
          * Clear color stages and override input color to that returned by getOptimizations
          */
@@ -94,7 +94,6 @@ public:
                                       bool colorWriteDisabled,
                                       bool doesStencilWrite,
                                       GrColor* overrideColor,
-                                      uint8_t* overrideCoverage,
                                       const GrDrawTargetCaps& caps) = 0;
 
     struct BlendInfo {
index 6c860b9..a348a02 100644 (file)
@@ -37,6 +37,9 @@ public:
     ////
 
     enum PrimaryOutputType {
+        kNone_PrimaryOutputType,
+        kColor_PrimaryOutputType,
+        kCoverage_PrimaryOutputType,
         // Modulate color and coverage, write result as the color output.
         kModulate_PrimaryOutputType,
         // Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This
@@ -68,8 +71,7 @@ public:
                                                bool isCoverageDrawing,
                                                bool colorWriteDisabled,
                                                bool doesStencilWrite,
-                                               GrColor* color,
-                                               uint8_t* coverage,
+                                               GrColor* overrideColor,
                                                const GrDrawTargetCaps& caps) SK_OVERRIDE;
 
     void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
@@ -99,9 +101,7 @@ private:
                                                        const GrProcOptInfo& coveragePOI,
                                                        bool isCoverageDrawing,
                                                        bool colorWriteDisabled,
-                                                       bool doesStencilWrite,
-                                                       GrColor* color,
-                                                       uint8_t* coverage);
+                                                       bool doesStencilWrite);
 
     void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps,
                          bool hasSolidCoverage, bool readDst);
index 0007e33..93e2b37 100644 (file)
@@ -519,16 +519,24 @@ public:
     class GLProcessor : public GrGLGeometryProcessor {
     public:
         GLProcessor(const GrGeometryProcessor&,
-                    const GrBatchTracker&) {}
+                    const GrBatchTracker&)
+            : fColor(GrColor_ILLEGAL) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
-            GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
+            GrGLGPBuilder* pb = args.fPB;
+            GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder();
 
             GrGLVertToFrag v(kVec4f_GrSLType);
             args.fPB->addVarying("QuadEdge", &v);
             vsBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
 
+            const BatchTracker& local = args.fBT.cast<BatchTracker>();
+
+            // Setup pass through color
+            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
+                                        &fColorUniform);
+
             // setup coord outputs
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), qe.inPosition()->fName);
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), qe.inPosition()->fName);
@@ -562,16 +570,30 @@ public:
             fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
         }
 
-        static inline void GenKey(const GrGeometryProcessor&,
-                                  const GrBatchTracker&,
+        static inline void GenKey(const GrGeometryProcessor& gp,
+                                  const GrBatchTracker& bt,
                                   const GrGLCaps&,
-                                  GrProcessorKeyBuilder*) {}
+                                  GrProcessorKeyBuilder* b) {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            b->add32(local.fInputColorType);
+        }
 
-        virtual void setData(const GrGLProgramDataManager&,
-                             const GrGeometryProcessor&,
-                             const GrBatchTracker&) SK_OVERRIDE {}
+        virtual void setData(const GrGLProgramDataManager& pdman,
+                             const GrPrimitiveProcessor& gp,
+                             const GrBatchTracker& bt) SK_OVERRIDE {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+                GrGLfloat c[4];
+                GrColorToRGBAFloat(local.fColor, c);
+                pdman.set4fv(fColorUniform, 1, c);
+                fColor = local.fColor;
+            }
+        }
 
     private:
+        GrColor fColor;
+        UniformHandle fColorUniform;
+
         typedef GrGLGeometryProcessor INHERITED;
     };
 
@@ -585,6 +607,18 @@ public:
         return SkNEW_ARGS(GLProcessor, (*this, bt));
     }
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE {
+        BatchTracker* local = bt->cast<BatchTracker>();
+        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+    }
+
+    bool onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const SK_OVERRIDE {
+        const BatchTracker& mine = m.cast<BatchTracker>();
+        const BatchTracker& theirs = t.cast<BatchTracker>();
+        return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                                theirs.fInputColorType, theirs.fColor);
+    }
+
 private:
     QuadEdgeEffect(GrColor color) : INHERITED(color) {
         this->initClassID<QuadEdgeEffect>();
@@ -600,6 +634,11 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    struct BatchTracker {
+        GrGPInput fInputColorType;
+        GrColor fColor;
+    };
+
     const GrAttribute* fInPosition;
     const GrAttribute* fInQuadEdge;
 
index cb73959..f7b85ee 100644 (file)
@@ -32,22 +32,54 @@ public:
     const GrAttribute* inColor() const { return fInColor; }
     const GrAttribute* inLocalCoords() const { return fInLocalCoords; }
     const GrAttribute* inCoverage() const { return fInCoverage; }
+    uint8_t coverage() const { return fCoverage; }
+
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE {
+        BatchTracker* local = bt->cast<BatchTracker>();
+        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
+                                                   SkToBool(fInColor));
+
+        bool hasVertexCoverage = SkToBool(fInCoverage) && !init.fCoverageIgnored;
+        bool covIsSolidWhite = !hasVertexCoverage && 0xff == this->coverage();
+        if (covIsSolidWhite) {
+            local->fInputCoverageType = kAllOnes_GrGPInput;
+        } else if (!hasVertexCoverage) {
+            local->fInputCoverageType = kUniform_GrGPInput;
+            local->fCoverage = this->coverage();
+        } else if (hasVertexCoverage) {
+            SkASSERT(fInCoverage);
+            local->fInputCoverageType = kAttribute_GrGPInput;
+        } else {
+            local->fInputCoverageType = kIgnored_GrGPInput;
+        }
+    }
+
+    bool onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const SK_OVERRIDE {
+        const BatchTracker& mine = m.cast<BatchTracker>();
+        const BatchTracker& theirs = t.cast<BatchTracker>();
+        return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                                theirs.fInputColorType, theirs.fColor) &&
+               CanCombineOutput(mine.fInputCoverageType, mine.fCoverage,
+                                theirs.fInputCoverageType, theirs.fCoverage);
+    }
 
     class GLProcessor : public GrGLGeometryProcessor {
     public:
-        GLProcessor(const GrGeometryProcessor&,
-                    const GrBatchTracker&) {}
+        GLProcessor(const GrGeometryProcessor& gp, const GrBatchTracker&)
+            : fColor(GrColor_ILLEGAL), fCoverage(0xff) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
-            GrGLVertexBuilder* vs = args.fPB->getVertexShaderBuilder();
+            GrGLGPBuilder* pb = args.fPB;
+            GrGLVertexBuilder* vs = pb->getVertexShaderBuilder();
+            GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder();
+            const BatchTracker& local = args.fBT.cast<BatchTracker>();
 
             vs->codeAppendf("%s = %s;", vs->positionCoords(), gp.inPosition()->fName);
 
             // Setup pass through color
-            if (gp.inColor()) {
-                args.fPB->addPassThroughAttribute(gp.inColor(), args.fOutputColor);
-            }
+            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, gp.inColor(),
+                                        &fColorUniform);
 
             // Setup local coords if needed
             if (gp.inLocalCoords()) {
@@ -61,27 +93,57 @@ public:
                             gp.inPosition()->fName);
 
             // Setup coverage as pass through
-            GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder();
-            fs->codeAppendf("float alpha = 1.0;");
-            if (gp.inCoverage()) {
+            if (kUniform_GrGPInput == local.fInputCoverageType) {
+                const char* fragCoverage;
+                fCoverageUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                                  kFloat_GrSLType,
+                                                  kDefault_GrSLPrecision,
+                                                  "Coverage",
+                                                  &fragCoverage);
+                fs->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage);
+            } else if (kAttribute_GrGPInput == local.fInputCoverageType) {
+                SkASSERT(gp.inCoverage());
+                fs->codeAppendf("float alpha = 1.0;");
                 args.fPB->addPassThroughAttribute(gp.inCoverage(), "alpha");
+                fs->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
+            } else if (kAllOnes_GrGPInput == local.fInputCoverageType) {
+                fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
             }
-            fs->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
         }
 
         static inline void GenKey(const GrGeometryProcessor& gp,
-                                  const GrBatchTracker&,
+                                  const GrBatchTracker& bt,
                                   const GrGLCaps&,
                                   GrProcessorKeyBuilder* b) {
             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
             b->add32(def.fFlags);
+
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            b->add32(local.fInputColorType | local.fInputCoverageType << 16);
         }
 
-        virtual void setData(const GrGLProgramDataManager&,
-                             const GrGeometryProcessor&,
-                             const GrBatchTracker&) SK_OVERRIDE {}
+        virtual void setData(const GrGLProgramDataManager& pdman,
+                             const GrPrimitiveProcessor& gp,
+                             const GrBatchTracker& bt) SK_OVERRIDE {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+                GrGLfloat c[4];
+                GrColorToRGBAFloat(local.fColor, c);
+                pdman.set4fv(fColorUniform, 1, c);
+                fColor = local.fColor;
+            }
+            if (kUniform_GrGPInput == local.fInputCoverageType && local.fCoverage != fCoverage) {
+                pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(local.fCoverage));
+                fCoverage = local.fCoverage;
+            }
+        }
 
     private:
+        GrColor fColor;
+        uint8_t fCoverage;
+        UniformHandle fColorUniform;
+        UniformHandle fCoverageUniform;
+
         typedef GrGLGeometryProcessor INHERITED;
     };
 
@@ -97,11 +159,12 @@ public:
 
 private:
     DefaultGeoProc(GrColor color, uint8_t coverage, uint32_t gpTypeFlags, bool opaqueVertexColors)
-        : INHERITED(color, opaqueVertexColors, coverage)
+        : INHERITED(color, opaqueVertexColors)
         , fInPosition(NULL)
         , fInColor(NULL)
         , fInLocalCoords(NULL)
         , fInCoverage(NULL)
+        , fCoverage(coverage)
         , fFlags(gpTypeFlags) {
         this->initClassID<DefaultGeoProc>();
         bool hasColor = SkToBool(gpTypeFlags & GrDefaultGeoProcFactory::kColor_GPType);
@@ -120,7 +183,6 @@ private:
         if (hasCoverage) {
             fInCoverage = &this->addVertexAttrib(GrAttribute("inCoverage",
                                                              kFloat_GrVertexAttribType));
-            this->setHasVertexCoverage();
         }
     }
 
@@ -138,10 +200,18 @@ private:
         }
     }
 
+    struct BatchTracker {
+        GrGPInput fInputColorType;
+        GrGPInput fInputCoverageType;
+        GrColor  fColor;
+        GrColor  fCoverage;
+    };
+
     const GrAttribute* fInPosition;
     const GrAttribute* fInColor;
     const GrAttribute* fInLocalCoords;
     const GrAttribute* fInCoverage;
+    uint8_t fCoverage;
     uint32_t fFlags;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp
new file mode 100644 (file)
index 0000000..5d9cdaf
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGeometryProcessor.h"
+
+#include "gl/GrGLGeometryProcessor.h"
+#include "GrInvariantOutput.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GrGeometryProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
+    if (fHasVertexColor) {
+        if (fOpaqueVertexColors) {
+            out->setUnknownOpaqueFourComponents();
+        } else {
+            out->setUnknownFourComponents();
+        }
+    } else {
+        out->setKnownFourComponents(fColor);
+    }
+    this->onGetInvariantOutputColor(out);
+}
+
+void GrGeometryProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
+    this->onGetInvariantOutputCoverage(out);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "gl/builders/GrGLProgramBuilder.h"
+
+void GrGLGeometryProcessor::setupColorPassThrough(GrGLGPBuilder* pb,
+                                                  GrGPInput inputType,
+                                                  const char* outputName,
+                                                  const GrGeometryProcessor::GrAttribute* colorAttr,
+                                                  UniformHandle* colorUniform) {
+    GrGLGPFragmentBuilder* fs = pb->getFragmentShaderBuilder();
+    if (kUniform_GrGPInput == inputType) {
+        SkASSERT(colorUniform);
+        const char* stagedLocalVarName;
+        *colorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                       kVec4f_GrSLType,
+                                       kDefault_GrSLPrecision,
+                                       "Color",
+                                       &stagedLocalVarName);
+        fs->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
+    } else if (kAttribute_GrGPInput == inputType) {
+        SkASSERT(colorAttr);
+        pb->addPassThroughAttribute(colorAttr, outputName);
+    } else if (kAllOnes_GrGPInput == inputType) {
+        fs->codeAppendf("%s = vec4(1);", outputName);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct PathBatchTracker {
+    GrGPInput fInputColorType;
+    GrGPInput fInputCoverageType;
+    GrColor fColor;
+};
+
+class GrGLPathProcessor : public GrGLGeometryProcessor {
+public:
+    GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&)
+        : fColor(GrColor_ILLEGAL) {}
+
+    void emitCode(const EmitArgs& args) SK_OVERRIDE {
+        GrGLGPBuilder* pb = args.fPB;
+        GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder();
+        const PathBatchTracker& local = args.fBT.cast<PathBatchTracker>();
+
+        // Setup uniform color
+        if (kUniform_GrGPInput == local.fInputColorType) {
+            const char* stagedLocalVarName;
+            fColorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                           kVec4f_GrSLType,
+                                           kDefault_GrSLPrecision,
+                                           "Color",
+                                           &stagedLocalVarName);
+            fs->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName);
+        }
+
+        // setup constant solid coverage
+        if (kAllOnes_GrGPInput == local.fInputCoverageType) {
+            fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
+        }
+    }
+
+    static inline void GenKey(const GrPathProcessor&,
+                              const GrBatchTracker& bt,
+                              const GrGLCaps&,
+                              GrProcessorKeyBuilder* b) {
+        const PathBatchTracker& local = bt.cast<PathBatchTracker>();
+        b->add32(local.fInputColorType | local.fInputCoverageType << 16);
+    }
+
+    void setData(const GrGLProgramDataManager& pdman,
+                 const GrPrimitiveProcessor& primProc,
+                 const GrBatchTracker& bt) SK_OVERRIDE {
+        const PathBatchTracker& local = bt.cast<PathBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
+    }
+
+private:
+    UniformHandle fColorUniform;
+    GrColor fColor;
+
+    typedef GrGLGeometryProcessor INHERITED;
+};
+
+GrPathProcessor::GrPathProcessor(GrColor color) : fColor(color) {
+    this->initClassID<GrPathProcessor>();
+}
+
+void GrPathProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
+    out->setKnownFourComponents(fColor);
+}
+
+void GrPathProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
+    out->setKnownSingleComponent(0xff);
+}
+
+void GrPathProcessor::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    PathBatchTracker* local = bt->cast<PathBatchTracker>();
+    if (init.fColorIgnored) {
+        local->fInputColorType = kIgnored_GrGPInput;
+        local->fColor = GrColor_ILLEGAL;
+    } else {
+        local->fInputColorType = kUniform_GrGPInput;
+        local->fColor = GrColor_ILLEGAL == init.fOverrideColor ? this->color() :
+                                                                 init.fOverrideColor;
+    }
+
+    local->fInputCoverageType = init.fCoverageIgnored ? kIgnored_GrGPInput : kAllOnes_GrGPInput;
+}
+
+bool GrPathProcessor::canMakeEqual(const GrBatchTracker& m,
+                                   const GrPrimitiveProcessor& that,
+                                   const GrBatchTracker& t) const {
+    if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
+        return false;
+    }
+
+    const PathBatchTracker& mine = m.cast<PathBatchTracker>();
+    const PathBatchTracker& theirs = t.cast<PathBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor) &&
+           CanCombineOutput(mine.fInputCoverageType, 0xff,
+                            theirs.fInputCoverageType, 0xff);
+}
+
+void GrPathProcessor::getGLProcessorKey(const GrBatchTracker& bt,
+                                        const GrGLCaps& caps,
+                                        GrProcessorKeyBuilder* b) const {
+    GrGLPathProcessor::GenKey(*this, bt, caps, b);
+}
+
+GrGLGeometryProcessor* GrPathProcessor::createGLInstance(const GrBatchTracker& bt) const {
+    return SkNEW_ARGS(GrGLPathProcessor, (*this, bt));
+}
index 7481515..f3ae800 100644 (file)
 #include "GrShaderVar.h"
 
 /*
+ * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape
+ * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is
+ * responsible for providing a color and coverage input into the Ganesh rendering pipeline.  Through
+ * optimization, Ganesh may decide a different color, no color, and / or no coverage are required
+ * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this
+ * functionality.  We also use the GrPrimitiveProcessor to make batching decisions.
+ *
+ * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
+ * GrPrimitiveProcessor.  These loops run on the CPU and compute any invariant components which
+ * might be useful for correctness / optimization decisions.  The GrPrimitiveProcessor seeds these
+ * loops, one with initial color and one with initial coverage, in its
+ * onComputeInvariantColor / Coverage calls.  These seed values are processed by the subsequent
+ * stages of the rendering pipeline and the output is then fed back into the GrPrimitiveProcessor in
+ * the initBatchTracker call, where the GrPrimitiveProcessor can then initialize the GrBatchTracker
+ * struct with the appropriate values.
+ *
+ * We are evolving this system to move towards generating geometric meshes and their associated
+ * vertex data after we have batched and reordered draws.  This system, known as 'deferred geometry'
+ * will allow the GrPrimitiveProcessor much greater control over how data is transmitted to shaders.
+ *
+ * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch'  To do this, each
+ * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how
+ * it draws.  Each primitive draw will bundle all required data to perform the draw, and these
+ * bundles of data will be owned by an instance of the associated GrPrimitiveProcessor.  Bundles
+ * can be updated alongside the GrBatchTracker struct itself, ultimately allowing the
+ * GrPrimitiveProcessor complete control of how it gets data into the fragment shader as long as
+ * it emits the appropriate color, or none at all, as directed.
+ */
+
+/*
  * A struct for tracking batching decisions.  While this lives on GrOptState, it is managed
  * entirely by the derived classes of the GP.
  */
@@ -21,18 +51,18 @@ class GrBatchTracker {
 public:
     template <typename T> const T& cast() const {
         SkASSERT(sizeof(T) <= kMaxSize);
-        return *reinterpret_cast<const T*>(fData);
+        return *reinterpret_cast<const T*>(fData.get());
     }
 
     template <typename T> T* cast() {
         SkASSERT(sizeof(T) <= kMaxSize);
-        return reinterpret_cast<T*>(fData);
+        return reinterpret_cast<T*>(fData.get());
     }
 
     static const size_t kMaxSize = 32;
 
 private:
-    uint8_t fData[kMaxSize];
+    SkAlignedSStorage<kMaxSize> fData;
 };
 
 class GrGLCaps;
@@ -41,58 +71,105 @@ class GrOptDrawState;
 
 struct GrInitInvariantOutput;
 
+
+/*
+ * This enum is shared by GrPrimitiveProcessors and GrGLPrimitiveProcessors to coordinate shaders
+ * with vertex attributes / uniforms.
+ */
+enum GrGPInput {
+    kAllOnes_GrGPInput,
+    kAttribute_GrGPInput,
+    kUniform_GrGPInput,
+    kIgnored_GrGPInput,
+};
+
 /*
- * GrGeometryProcessors and GrPathProcessors may effect invariantColor
+ * GrPrimitiveProcessor defines an interface which all subclasses must implement.  All
+ * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
+ * pipelines, and they must provide some notion of equality
  */
 class GrPrimitiveProcessor : public GrProcessor {
 public:
-    // TODO GPs and PPs have to provide an initial coverage because the coverage invariant code is
-    // broken right now
-    virtual uint8_t coverage() const = 0;
+    /*
+     * This struct allows the optstate to communicate requirements to the GrPrimitiveProcessor.
+     */
+    struct InitBT {
+        bool fColorIgnored;
+        bool fCoverageIgnored;
+        GrColor fOverrideColor;
+    };
+
+    virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const = 0;
+
+    virtual bool canMakeEqual(const GrBatchTracker& mine,
+                              const GrPrimitiveProcessor& that,
+                              const GrBatchTracker& theirs) const = 0;
+
+    /*
+     * We always call canMakeEqual before makeEqual so there is no need to do any kind of equality
+     * testing here
+     * TODO make this pure virtual when primProcs can actually use it
+     */
+    virtual void makeEqual(GrBatchTracker*, const GrBatchTracker&) const {}
+
     virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
     virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
 
+    /**
+     * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
+     * processor's GL backend implementation.
+     */
+    virtual void getGLProcessorKey(const GrBatchTracker& bt,
+                                   const GrGLCaps& caps,
+                                   GrProcessorKeyBuilder* b) const = 0;
+
+
+    /** Returns a new instance of the appropriate *GL* implementation class
+        for the given GrProcessor; caller is responsible for deleting
+        the object. */
+    virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const = 0;
+
+protected:
+    /*
+     * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
+     * TODO remove this when GPs can upgrade to attribute color
+     */
+    static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
+        if (left != right) {
+            return false;
+        }
+
+        if (kUniform_GrGPInput == left && lColor != rColor) {
+            return false;
+        }
+
+        return true;
+    }
+
 private:
     typedef GrProcessor INHERITED;
 };
 
 /**
- * A GrGeometryProcessor is used to perform computation in the vertex shader and
- * add support for custom vertex attributes. A GrGemeotryProcessor is typically
- * tied to the code that does a specific type of high-level primitive rendering
- * (e.g. anti-aliased circle rendering). The GrGeometryProcessor used for a draw is
- * specified using GrDrawState. There can only be one geometry processor active for
- * a draw. The custom vertex attributes required by the geometry processor must be
- * added to the vertex attribute array specified on the GrDrawState.
- * GrGeometryProcessor subclasses should be immutable after construction.
+ * A GrGeometryProcessor is a flexible method for rendering a primitive.  The GrGeometryProcessor
+ * has complete control over vertex attributes and uniforms(aside from the render target) but it
+ * must obey the same contract as any GrPrimitiveProcessor, specifically it must emit a color and
+ * coverage into the fragment shader.  Where this color and coverage come from is completely the
+ * responsibility of the GrGeometryProcessor.
  */
 class GrGeometryProcessor : public GrPrimitiveProcessor {
 public:
     // TODO the Hint can be handled in a much more clean way when we have deferred geometry or
     // atleast bundles
-    GrGeometryProcessor(GrColor color, bool opaqueVertexColors = false, uint8_t coverage = 0xff)
+    GrGeometryProcessor(GrColor color, bool opaqueVertexColors = false)
         : fVertexStride(0)
         , fColor(color)
-        , fCoverage(coverage)
         , fOpaqueVertexColors(opaqueVertexColors)
         , fWillUseGeoShader(false)
         , fHasVertexColor(false)
-        , fHasVertexCoverage(false)
         , fHasLocalCoords(false) {}
 
-    /**
-     * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
-     * processor's GL backend implementation.
-     */
-    virtual void getGLProcessorKey(const GrBatchTracker& bt,
-                                   const GrGLCaps& caps,
-                                   GrProcessorKeyBuilder* b) const = 0;
-
-
-    /** Returns a new instance of the appropriate *GL* implementation class
-        for the given GrProcessor; caller is responsible for deleting
-        the object. */
-    virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const = 0;
+    virtual const char* name() const = 0;
 
     /*
      * This is a safeguard to prevent GPs from going beyond platform specific attribute limits.
@@ -121,61 +198,87 @@ public:
 
     bool willUseGeoShader() const { return fWillUseGeoShader; }
 
-    /** Returns true if this and other processor conservatively draw identically. It can only return
-        true when the two prcoessors are of the same subclass (i.e. they return the same object from
-        from getFactory()).
-        A return value of true from isEqual() should not be used to test whether the processors
-        would generate the same shader code. To test for identical code generation use the
-        processors' keys computed by the GrBackendEffectFactory. */
-    bool isEqual(const GrGeometryProcessor& that) const {
+    /*
+     * In an ideal world, two GrGeometryProcessors with the same class id and texture accesses
+     * would ALWAYS be able to batch together.  If two GrGeometryProcesosrs are the same then we
+     * will only keep one of them.  The remaining GrGeometryProcessor then updates its
+     * GrBatchTracker to incorporate the draw information from the GrGeometryProcessor we discard.
+     * Any bundles associated with the discarded GrGeometryProcessor will be attached to the
+     * remaining GrGeometryProcessor.
+     */
+    bool canMakeEqual(const GrBatchTracker& mine,
+                      const GrPrimitiveProcessor& that,
+                      const GrBatchTracker& theirs) const SK_OVERRIDE {
         if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
             return false;
         }
 
         // TODO remove the hint
-        if (fHasVertexColor && fOpaqueVertexColors != that.fOpaqueVertexColors) {
+        const GrGeometryProcessor& other = that.cast<GrGeometryProcessor>();
+        if (fHasVertexColor && fOpaqueVertexColors != other.fOpaqueVertexColors) {
             return false;
         }
 
-        if (!fHasVertexColor && this->color() != that.color()) {
+        // TODO this equality test should really be broken up, some of this can live on the batch
+        // tracker test and some of this should be in bundles
+        if (!this->onIsEqual(other)) {
             return false;
         }
 
-        // TODO this is fragile, most gps set their coverage to 0xff so this is okay.  In the long
-        // term this should move to subclasses which set explicit coverage
-        if (!fHasVertexCoverage && this->coverage() != that.coverage()) {
-            return false;
-        }
-        return this->onIsEqual(that);
+        return this->onCanMakeEqual(mine, theirs);
     }
 
-    struct InitBT {
-        bool fOutputColor;
-        bool fOutputCoverage;
-        GrColor fColor;
-        GrColor fCoverage;
-    };
-
-    virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const {}
-
+    
+    // TODO we can remove color from the GrGeometryProcessor base class once we have bundles of
+    // primitive data
     GrColor color() const { return fColor; }
-    uint8_t coverage() const SK_OVERRIDE { return fCoverage; }
 
-    // TODO this is a total hack until the gp can own whether or not it uses uniform
-    // color / coverage
+    // TODO this is a total hack until the gp can do deferred geometry
     bool hasVertexColor() const { return fHasVertexColor; }
-    bool hasVertexCoverage() const { return fHasVertexCoverage; }
+
+    // TODO this is a total hack until gp can setup and manage local coords
     bool hasLocalCoords() const { return fHasLocalCoords; }
 
     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
 
 protected:
+    /*
+     * An optional simple helper function to determine by what means the GrGeometryProcessor should
+     * use to provide color.  If we are given an override color(ie the given overridecolor is NOT
+     * GrColor_ILLEGAL) then we must always emit that color(currently overrides are only supported
+     * via uniform, but with deferred Geometry we could use attributes).  Otherwise, if our color is
+     * ignored then we should not emit a color.  Lastly, if we don't have vertex colors then we must
+     * emit a color via uniform
+     * TODO this function changes quite a bit with deferred geometry.  There the GrGeometryProcessor
+     * can upload a new color via attribute if needed.
+     */
+    static GrGPInput GetColorInputType(GrColor* color, GrColor primitiveColor, const InitBT& init,
+                                       bool hasVertexColor) {
+        if (init.fColorIgnored) {
+            *color = GrColor_ILLEGAL;
+            return kIgnored_GrGPInput;
+        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
+            *color = init.fOverrideColor;
+            return kUniform_GrGPInput;
+        }
+
+        *color = primitiveColor;
+        if (hasVertexColor) {
+            return kAttribute_GrGPInput;
+        } else {
+            return kUniform_GrGPInput;
+        }
+    }
+
     /**
      * Subclasses call this from their constructor to register vertex attributes.  Attributes
      * will be padded to the nearest 4 bytes for performance reasons.
      * TODO After deferred geometry, we should do all of this inline in GenerateGeometry alongside
-     * the struct used to actually populate the attributes
+     * the struct used to actually populate the attributes.  This is all extremely fragile, vertex
+     * attributes have to be added in the order they will appear in the struct which maps memory.
+     * The processor key should reflect the vertex attributes, or there lack thereof in the
+     * GrGeometryProcessor.
      */
     const GrAttribute& addVertexAttrib(const GrAttribute& attribute) {
         fVertexStride += attribute.fOffset;
@@ -186,23 +289,22 @@ protected:
 
     // TODO hack see above
     void setHasVertexColor() { fHasVertexColor = true; }
-    void setHasVertexCoverage() { fHasVertexCoverage = true; }
     void setHasLocalCoords() { fHasLocalCoords = true; }
 
     virtual void onGetInvariantOutputColor(GrInitInvariantOutput*) const {}
     virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const = 0;
 
 private:
+    virtual bool onCanMakeEqual(const GrBatchTracker& mine, const GrBatchTracker& theirs) const = 0;
+    // TODO delete this when we have more advanced equality testing via bundles and the BT
     virtual bool onIsEqual(const GrGeometryProcessor&) const = 0;
 
     SkSTArray<kMaxVertexAttribs, GrAttribute, true> fAttribs;
     size_t fVertexStride;
     GrColor fColor;
-    uint8_t fCoverage;
     bool fOpaqueVertexColors;
     bool fWillUseGeoShader;
     bool fHasVertexColor;
-    bool fHasVertexCoverage;
     bool fHasLocalCoords;
 
     typedef GrProcessor INHERITED;
@@ -217,14 +319,28 @@ public:
     static GrPathProcessor* Create(GrColor color) {
         return SkNEW_ARGS(GrPathProcessor, (color));
     }
+    
+    void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
+
+    bool canMakeEqual(const GrBatchTracker& mine,
+                      const GrPrimitiveProcessor& that,
+                      const GrBatchTracker& theirs) const SK_OVERRIDE;
 
     const char* name() const SK_OVERRIDE { return "PathProcessor"; }
-    uint8_t coverage() const SK_OVERRIDE { return 0xff; }
+
+    GrColor color() const { return fColor; }
+
     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
 
+    virtual void getGLProcessorKey(const GrBatchTracker& bt,
+                                   const GrGLCaps& caps,
+                                   GrProcessorKeyBuilder* b) const SK_OVERRIDE;
+
+    virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
+
 private:
-    GrPathProcessor(GrColor color) : fColor(color) {}
+    GrPathProcessor(GrColor color);
     GrColor fColor;
 
     typedef GrProcessor INHERITED;
index 62d6818..83e0926 100644 (file)
@@ -502,7 +502,7 @@ bool GrInOrderDrawBuffer::recordStateAndShouldDraw(const GrDrawState& ds,
         fCmdBuffer.pop_back();
         return false;
     }
-    if (fPrevState && *fPrevState == ss->fState) {
+    if (fPrevState && fPrevState->combineIfPossible(ss->fState)) {
         fCmdBuffer.pop_back();
     } else {
         fPrevState = &ss->fState;
index 060e42e..e2916dd 100644 (file)
@@ -260,7 +260,7 @@ private:
     };
 
     CmdBuffer                           fCmdBuffer;
-    const GrOptDrawState*               fPrevState;
+    GrOptDrawState*                     fPrevState;
     SkTArray<GrTraceMarkerSet, false>   fGpuCmdMarkers;
     SkTDArray<char>                     fPathIndexBuffer;
     SkTDArray<float>                    fPathTransformBuffer;
index 93184b4..b5fe8d5 100644 (file)
@@ -32,23 +32,23 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
         fPrimitiveProcessor.reset(gp);
     } else {
         SkASSERT(!gp && pathProc && (GrGpu::IsPathRenderingDrawType(drawType) ||
-                               GrGpu::kStencilPath_DrawType == drawType));
+                 GrGpu::kStencilPath_DrawType == drawType));
         fPrimitiveProcessor.reset(pathProc);
     }
 
 
     const GrProcOptInfo& colorPOI = drawState.colorProcInfo(fPrimitiveProcessor);
     const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(fPrimitiveProcessor);
-    
-    fColor = colorPOI.inputColorToEffectiveStage();
-    // TODO fix this when coverage stages work correctly
-    // fCoverage = coveragePOI.inputColorToEffectiveStage();
-    fCoverage = fPrimitiveProcessor->coverage();
 
     // Create XferProcessor from DS's XPFactory
     SkAutoTUnref<GrXferProcessor> xferProcessor(
         drawState.getXPFactory()->createXferProcessor(colorPOI, coveragePOI));
 
+    GrColor overrideColor = GrColor_ILLEGAL;
+    if (colorPOI.firstEffectiveStageIndex() != 0) {
+        overrideColor = colorPOI.inputColorToEffectiveStage();
+    }
+
     GrXferProcessor::OptFlags optFlags;
     if (xferProcessor) {
         fXferProcessor.reset(xferProcessor.get());
@@ -58,8 +58,7 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
                                                    drawState.isCoverageDrawing(),
                                                    drawState.isColorWriteDisabled(),
                                                    drawState.getStencil().doesWrite(),
-                                                   &fColor,
-                                                   &fCoverage,
+                                                   &overrideColor,
                                                    caps);
     }
 
@@ -98,22 +97,14 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
         fFlags |= kDither_Flag;
     }
 
-    fDescInfo.fHasVertexColor = gp && gp->hasVertexColor();
-
-    fDescInfo.fHasVertexCoverage = gp && gp->hasVertexCoverage();
-
+    // TODO move local coords completely into GP
     bool hasLocalCoords = gp && gp->hasLocalCoords();
 
     int firstColorStageIdx = colorPOI.firstEffectiveStageIndex();
-    fDescInfo.fInputColorIsUsed = colorPOI.inputColorIsUsed();
-    if (colorPOI.removeVertexAttrib()) {
-        fDescInfo.fHasVertexColor = false;
-    }
 
     // TODO: Once we can handle single or four channel input into coverage stages then we can use
     // drawState's coverageProcInfo (like color above) to set this initial information.
     int firstCoverageStageIdx = 0;
-    fDescInfo.fInputCoverageIsUsed = true;
 
     GrXferProcessor::BlendInfo blendInfo;
     fXferProcessor->getBlendInfo(&blendInfo);
@@ -138,14 +129,11 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
     }
 
     // let the GP init the batch tracker
-    if (gp) {
-        GrGeometryProcessor::InitBT init;
-        init.fOutputColor = fDescInfo.fInputColorIsUsed;
-        init.fOutputCoverage = fDescInfo.fInputCoverageIsUsed;
-        init.fColor = this->getColor();
-        init.fCoverage = this->getCoverage();
-        fGeometryProcessor->initBatchTracker(&fBatchTracker, init);
-    }
+    GrGeometryProcessor::InitBT init;
+    init.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag);
+    init.fOverrideColor = init.fColorIgnored ? GrColor_ILLEGAL : overrideColor;
+    init.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag);
+    fPrimitiveProcessor->initBatchTracker(&fBatchTracker, init);
 }
 
 void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds,
@@ -157,20 +145,16 @@ void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds,
     fDescInfo.fReadsDst = false;
     fDescInfo.fReadsFragPosition = false;
 
-    if (flags & GrXferProcessor::kClearColorStages_OptFlag ||
-        flags & GrXferProcessor::kOverrideColor_OptFlag) {
-        fDescInfo.fInputColorIsUsed = true;
+    if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
+        (flags & GrXferProcessor::kOverrideColor_OptFlag)) {
         *firstColorStageIdx = ds.numColorStages();
-        fDescInfo.fHasVertexColor = false;
     } else {
         fDescInfo.fReadsDst = colorPOI.readsDst();
         fDescInfo.fReadsFragPosition = colorPOI.readsFragPosition();
     }
 
-    if (flags & GrXferProcessor::kClearCoverageStages_OptFlag) {
-        fDescInfo.fInputCoverageIsUsed = true;
+    if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) {
         *firstCoverageStageIdx = ds.numCoverageStages();
-        fDescInfo.fHasVertexCoverage = false;
     } else {
         if (coveragePOI.readsDst()) {
             fDescInfo.fReadsDst = true;
@@ -188,15 +172,11 @@ void GrOptDrawState::finalize(GrGpu* gpu) {
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
+bool GrOptDrawState::combineIfPossible(const GrOptDrawState& that) {
     if (fDescInfo != that.fDescInfo) {
         return false;
     }
 
-    if (!fDescInfo.fHasVertexColor && this->fColor != that.fColor) {
-        return false;
-    }
-
     if (this->getRenderTarget() != that.getRenderTarget() ||
         this->fFragmentStages.count() != that.fFragmentStages.count() ||
         this->fNumColorStages != that.fNumColorStages ||
@@ -210,17 +190,9 @@ bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
         return false;
     }
 
-    if (!fDescInfo.fHasVertexCoverage && this->fCoverage != that.fCoverage) {
-        return false;
-    }
-
-    if (this->hasGeometryProcessor()) {
-        if (!that.hasGeometryProcessor()) {
-            return false;
-        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
-            return false;
-        }
-    } else if (that.hasGeometryProcessor()) {
+    if (!this->getPrimitiveProcessor()->canMakeEqual(fBatchTracker,
+                                                     *that.getPrimitiveProcessor(),
+                                                     that.getBatchTracker())) {
         return false;
     }
 
@@ -236,6 +208,9 @@ bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
             return false;
         }
     }
+
+    // Now update the GrPrimitiveProcessor's batch tracker
+    fPrimitiveProcessor->makeEqual(&fBatchTracker, that.getBatchTracker());
     return true;
 }
 
index 876ff52..95f7fa9 100644 (file)
@@ -35,28 +35,11 @@ public:
                    const GrDrawTargetCaps&, const ScissorState&,
                    const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType);
 
-    bool operator== (const GrOptDrawState& that) const;
-    bool operator!= (const GrOptDrawState& that) const { return !(*this == that); }
-
-    /// @}
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Color
-    ////
-
-    GrColor getColor() const { return fColor; }
-
-    /// @}
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Coverage
-    ////
-
-    uint8_t getCoverage() const { return fCoverage; }
-
-    GrColor getCoverageColor() const {
-        return GrColorPackRGBA(fCoverage, fCoverage, fCoverage, fCoverage);
-    }
+    /*
+     * Returns true if it is possible to combine the two GrOptDrawStates and it will update 'this'
+     * to subsume 'that''s draw.
+     */
+    bool combineIfPossible(const GrOptDrawState& that);
 
     /// @}
 
@@ -80,13 +63,11 @@ public:
     int numColorStages() const { return fNumColorStages; }
     int numCoverageStages() const { return fFragmentStages.count() - fNumColorStages; }
     int numFragmentStages() const { return fFragmentStages.count(); }
-    int numTotalStages() const {
-        // the + 1 at the end is for the xferProcessor which will always be present
-        return this->numFragmentStages() + (this->hasGeometryProcessor() ? 1 : 0) + 1;
-    }
 
+    // TODO remove the GP specific calls when the PathProc can provide the same interface
     bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); }
     const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); }
+    const GrPrimitiveProcessor* getPrimitiveProcessor() const { return fPrimitiveProcessor.get(); }
     const GrBatchTracker& getBatchTracker() const { return fBatchTracker; }
 
     const GrXferProcessor* getXferProcessor() const { return fXferProcessor.get(); }
@@ -210,10 +191,8 @@ private:
     typedef GrPendingProgramElement<const GrXferProcessor> ProgramXferProcessor;
     RenderTarget                        fRenderTarget;
     ScissorState                        fScissorState;
-    GrColor                             fColor;
     SkMatrix                            fViewMatrix;
     GrStencilSettings                   fStencilSettings;
-    uint8_t                             fCoverage;
     GrDrawState::DrawFace               fDrawFace;
     GrDeviceCoordTexture                fDstCopy;
     uint32_t                            fFlags;
index e1a29f5..659857a 100644 (file)
@@ -80,16 +80,23 @@ public:
     class GLProcessor : public GrGLGeometryProcessor {
     public:
         GLProcessor(const GrGeometryProcessor&,
-                    const GrBatchTracker&) {}
+                    const GrBatchTracker&)
+            : fColor(GrColor_ILLEGAL) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
+            GrGLGPBuilder* pb = args.fPB;
+            const BatchTracker& local = args.fBT.cast<BatchTracker>();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
 
             GrGLVertToFrag v(kVec4f_GrSLType);
             args.fPB->addVarying("CircleEdge", &v);
             vsBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
 
+            // Setup pass through color
+            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
+                                        &fColorUniform);
+
             // setup coord outputs
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ce.inPosition()->fName);
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ce.inPosition()->fName);
@@ -111,18 +118,29 @@ public:
         }
 
         static void GenKey(const GrGeometryProcessor& processor,
-                           const GrBatchTracker&,
+                           const GrBatchTracker& bt,
                            const GrGLCaps&,
                            GrProcessorKeyBuilder* b) {
+            const BatchTracker& local = bt.cast<BatchTracker>();
             const CircleEdgeEffect& circleEffect = processor.cast<CircleEdgeEffect>();
-            b->add32(circleEffect.isStroked());
+            b->add32(circleEffect.isStroked() << 16 | local.fInputColorType);
         }
 
-        virtual void setData(const GrGLProgramDataManager&,
-                             const GrGeometryProcessor&,
-                             const GrBatchTracker&) SK_OVERRIDE {}
+        virtual void setData(const GrGLProgramDataManager& pdman,
+                             const GrPrimitiveProcessor& gp,
+                             const GrBatchTracker& bt) SK_OVERRIDE {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+                GrGLfloat c[4];
+                GrColorToRGBAFloat(local.fColor, c);
+                pdman.set4fv(fColorUniform, 1, c);
+                fColor = local.fColor;
+            }
+        }
 
     private:
+        GrColor fColor;
+        UniformHandle fColorUniform;
         typedef GrGLGeometryProcessor INHERITED;
     };
 
@@ -136,6 +154,19 @@ public:
         return SkNEW_ARGS(GLProcessor, (*this, bt));
     }
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE {
+        BatchTracker* local = bt->cast<BatchTracker>();
+        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+
+    }
+
+    bool onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const SK_OVERRIDE {
+        const BatchTracker& mine = m.cast<BatchTracker>();
+        const BatchTracker& theirs = t.cast<BatchTracker>();
+        return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                                theirs.fInputColorType, theirs.fColor);
+    }
+
 private:
     CircleEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
         this->initClassID<CircleEdgeEffect>();
@@ -154,6 +185,11 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    struct BatchTracker {
+        GrGPInput fInputColorType;
+        GrColor fColor;
+    };
+
     const GrAttribute* fInPosition;
     const GrAttribute* fInCircleEdge;
     bool fStroke;
@@ -201,11 +237,13 @@ public:
     class GLProcessor : public GrGLGeometryProcessor {
     public:
         GLProcessor(const GrGeometryProcessor&,
-                    const GrBatchTracker&) {}
+                    const GrBatchTracker&)
+            : fColor(GrColor_ILLEGAL) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
-
+            GrGLGPBuilder* pb = args.fPB;
+            const BatchTracker& local = args.fBT.cast<BatchTracker>();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
 
             GrGLVertToFrag ellipseOffsets(kVec2f_GrSLType);
@@ -218,6 +256,10 @@ public:
             vsBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
                                    ee.inEllipseRadii()->fName);
 
+            // Setup pass through color
+            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
+                                        &fColorUniform);
+
             // setup coord outputs
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ee.inPosition()->fName);
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ee.inPosition()->fName);
@@ -254,19 +296,30 @@ public:
         }
 
         static void GenKey(const GrGeometryProcessor& processor,
-                           const GrBatchTracker&,
+                           const GrBatchTracker& bt,
                            const GrGLCaps&,
                            GrProcessorKeyBuilder* b) {
+            const BatchTracker& local = bt.cast<BatchTracker>();
             const EllipseEdgeEffect& ellipseEffect = processor.cast<EllipseEdgeEffect>();
-            b->add32(ellipseEffect.isStroked());
+            b->add32(ellipseEffect.isStroked() << 16 | local.fInputColorType);
         }
 
-        virtual void setData(const GrGLProgramDataManager&,
-                             const GrGeometryProcessor&,
-                             const GrBatchTracker&) SK_OVERRIDE {
+        virtual void setData(const GrGLProgramDataManager& pdman,
+                             const GrPrimitiveProcessor& gp,
+                             const GrBatchTracker& bt) SK_OVERRIDE {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+                GrGLfloat c[4];
+                GrColorToRGBAFloat(local.fColor, c);
+                pdman.set4fv(fColorUniform, 1, c);
+                fColor = local.fColor;
+            }
         }
 
     private:
+        GrColor fColor;
+        UniformHandle fColorUniform;
+
         typedef GrGLGeometryProcessor INHERITED;
     };
 
@@ -280,6 +333,18 @@ public:
         return SkNEW_ARGS(GLProcessor, (*this, bt));
     }
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE {
+        BatchTracker* local = bt->cast<BatchTracker>();
+        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+    }
+
+    bool onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const SK_OVERRIDE {
+        const BatchTracker& mine = m.cast<BatchTracker>();
+        const BatchTracker& theirs = t.cast<BatchTracker>();
+        return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                                theirs.fInputColorType, theirs.fColor);
+    }
+
 private:
     EllipseEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
         this->initClassID<EllipseEdgeEffect>();
@@ -300,6 +365,11 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    struct BatchTracker {
+        GrGPInput fInputColorType;
+        GrColor fColor;
+    };
+
     const GrAttribute* fInPosition;
     const GrAttribute* fInEllipseOffset;
     const GrAttribute* fInEllipseRadii;
@@ -351,11 +421,13 @@ public:
     class GLProcessor : public GrGLGeometryProcessor {
     public:
         GLProcessor(const GrGeometryProcessor&,
-                    const GrBatchTracker&) {}
+                    const GrBatchTracker&)
+            : fColor(GrColor_ILLEGAL) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
-
+            GrGLGPBuilder* pb = args.fPB;
+            const BatchTracker& local = args.fBT.cast<BatchTracker>();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
 
             GrGLVertToFrag offsets0(kVec2f_GrSLType);
@@ -368,6 +440,10 @@ public:
             vsBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
                                    ee.inEllipseOffsets1()->fName);
 
+            // Setup pass through color
+            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
+                                        &fColorUniform);
+
             // setup coord outputs
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ee.inPosition()->fName);
             vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ee.inPosition()->fName);
@@ -418,20 +494,30 @@ public:
         }
 
         static void GenKey(const GrGeometryProcessor& processor,
-                           const GrBatchTracker&,
+                           const GrBatchTracker& bt,
                            const GrGLCaps&,
                            GrProcessorKeyBuilder* b) {
+            const BatchTracker& local = bt.cast<BatchTracker>();
             const DIEllipseEdgeEffect& ellipseEffect = processor.cast<DIEllipseEdgeEffect>();
-
-            b->add32(ellipseEffect.getMode());
+            b->add32(ellipseEffect.getMode() << 16 | local.fInputColorType);
         }
 
-        virtual void setData(const GrGLProgramDataManager&,
-                             const GrGeometryProcessor&,
-                             const GrBatchTracker&) SK_OVERRIDE {
+        virtual void setData(const GrGLProgramDataManager& pdman,
+                             const GrPrimitiveProcessor& gp,
+                             const GrBatchTracker& bt) SK_OVERRIDE {
+            const BatchTracker& local = bt.cast<BatchTracker>();
+            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+                GrGLfloat c[4];
+                GrColorToRGBAFloat(local.fColor, c);
+                pdman.set4fv(fColorUniform, 1, c);
+                fColor = local.fColor;
+            }
         }
 
     private:
+        GrColor fColor;
+        UniformHandle fColorUniform;
+
         typedef GrGLGeometryProcessor INHERITED;
     };
 
@@ -445,6 +531,18 @@ public:
         return SkNEW_ARGS(GLProcessor, (*this, bt));
     }
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE {
+        BatchTracker* local = bt->cast<BatchTracker>();
+        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+    }
+
+    bool onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const SK_OVERRIDE {
+        const BatchTracker& mine = m.cast<BatchTracker>();
+        const BatchTracker& theirs = t.cast<BatchTracker>();
+        return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                                theirs.fInputColorType, theirs.fColor);
+    }
+
 private:
     DIEllipseEdgeEffect(GrColor color, Mode mode) : INHERITED(color) {
         this->initClassID<DIEllipseEdgeEffect>();
@@ -465,6 +563,11 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    struct BatchTracker {
+        GrGPInput fInputColorType;
+        GrColor fColor;
+    };
+
     const GrAttribute* fInPosition;
     const GrAttribute* fInEllipseOffsets0;
     const GrAttribute* fInEllipseOffsets1;
index 4c119b5..6fad760 100644 (file)
@@ -48,7 +48,6 @@ void GrProcOptInfo::internalCalc(const GrFragmentStage* stages,
     fFirstEffectStageIndex = 0;
     fInputColorIsUsed = true;
     fInputColor = fInOut.color();
-    fRemoveVertexAttrib = false;
     fReadsDst = false;
     fReadsFragPosition = initWillReadFragmentPosition;
 
@@ -74,7 +73,6 @@ void GrProcOptInfo::internalCalc(const GrFragmentStage* stages,
             fFirstEffectStageIndex = i + 1;
             fInputColor = fInOut.color();
             fInputColorIsUsed = true;
-            fRemoveVertexAttrib = true;
             // Since we are clearing all previous color stages we are in a state where we have found
             // zero stages that don't multiply the inputColor.
             fInOut.resetNonMulStageFound();
index 30b286f..43d6c55 100644 (file)
@@ -28,7 +28,6 @@ public:
         , fFirstEffectStageIndex(0)
         , fInputColorIsUsed(true)
         , fInputColor(0)
-        , fRemoveVertexAttrib(false)
         , fReadsDst(false)
         , fReadsFragPosition(false) {}
 
@@ -76,12 +75,6 @@ public:
     GrColor inputColorToEffectiveStage() const { return fInputColor; }
 
     /**
-     * Given the set of optimizations determined by GrProcOptInfo, should the caller remove the
-     * color/coverage vertex attribute that was input to the first stage.
-     */
-    bool removeVertexAttrib() const { return fRemoveVertexAttrib; }
-
-    /**
      * Returns true if any of the stages preserved by GrProcOptInfo read the dst color.
      */
     bool readsDst() const { return fReadsDst; }
@@ -98,7 +91,6 @@ private:
     int fFirstEffectStageIndex;
     bool fInputColorIsUsed;
     GrColor fInputColor;
-    bool fRemoveVertexAttrib;
     bool fReadsDst;
     bool fReadsFragPosition;
 };
index 721859b..d2ad7a5 100644 (file)
@@ -171,35 +171,6 @@ void GrFragmentProcessor::computeInvariantOutput(GrInvariantOutput* inout) const
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-void GrGeometryProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
-    if (fHasVertexColor) {
-        if (fOpaqueVertexColors) {
-            out->setUnknownOpaqueFourComponents();
-        } else {
-            out->setUnknownFourComponents();
-        }
-    } else {
-        out->setKnownFourComponents(fColor);
-    }
-    this->onGetInvariantOutputColor(out);
-}
-
-void GrGeometryProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    this->onGetInvariantOutputCoverage(out);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void GrPathProcessor::getInvariantOutputColor(GrInitInvariantOutput* out) const {
-    out->setKnownFourComponents(fColor);
-}
-
-void GrPathProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
-    out->setKnownSingleComponent(0xff);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /*
  * GrGeometryData shares the same pool so it lives in this file too
  */
index 022bbc3..8e25527 100644 (file)
@@ -54,16 +54,6 @@ public:
         return memcmp(a.asKey(), b.asKey(), a.keyLength() & ~0x3) < 0;
     }
 
-
-    // Specifies where the initial color comes from before the stages are applied.
-    enum ColorInput {
-        kAllOnes_ColorInput,
-        kAttribute_ColorInput,
-        kUniform_ColorInput,
-
-        kColorInputCnt
-    };
-
     struct KeyHeader {
         uint8_t                     fDstReadKey;   // set by GrGLShaderBuilder if there
                                                    // are effects that must read the dst.
@@ -72,19 +62,10 @@ public:
                                                    // effects that read the fragment position.
                                                    // Otherwise, 0.
 
-        ColorInput                  fColorInput : 8;
-        ColorInput                  fCoverageInput : 8;
-
-        SkBool8                     fHasGeometryProcessor;
         int8_t                      fColorEffectCnt;
         int8_t                      fCoverageEffectCnt;
     };
 
-
-    bool hasGeometryProcessor() const {
-        return SkToBool(this->header().fHasGeometryProcessor);
-    }
-
     int numColorEffects() const {
         return this->header().fColorEffectCnt;
     }
@@ -101,31 +82,17 @@ public:
     // A struct to communicate descriptor information to the program descriptor builder
     struct DescInfo {
         bool operator==(const DescInfo& that) const {
-            return fHasVertexColor == that.fHasVertexColor &&
-                   fHasVertexCoverage == that.fHasVertexCoverage &&
-                   fInputColorIsUsed == that.fInputColorIsUsed &&
-                   fInputCoverageIsUsed == that.fInputCoverageIsUsed &&
-                   fReadsDst == that.fReadsDst &&
+            return fReadsDst == that.fReadsDst &&
                    fReadsFragPosition == that.fReadsFragPosition &&
                    fRequiresLocalCoordAttrib == that.fRequiresLocalCoordAttrib;
         }
         bool operator!=(const DescInfo& that) const { return !(*this == that); };
-        // TODO when GPs control uniform / attribute handling of color / coverage, then we can
-        // clean this up
-        bool            fHasVertexColor;
-        bool            fHasVertexCoverage;
-
-        // These flags are needed to protect the code from creating an unused uniform color/coverage
-        // which will cause shader compiler errors.
-        bool            fInputColorIsUsed;
-        bool            fInputCoverageIsUsed;
 
         // These flags give aggregated info on the processor stages that are used when building
         // programs.
         bool            fReadsDst;
         bool            fReadsFragPosition;
         bool            fRequiresLocalCoordAttrib;
-
     };
 
 private:
index 6f4f28a..be1fef7 100644 (file)
 #include "gl/GrGLGeometryProcessor.h"
 #include "gl/builders/GrGLProgramBuilder.h"
 
+struct ConicBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+    uint8_t fCoverageScale;
+};
+
 class GrGLConicEffect : public GrGLGeometryProcessor {
 public:
     GrGLConicEffect(const GrGeometryProcessor&,
@@ -24,30 +30,53 @@ public:
                               const GrGLCaps&,
                               GrProcessorKeyBuilder*);
 
-    virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
-                         const GrBatchTracker&) SK_OVERRIDE {}
+    virtual void setData(const GrGLProgramDataManager& pdman,
+                         const GrPrimitiveProcessor&,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
+        const ConicBatchTracker& local = bt.cast<ConicBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
+        if (0xff != local.fCoverageScale && fCoverageScale != local.fCoverageScale) {
+            pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(local.fCoverageScale));
+            fCoverageScale = local.fCoverageScale;
+        }
+    }
 
 private:
+    GrColor fColor;
+    uint8_t fCoverageScale;
     GrPrimitiveEdgeType fEdgeType;
+    UniformHandle fColorUniform;
+    UniformHandle fCoverageScaleUniform;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLConicEffect::GrGLConicEffect(const GrGeometryProcessor& processor,
-                                 const GrBatchTracker& bt) {
+                                 const GrBatchTracker& bt)
+    : fColor(GrColor_ILLEGAL), fCoverageScale(0xff) {
     const GrConicEffect& ce = processor.cast<GrConicEffect>();
     fEdgeType = ce.getEdgeType();
 }
 
 void GrGLConicEffect::emitCode(const EmitArgs& args) {
+    GrGLGPBuilder* pb = args.fPB;
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
     const GrConicEffect& gp = args.fGP.cast<GrConicEffect>();
+    const ConicBatchTracker& local = args.fBT.cast<ConicBatchTracker>();
 
     GrGLVertToFrag v(kVec4f_GrSLType);
     args.fPB->addVarying("ConicCoeffs", &v);
     vsBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs()->fName);
 
+    // Setup pass through color
+    this->setupColorPassThrough(args.fPB, local.fInputColorType, args.fOutputColor, NULL,
+                                &fColorUniform);
+
     // setup coord outputs
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), gp.inPosition()->fName);
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), gp.inPosition()->fName);
@@ -113,15 +142,28 @@ void GrGLConicEffect::emitCode(const EmitArgs& args) {
             SkFAIL("Shouldn't get here");
     }
 
-    fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
+    if (0xff != local.fCoverageScale) {
+        const char* coverageScale;
+        fCoverageScaleUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                          kFloat_GrSLType,
+                                          kDefault_GrSLPrecision,
+                                          "Coverage",
+                                          &coverageScale);
+        fsBuilder->codeAppendf("%s = vec4(%s * edgeAlpha);", args.fOutputCoverage, coverageScale);
+    } else {
+        fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
+    }
 }
 
 void GrGLConicEffect::GenKey(const GrGeometryProcessor& processor,
-                             const GrBatchTracker&,
+                             const GrBatchTracker& bt,
                              const GrGLCaps&,
                              GrProcessorKeyBuilder* b) {
     const GrConicEffect& ce = processor.cast<GrConicEffect>();
+    const ConicBatchTracker& local = bt.cast<ConicBatchTracker>();
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+    key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x0;
+    key |= 0xff != local.fCoverageScale ? 0x8 : 0x0;
     b->add32(key);
 }
 
@@ -140,7 +182,7 @@ GrGLGeometryProcessor* GrConicEffect::createGLInstance(const GrBatchTracker& bt)
 }
 
 GrConicEffect::GrConicEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
-    : INHERITED(color, falsecoverage), fEdgeType(edgeType) {
+    : INHERITED(color, false), fCoverageScale(coverage), fEdgeType(edgeType) {
     this->initClassID<GrConicEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInConicCoeffs = &this->addVertexAttrib(GrAttribute("inConicCoeffs",
@@ -152,6 +194,20 @@ bool GrConicEffect::onIsEqual(const GrGeometryProcessor& other) const {
     return (ce.fEdgeType == fEdgeType);
 }
 
+void GrConicEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    ConicBatchTracker* local = bt->cast<ConicBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+    local->fCoverageScale = fCoverageScale;
+}
+
+bool GrConicEffect::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const ConicBatchTracker& mine = m.cast<ConicBatchTracker>();
+    const ConicBatchTracker& theirs = t.cast<ConicBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor) &&
+           mine.fCoverageScale == theirs.fCoverageScale;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect);
@@ -173,6 +229,12 @@ GrGeometryProcessor* GrConicEffect::TestCreate(SkRandom* random,
 // Quad
 //////////////////////////////////////////////////////////////////////////////
 
+struct QuadBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+    uint8_t fCoverageScale;
+};
+
 class GrGLQuadEffect : public GrGLGeometryProcessor {
 public:
     GrGLQuadEffect(const GrGeometryProcessor&,
@@ -185,30 +247,53 @@ public:
                               const GrGLCaps&,
                               GrProcessorKeyBuilder*);
 
-    virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
-                         const GrBatchTracker&) SK_OVERRIDE {}
+    virtual void setData(const GrGLProgramDataManager& pdman,
+                         const GrPrimitiveProcessor&,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
+        const QuadBatchTracker& local = bt.cast<QuadBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
+        if (0xff != local.fCoverageScale && local.fCoverageScale != fCoverageScale) {
+            pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(local.fCoverageScale));
+            fCoverageScale = local.fCoverageScale;
+        }
+    }
 
 private:
+    GrColor fColor;
+    uint8_t fCoverageScale;
     GrPrimitiveEdgeType fEdgeType;
+    UniformHandle fColorUniform;
+    UniformHandle fCoverageScaleUniform;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLQuadEffect::GrGLQuadEffect(const GrGeometryProcessor& processor,
-                               const GrBatchTracker& bt) {
+                               const GrBatchTracker& bt)
+    : fColor(GrColor_ILLEGAL), fCoverageScale(0xff) {
     const GrQuadEffect& ce = processor.cast<GrQuadEffect>();
     fEdgeType = ce.getEdgeType();
 }
 
 void GrGLQuadEffect::emitCode(const EmitArgs& args) {
+    GrGLGPBuilder* pb = args.fPB;
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
     const GrQuadEffect& gp = args.fGP.cast<GrQuadEffect>();
+    const QuadBatchTracker& local = args.fBT.cast<QuadBatchTracker>();
 
     GrGLVertToFrag v(kVec4f_GrSLType);
     args.fPB->addVarying("HairQuadEdge", &v);
     vsBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge()->fName);
 
+    // Setup pass through color
+    this->setupColorPassThrough(args.fPB, local.fInputColorType, args.fOutputColor, NULL,
+                                &fColorUniform);
+
     // setup coord outputs
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), gp.inPosition()->fName);
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), gp.inPosition()->fName);
@@ -260,15 +345,28 @@ void GrGLQuadEffect::emitCode(const EmitArgs& args) {
             SkFAIL("Shouldn't get here");
     }
 
-    fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
+    if (0xff != local.fCoverageScale) {
+        const char* coverageScale;
+        fCoverageScaleUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                          kFloat_GrSLType,
+                                          kDefault_GrSLPrecision,
+                                          "Coverage",
+                                          &coverageScale);
+        fsBuilder->codeAppendf("%s = vec4(%s * edgeAlpha);", args.fOutputCoverage, coverageScale);
+    } else {
+        fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
+    }
 }
 
 void GrGLQuadEffect::GenKey(const GrGeometryProcessor& processor,
-                            const GrBatchTracker&,
+                            const GrBatchTracker& bt,
                             const GrGLCaps&,
                             GrProcessorKeyBuilder* b) {
     const GrQuadEffect& ce = processor.cast<GrQuadEffect>();
+    const QuadBatchTracker& local = bt.cast<QuadBatchTracker>();
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+    key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x0;
+    key |= 0xff != local.fCoverageScale ? 0x8 : 0x0;
     b->add32(key);
 }
 
@@ -287,7 +385,7 @@ GrGLGeometryProcessor* GrQuadEffect::createGLInstance(const GrBatchTracker& bt)
 }
 
 GrQuadEffect::GrQuadEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
-    : INHERITED(color, falsecoverage), fEdgeType(edgeType) {
+    : INHERITED(color, false), fCoverageScale(coverage), fEdgeType(edgeType) {
     this->initClassID<GrQuadEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInHairQuadEdge = &this->addVertexAttrib(GrAttribute("inHairQuadEdge",
@@ -299,6 +397,20 @@ bool GrQuadEffect::onIsEqual(const GrGeometryProcessor& other) const {
     return (ce.fEdgeType == fEdgeType);
 }
 
+void GrQuadEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    QuadBatchTracker* local = bt->cast<QuadBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+    local->fCoverageScale = fCoverageScale;
+}
+
+bool GrQuadEffect::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const QuadBatchTracker& mine = m.cast<QuadBatchTracker>();
+    const QuadBatchTracker& theirs = t.cast<QuadBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor) &&
+           mine.fCoverageScale == theirs.fCoverageScale;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect);
@@ -320,6 +432,11 @@ GrGeometryProcessor* GrQuadEffect::TestCreate(SkRandom* random,
 // Cubic
 //////////////////////////////////////////////////////////////////////////////
 
+struct CubicBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 class GrGLCubicEffect : public GrGLGeometryProcessor {
 public:
     GrGLCubicEffect(const GrGeometryProcessor&,
@@ -332,18 +449,29 @@ public:
                               const GrGLCaps&,
                               GrProcessorKeyBuilder*);
 
-    virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
-                         const GrBatchTracker&) SK_OVERRIDE {}
+    virtual void setData(const GrGLProgramDataManager& pdman,
+                         const GrPrimitiveProcessor&,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
+        const CubicBatchTracker& local = bt.cast<CubicBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
+    }
 
 private:
+    GrColor fColor;
     GrPrimitiveEdgeType fEdgeType;
+    UniformHandle fColorUniform;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLCubicEffect::GrGLCubicEffect(const GrGeometryProcessor& processor,
-                                 const GrBatchTracker&) {
+                                 const GrBatchTracker&)
+    : fColor(GrColor_ILLEGAL) {
     const GrCubicEffect& ce = processor.cast<GrCubicEffect>();
     fEdgeType = ce.getEdgeType();
 }
@@ -351,11 +479,16 @@ GrGLCubicEffect::GrGLCubicEffect(const GrGeometryProcessor& processor,
 void GrGLCubicEffect::emitCode(const EmitArgs& args) {
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
     const GrCubicEffect& gp = args.fGP.cast<GrCubicEffect>();
+    const CubicBatchTracker& local = args.fBT.cast<CubicBatchTracker>();
 
     GrGLVertToFrag v(kVec4f_GrSLType);
     args.fPB->addVarying("CubicCoeffs", &v, kHigh_GrSLPrecision);
     vsBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inCubicCoeffs()->fName);
 
+    // Setup pass through color
+    this->setupColorPassThrough(args.fPB, local.fInputColorType, args.fOutputColor, NULL,
+                                &fColorUniform);
+
     // setup coord outputs
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), gp.inPosition()->fName);
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), gp.inPosition()->fName);
@@ -452,11 +585,13 @@ void GrGLCubicEffect::emitCode(const EmitArgs& args) {
 }
 
 void GrGLCubicEffect::GenKey(const GrGeometryProcessor& processor,
-                             const GrBatchTracker&,
+                             const GrBatchTracker& bt,
                              const GrGLCaps&,
                              GrProcessorKeyBuilder* b) {
     const GrCubicEffect& ce = processor.cast<GrCubicEffect>();
+    const CubicBatchTracker& local = bt.cast<CubicBatchTracker>();
     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+    key |= kUniform_GrGPInput == local.fInputColorType ? 0x4 : 0x8;
     b->add32(key);
 }
 
@@ -487,6 +622,18 @@ bool GrCubicEffect::onIsEqual(const GrGeometryProcessor& other) const {
     return (ce.fEdgeType == fEdgeType);
 }
 
+void GrCubicEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    CubicBatchTracker* local = bt->cast<CubicBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+}
+
+bool GrCubicEffect::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const CubicBatchTracker& mine = m.cast<CubicBatchTracker>();
+    const CubicBatchTracker& theirs = t.cast<CubicBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrCubicEffect);
index 53b1053..a58211b 100644 (file)
@@ -97,6 +97,9 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrConicEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
 
@@ -106,6 +109,7 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    uint8_t               fCoverageScale;
     GrPrimitiveEdgeType   fEdgeType;
     const GrAttribute*    fInPosition;
     const GrAttribute*    fInConicCoeffs;
@@ -166,6 +170,9 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrQuadEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
 
@@ -175,6 +182,7 @@ private:
         out->setUnknownSingleComponent();
     }
 
+    uint8_t               fCoverageScale;
     GrPrimitiveEdgeType   fEdgeType;
     const GrAttribute*    fInPosition;
     const GrAttribute*    fInHairQuadEdge;
@@ -236,6 +244,9 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrCubicEffect(GrColor, GrPrimitiveEdgeType);
 
index c93db90..1b393f3 100644 (file)
 #include "gl/GrGLGeometryProcessor.h"
 #include "gl/builders/GrGLProgramBuilder.h"
 
+struct BitmapTextBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 class GrGLBitmapTextGeoProc : public GrGLGeometryProcessor {
 public:
-    GrGLBitmapTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&) {}
+    GrGLBitmapTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&)
+        : fColor(GrColor_ILLEGAL) {}
 
     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
         const GrBitmapTextGeoProc& cte = args.fGP.cast<GrBitmapTextGeoProc>();
+        const BitmapTextBatchTracker& local = args.fBT.cast<BitmapTextBatchTracker>();
 
-        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
+        GrGLGPBuilder* pb = args.fPB;
+        GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder();
 
         GrGLVertToFrag v(kVec2f_GrSLType);
-        args.fPB->addVarying("TextureCoords", &v);
+        pb->addVarying("TextureCoords", &v);
         vsBuilder->codeAppendf("%s = %s;", v.vsOut(), cte.inTextureCoords()->fName);
 
-        if (cte.inColor()) {
-            args.fPB->addPassThroughAttribute(cte.inColor(), args.fOutputColor);
-        }
+        // Setup pass through color
+        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, cte.inColor(),
+                                    &fColorUniform);
 
         // setup output coords
         vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), cte.inPosition()->fName);
@@ -39,27 +47,41 @@ public:
         vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(),
                                vsBuilder->uViewM(), cte.inPosition()->fName);
 
-        GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
+        GrGLGPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
         fsBuilder->codeAppendf("%s = ", args.fOutputCoverage);
         fsBuilder->appendTextureLookup(args.fSamplers[0], v.fsIn(), kVec2f_GrSLType);
         fsBuilder->codeAppend(";");
     }
 
-    virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
-                         const GrBatchTracker&) SK_OVERRIDE {}
+    virtual void setData(const GrGLProgramDataManager& pdman,
+                         const GrPrimitiveProcessor& gp,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
+        const BitmapTextBatchTracker& local = bt.cast<BitmapTextBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
+    }
 
     static inline void GenKey(const GrGeometryProcessor& proc,
-                              const GrBatchTracker&,
+                              const GrBatchTracker& bt,
                               const GrGLCaps&,
                               GrProcessorKeyBuilder* b) {
+        const BitmapTextBatchTracker& local = bt.cast<BitmapTextBatchTracker>();
+        // We have to put the optional vertex attribute as part of the key.  See the comment
+        // on addVertexAttrib.
+        // TODO When we have deferred geometry we can fix this
         const GrBitmapTextGeoProc& gp = proc.cast<GrBitmapTextGeoProc>();
-
         b->add32(SkToBool(gp.inColor()));
+        b->add32(local.fInputColorType);
     }
 
-
 private:
+    GrColor fColor;
+    UniformHandle fColorUniform;
+
     typedef GrGLGeometryProcessor INHERITED;
 };
 
@@ -107,6 +129,20 @@ GrGLGeometryProcessor*
 GrBitmapTextGeoProc::createGLInstance(const GrBatchTracker& bt) const {
     return SkNEW_ARGS(GrGLBitmapTextGeoProc, (*this, bt));
 }
+
+void GrBitmapTextGeoProc::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    BitmapTextBatchTracker* local = bt->cast<BitmapTextBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
+                                               SkToBool(fInColor));
+}
+
+bool GrBitmapTextGeoProc::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const BitmapTextBatchTracker& mine = m.cast<BitmapTextBatchTracker>();
+    const BitmapTextBatchTracker& theirs = t.cast<BitmapTextBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
index 0c84842..4234570 100644 (file)
@@ -40,6 +40,9 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrBitmapTextGeoProc(GrColor, GrTexture* texture, const GrTextureParams& params,
                         bool useColorAttrib, bool opaqueVertexColors);
index 1641d27..69e40eb 100644 (file)
@@ -441,6 +441,12 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, GrDrawState
 //////////////////////////////////////////////////////////////////////////////
 
 class GLDashingCircleEffect;
+
+struct DashingCircleBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 /*
  * This effect will draw a dotted line (defined as a dashed lined with round caps and no on
  * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo.
@@ -481,6 +487,10 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker&) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE;
+
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
                         SkScalar radius);
@@ -515,19 +525,22 @@ public:
                               GrProcessorKeyBuilder*);
 
     virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
+                         const GrPrimitiveProcessor&,
                          const GrBatchTracker&) SK_OVERRIDE;
 
 private:
-    GrGLProgramDataManager::UniformHandle fParamUniform;
-    SkScalar                              fPrevRadius;
-    SkScalar                              fPrevCenterX;
-    SkScalar                              fPrevIntervalLength;
+    UniformHandle fParamUniform;
+    UniformHandle fColorUniform;
+    GrColor       fColor;
+    SkScalar      fPrevRadius;
+    SkScalar      fPrevCenterX;
+    SkScalar      fPrevIntervalLength;
     typedef GrGLGeometryProcessor INHERITED;
 };
 
 GLDashingCircleEffect::GLDashingCircleEffect(const GrGeometryProcessor&,
                                              const GrBatchTracker&) {
+    fColor = GrColor_ILLEGAL;
     fPrevRadius = SK_ScalarMin;
     fPrevCenterX = SK_ScalarMin;
     fPrevIntervalLength = SK_ScalarMax;
@@ -535,6 +548,8 @@ GLDashingCircleEffect::GLDashingCircleEffect(const GrGeometryProcessor&,
 
 void GLDashingCircleEffect::emitCode(const EmitArgs& args) {
     const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>();
+    const DashingCircleBatchTracker local = args.fBT.cast<DashingCircleBatchTracker>();
+    GrGLGPBuilder* pb = args.fPB;
     const char *paramName;
     // The param uniforms, xyz, refer to circle radius - 0.5, cicles center x coord, and
     // the total interval length of the dash.
@@ -548,6 +563,9 @@ void GLDashingCircleEffect::emitCode(const EmitArgs& args) {
     args.fPB->addVarying("Coord", &v);
     vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dce.inCoord()->fName);
 
+    // Setup pass through color
+    this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
+
     // setup coord outputs
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), dce.inPosition()->fName);
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), dce.inPosition()->fName);
@@ -575,8 +593,8 @@ void GLDashingCircleEffect::emitCode(const EmitArgs& args) {
 }
 
 void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman,
-                                    const GrGeometryProcessor& processor,
-                                    const GrBatchTracker&) {
+                                    const GrPrimitiveProcessor& processor,
+                                    const GrBatchTracker& bt) {
     const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>();
     SkScalar radius = dce.getRadius();
     SkScalar centerX = dce.getCenterX();
@@ -587,14 +605,23 @@ void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman,
         fPrevCenterX = centerX;
         fPrevIntervalLength = intervalLength;
     }
+
+    const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
+    if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+        GrGLfloat c[4];
+        GrColorToRGBAFloat(local.fColor, c);
+        pdman.set4fv(fColorUniform, 1, c);
+        fColor = local.fColor;
+    }
 }
 
 void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& processor,
-                                   const GrBatchTracker&,
+                                   const GrBatchTracker& bt,
                                    const GrGLCaps&,
                                    GrProcessorKeyBuilder* b) {
+    const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
     const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>();
-    b->add32(dce.getEdgeType());
+    b->add32(dce.getEdgeType() << 16 | local.fInputColorType);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -649,6 +676,18 @@ bool DashingCircleEffect::onIsEqual(const GrGeometryProcessor& other) const {
             fCenterX == dce.fCenterX);
 }
 
+void DashingCircleEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    DashingCircleBatchTracker* local = bt->cast<DashingCircleBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+}
+
+bool DashingCircleEffect::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const DashingCircleBatchTracker& mine = m.cast<DashingCircleBatchTracker>();
+    const DashingCircleBatchTracker& theirs = t.cast<DashingCircleBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect);
 
 GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random,
@@ -673,6 +712,11 @@ GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random,
 
 class GLDashingLineEffect;
 
+struct DashingLineBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor  fColor;
+};
+
 /*
  * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the
  * length and spacing by the DashInfo. Both of the previous two parameters are in device space.
@@ -711,6 +755,10 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE;
+
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
                       SkScalar strokeWidth);
@@ -744,25 +792,30 @@ public:
                               GrProcessorKeyBuilder*);
 
     virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
+                         const GrPrimitiveProcessor&,
                          const GrBatchTracker&) SK_OVERRIDE;
 
 private:
-    GrGLProgramDataManager::UniformHandle fRectUniform;
-    GrGLProgramDataManager::UniformHandle fIntervalUniform;
-    SkRect                                fPrevRect;
-    SkScalar                              fPrevIntervalLength;
+    GrColor       fColor;
+    UniformHandle fRectUniform;
+    UniformHandle fIntervalUniform;
+    UniformHandle fColorUniform;
+    SkRect        fPrevRect;
+    SkScalar      fPrevIntervalLength;
     typedef GrGLGeometryProcessor INHERITED;
 };
 
 GLDashingLineEffect::GLDashingLineEffect(const GrGeometryProcessor&,
                                          const GrBatchTracker&) {
+    fColor = GrColor_ILLEGAL;
     fPrevRect.fLeft = SK_ScalarNaN;
     fPrevIntervalLength = SK_ScalarMax;
 }
 
 void GLDashingLineEffect::emitCode(const EmitArgs& args) {
     const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>();
+    const DashingLineBatchTracker& local = args.fBT.cast<DashingLineBatchTracker>();
+    GrGLGPBuilder* pb = args.fPB;
     const char *rectName;
     // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
     // respectively.
@@ -784,6 +837,9 @@ void GLDashingLineEffect::emitCode(const EmitArgs& args) {
     args.fPB->addVarying("Coord", &v);
     vsBuilder->codeAppendf("%s = %s;", v.vsOut(), de.inCoord()->fName);
 
+    // Setup pass through color
+    this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
+
     // setup coord outputs
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), de.inPosition()->fName);
     vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), de.inPosition()->fName);
@@ -818,8 +874,8 @@ void GLDashingLineEffect::emitCode(const EmitArgs& args) {
 }
 
 void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman,
-                                  const GrGeometryProcessor& processor,
-                                  const GrBatchTracker&) {
+                                  const GrPrimitiveProcessor& processor,
+                                  const GrBatchTracker& bt) {
     const DashingLineEffect& de = processor.cast<DashingLineEffect>();
     const SkRect& rect = de.getRect();
     SkScalar intervalLength = de.getIntervalLength();
@@ -830,14 +886,23 @@ void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman,
         fPrevRect = rect;
         fPrevIntervalLength = intervalLength;
     }
+
+    const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
+    if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+        GrGLfloat c[4];
+        GrColorToRGBAFloat(local.fColor, c);
+        pdman.set4fv(fColorUniform, 1, c);
+        fColor = local.fColor;
+    }
 }
 
 void GLDashingLineEffect::GenKey(const GrGeometryProcessor& processor,
-                                 const GrBatchTracker&,
+                                 const GrBatchTracker& bt,
                                  const GrGLCaps&,
                                  GrProcessorKeyBuilder* b) {
+    const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
     const DashingLineEffect& de = processor.cast<DashingLineEffect>();
-    b->add32(de.getEdgeType());
+    b->add32(de.getEdgeType() << 16 | local.fInputColorType);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -892,6 +957,18 @@ bool DashingLineEffect::onIsEqual(const GrGeometryProcessor& other) const {
             fIntervalLength == de.fIntervalLength);
 }
 
+void DashingLineEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    DashingLineBatchTracker* local = bt->cast<DashingLineBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+}
+
+bool DashingLineEffect::onCanMakeEqual(const GrBatchTracker& m, const GrBatchTracker& t) const {
+    const DashingLineBatchTracker& mine = m.cast<DashingLineBatchTracker>();
+    const DashingLineBatchTracker& theirs = t.cast<DashingLineBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect);
 
 GrGeometryProcessor* DashingLineEffect::TestCreate(SkRandom* random,
index 66d06b6..cc0a800 100755 (executable)
 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
 #define SK_DistanceFieldAAFactor     "0.7071"
 
+struct DistanceFieldBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLDistanceFieldTextureEffect(const GrGeometryProcessor&,
                                    const GrBatchTracker&)
-        : fTextureSize(SkISize::Make(-1,-1))
+        : fColor(GrColor_ILLEGAL)
+        , fTextureSize(SkISize::Make(-1,-1))
 #ifdef SK_GAMMA_APPLY_TO_A8
         , fLuminance(-1.0f)
 #endif
@@ -31,7 +37,8 @@ public:
     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
         const GrDistanceFieldTextureEffect& dfTexEffect =
                 args.fGP.cast<GrDistanceFieldTextureEffect>();
-
+        const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatchTracker>();
+        GrGLGPBuilder* pb = args.fPB;
         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
         SkAssertResult(fsBuilder->enableFeature(
                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
@@ -41,10 +48,9 @@ public:
         args.fPB->addVarying("TextureCoords", &v);
         vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
-        // setup color attribute
-        if(dfTexEffect.inColor()) {
-            args.fPB->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
-        }
+        // Setup pass through color
+        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
+                                    dfTexEffect.inColor(), &fColorUniform);
 
         // setup position varying
         vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(),
@@ -121,8 +127,8 @@ public:
     }
 
     virtual void setData(const GrGLProgramDataManager& pdman,
-                         const GrGeometryProcessor& proc,
-                         const GrBatchTracker&) SK_OVERRIDE {
+                         const GrPrimitiveProcessor& proc,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
         SkASSERT(fTextureSizeUni.isValid());
 
         GrTexture* texture = proc.texture(0);
@@ -142,23 +148,34 @@ public:
             fLuminance = luminance;
         }
 #endif
+
+        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
     }
 
     static inline void GenKey(const GrGeometryProcessor& processor,
-                              const GrBatchTracker&,
+                              const GrBatchTracker& bt,
                               const GrGLCaps&,
                               GrProcessorKeyBuilder* b) {
         const GrDistanceFieldTextureEffect& dfTexEffect =
                 processor.cast<GrDistanceFieldTextureEffect>();
-
+        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
         b->add32(dfTexEffect.getFlags());
+        b->add32(local.fInputColorType);
     }
 
 private:
-    GrGLProgramDataManager::UniformHandle fTextureSizeUni;
-    SkISize                               fTextureSize;
-    GrGLProgramDataManager::UniformHandle fLuminanceUni;
-    float                                 fLuminance;
+    GrColor       fColor;
+    UniformHandle fColorUniform;
+    UniformHandle fTextureSizeUni;
+    SkISize       fTextureSize;
+    UniformHandle fLuminanceUni;
+    float         fLuminance;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
@@ -221,6 +238,20 @@ GrDistanceFieldTextureEffect::createGLInstance(const GrBatchTracker& bt) const {
     return SkNEW_ARGS(GrGLDistanceFieldTextureEffect, (*this, bt));
 }
 
+void GrDistanceFieldTextureEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
+    DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
+                                               SkToBool(fInColor));
+}
+
+bool GrDistanceFieldTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
+                                                  const GrBatchTracker& t) const {
+    const DistanceFieldBatchTracker& mine = m.cast<DistanceFieldBatchTracker>();
+    const DistanceFieldBatchTracker& theirs = t.cast<DistanceFieldBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
@@ -263,16 +294,24 @@ GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
 
 ///////////////////////////////////////////////////////////////////////////////
 
+struct DistanceFieldNoGammaBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLDistanceFieldNoGammaTextureEffect(const GrGeometryProcessor&,
                                           const GrBatchTracker&)
-        : fTextureSize(SkISize::Make(-1, -1)) {}
+        : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {}
 
     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
         const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
                 args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>();
 
+        const DistanceFieldNoGammaBatchTracker& local =
+                args.fBT.cast<DistanceFieldNoGammaBatchTracker>();
+        GrGLGPBuilder* pb = args.fPB;
         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
         SkAssertResult(fsBuilder->enableFeature(
                                      GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
@@ -281,10 +320,9 @@ public:
         GrGLVertToFrag v(kVec2f_GrSLType);
         args.fPB->addVarying("TextureCoords", &v);
 
-        // setup color attribute
-        if(dfTexEffect.inColor()) {
-            args.fPB->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
-        }
+        // setup pass through color
+        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
+                                    dfTexEffect.inColor(), &fColorUniform);
 
         vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
@@ -348,8 +386,8 @@ public:
     }
 
     virtual void setData(const GrGLProgramDataManager& pdman,
-                         const GrGeometryProcessor& proc,
-                         const GrBatchTracker&) SK_OVERRIDE {
+                         const GrPrimitiveProcessor& proc,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
         SkASSERT(fTextureSizeUni.isValid());
 
         GrTexture* texture = proc.texture(0);
@@ -360,21 +398,33 @@ public:
                         SkIntToScalar(fTextureSize.width()),
                         SkIntToScalar(fTextureSize.height()));
         }
+
+        const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
     }
 
     static inline void GenKey(const GrGeometryProcessor& proc,
-                              const GrBatchTracker&,
+                              const GrBatchTracker& bt,
                               const GrGLCaps&,
                               GrProcessorKeyBuilder* b) {
         const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
             proc.cast<GrDistanceFieldNoGammaTextureEffect>();
 
+        const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
         b->add32(dfTexEffect.getFlags());
+        b->add32(local.fInputColorType);
     }
 
 private:
-    GrGLProgramDataManager::UniformHandle fTextureSizeUni;
-    SkISize                               fTextureSize;
+    UniformHandle fColorUniform;
+    UniformHandle fTextureSizeUni;
+    GrColor       fColor;
+    SkISize       fTextureSize;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
@@ -424,6 +474,21 @@ GrDistanceFieldNoGammaTextureEffect::createGLInstance(const GrBatchTracker& bt)
     return SkNEW_ARGS(GrGLDistanceFieldNoGammaTextureEffect, (*this, bt));
 }
 
+void GrDistanceFieldNoGammaTextureEffect::initBatchTracker(GrBatchTracker* bt,
+                                                           const InitBT& init) const {
+    DistanceFieldNoGammaBatchTracker* local = bt->cast<DistanceFieldNoGammaBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
+                                               SkToBool(fInColor));
+}
+
+bool GrDistanceFieldNoGammaTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
+                                                         const GrBatchTracker& t) const {
+    const DistanceFieldNoGammaBatchTracker& mine = m.cast<DistanceFieldNoGammaBatchTracker>();
+    const DistanceFieldNoGammaBatchTracker& theirs = t.cast<DistanceFieldNoGammaBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect);
@@ -453,22 +518,34 @@ GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* r
 
 ///////////////////////////////////////////////////////////////////////////////
 
+struct DistanceFieldLCDBatchTracker {
+    GrGPInput fInputColorType;
+    GrColor fColor;
+};
+
 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLDistanceFieldLCDTextureEffect(const GrGeometryProcessor&,
                                       const GrBatchTracker&)
-    : fTextureSize(SkISize::Make(-1,-1))
+    : fColor(GrColor_ILLEGAL)
+    , fTextureSize(SkISize::Make(-1,-1))
     , fTextColor(GrColor_ILLEGAL) {}
 
     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
                 args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
+        const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldLCDBatchTracker>();
+        GrGLGPBuilder* pb = args.fPB;
 
         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
         GrGLVertToFrag v(kVec2f_GrSLType);
         args.fPB->addVarying("TextureCoords", &v);
         vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
+        // setup pass through color
+        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
+                                    &fColorUniform);
+
         // setup coord outputs
         vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(),
                                dfTexEffect.inPosition()->fName);
@@ -588,8 +665,8 @@ public:
     }
 
     virtual void setData(const GrGLProgramDataManager& pdman,
-                         const GrGeometryProcessor& processor,
-                         const GrBatchTracker&) SK_OVERRIDE {
+                         const GrPrimitiveProcessor& processor,
+                         const GrBatchTracker& bt) SK_OVERRIDE {
         SkASSERT(fTextureSizeUni.isValid());
         SkASSERT(fTextColorUni.isValid());
 
@@ -618,23 +695,35 @@ public:
                         GrColorUnpackB(textColor) * ONE_OVER_255);
             fTextColor = textColor;
         }
+
+        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
+        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
+            GrGLfloat c[4];
+            GrColorToRGBAFloat(local.fColor, c);
+            pdman.set4fv(fColorUniform, 1, c);
+            fColor = local.fColor;
+        }
     }
 
     static inline void GenKey(const GrGeometryProcessor& processor,
-                              const GrBatchTracker&,
+                              const GrBatchTracker& bt,
                               const GrGLCaps&,
                               GrProcessorKeyBuilder* b) {
         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
                 processor.cast<GrDistanceFieldLCDTextureEffect>();
 
+        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
         b->add32(dfTexEffect.getFlags());
+        b->add32(local.fInputColorType);
     }
 
 private:
-    GrGLProgramDataManager::UniformHandle fTextureSizeUni;
-    SkISize                               fTextureSize;
-    GrGLProgramDataManager::UniformHandle fTextColorUni;
-    SkColor                               fTextColor;
+    GrColor       fColor;
+    UniformHandle fColorUniform;
+    UniformHandle fTextureSizeUni;
+    SkISize       fTextureSize;
+    UniformHandle fTextColorUni;
+    SkColor       fTextColor;
 
     typedef GrGLGeometryProcessor INHERITED;
 };
@@ -683,6 +772,20 @@ GrDistanceFieldLCDTextureEffect::createGLInstance(const GrBatchTracker& bt) cons
     return SkNEW_ARGS(GrGLDistanceFieldLCDTextureEffect, (*this, bt));
 }
 
+void GrDistanceFieldLCDTextureEffect::initBatchTracker(GrBatchTracker* bt,
+                                                       const InitBT& init) const {
+    DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>();
+    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
+}
+
+bool GrDistanceFieldLCDTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
+                                                     const GrBatchTracker& t) const {
+    const DistanceFieldLCDBatchTracker& mine = m.cast<DistanceFieldLCDBatchTracker>();
+    const DistanceFieldLCDBatchTracker& theirs = t.cast<DistanceFieldLCDBatchTracker>();
+    return CanCombineOutput(mine.fInputColorType, mine.fColor,
+                            theirs.fInputColorType, theirs.fColor);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
index 288da5c..5650cfc 100644 (file)
@@ -79,6 +79,10 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE;
+
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrDistanceFieldTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
 #ifdef SK_GAMMA_APPLY_TO_A8
@@ -135,6 +139,10 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE;
+
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrDistanceFieldNoGammaTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
                                         uint32_t flags, bool opaqueVertexColors);
@@ -184,6 +192,10 @@ public:
 
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
+    void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE;
+
+    bool onCanMakeEqual(const GrBatchTracker&, const GrBatchTracker&) const SK_OVERRIDE;
+
 private:
     GrDistanceFieldLCDTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
                                     GrTexture* gamma, const GrTextureParams& gammaParams,
index b825916..bf48379 100644 (file)
@@ -66,11 +66,28 @@ public:
             }
         }
         
-        fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
-                               args.fInputCoverage);
-        if (GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType == xp.primaryOutputType()){
-            fsBuilder->codeAppendf("%s += (vec4(1.0) - %s) * %s;", args.fOutputPrimary,
-                                   args.fInputCoverage, fsBuilder->dstColor());
+        switch (xp.primaryOutputType()) {
+            case GrPorterDuffXferProcessor::kNone_PrimaryOutputType:
+                fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
+                break;
+            case GrPorterDuffXferProcessor::kColor_PrimaryOutputType:
+                fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
+                break;
+            case GrPorterDuffXferProcessor::kCoverage_PrimaryOutputType:
+                fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
+                break;
+            case GrPorterDuffXferProcessor::kModulate_PrimaryOutputType:
+            case GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType:
+                fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
+                                       args.fInputCoverage);
+                if (GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType ==
+                    xp.primaryOutputType()){
+                    fsBuilder->codeAppendf("%s += (vec4(1.0) - %s) * %s;", args.fOutputPrimary,
+                                           args.fInputCoverage, fsBuilder->dstColor());
+                }
+                break;
+            default:
+                SkFAIL("Unexpected Primary Output");
         }
     }
 
@@ -122,7 +139,6 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
                                             bool colorWriteDisabled,
                                             bool doesStencilWrite,
                                             GrColor* overrideColor,
-                                            uint8_t* overrideCoverage,
                                             const GrDrawTargetCaps& caps) {
     GrXferProcessor::OptFlags optFlags;
     // Optimizations when doing RGB Coverage
@@ -139,9 +155,7 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
                                                   coveragePOI,
                                                   isCoverageDrawing,
                                                   colorWriteDisabled,
-                                                  doesStencilWrite,
-                                                  overrideColor,
-                                                  overrideCoverage);
+                                                  doesStencilWrite);
     }
     this->calcOutputTypes(optFlags, caps, isCoverageDrawing || coveragePOI.isSolidWhite(),
                           colorPOI.readsDst() || coveragePOI.readsDst());
@@ -151,6 +165,19 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
 void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
                                                 const GrDrawTargetCaps& caps,
                                                 bool hasSolidCoverage, bool readsDst) {
+    if (optFlags & kIgnoreColor_OptFlag) {
+        if (optFlags & kIgnoreCoverage_OptFlag) {
+            fPrimaryOutputType = kNone_PrimaryOutputType;
+            return;
+        } else {
+            fPrimaryOutputType = kCoverage_PrimaryOutputType;
+            return;
+        }
+    } else if (optFlags & kIgnoreCoverage_OptFlag) {
+        fPrimaryOutputType = kColor_PrimaryOutputType;
+        return;
+    }
+
     // If we do have coverage determine whether it matters.  Dual source blending is expensive so
     // we don't do it if we are doing coverage drawing.  If we aren't then We always do dual source
     // blending if we have any effective coverage stages OR the geometry processor doesn't emits
@@ -183,9 +210,7 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO
                                                     const GrProcOptInfo& coveragePOI,
                                                     bool isCoverageDrawing,
                                                     bool colorWriteDisabled,
-                                                    bool doesStencilWrite,
-                                                    GrColor* overrideColor,
-                                                    uint8_t* overrideCoverage) {
+                                                    bool doesStencilWrite) {
     if (colorWriteDisabled) {
         fSrcBlend = kZero_GrBlendCoeff;
         fDstBlend = kOne_GrBlendCoeff;
@@ -211,8 +236,7 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO
     // (0,1).
     if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
         if (doesStencilWrite) {
-            *overrideColor = 0xffffffff;
-            return GrXferProcessor::kClearColorStages_OptFlag |
+            return GrXferProcessor::kIgnoreColor_OptFlag |
                    GrXferProcessor::kSetCoverageDrawing_OptFlag;
         } else {
             fDstBlend = kOne_GrBlendCoeff;
@@ -234,10 +258,8 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO
                 // or blend, just write transparent black into the dst.
                 fSrcBlend = kOne_GrBlendCoeff;
                 fDstBlend = kZero_GrBlendCoeff;
-                *overrideColor = 0;
-                *overrideCoverage = 0xff;
-                return GrXferProcessor::kClearColorStages_OptFlag |
-                       GrXferProcessor::kClearCoverageStages_OptFlag;
+                return GrXferProcessor::kIgnoreColor_OptFlag |
+                       GrXferProcessor::kIgnoreCoverage_OptFlag;
             }
         }
     } else if (isCoverageDrawing) {
@@ -255,8 +277,7 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO
                 // the dst coeff is effectively zero so blend works out to:
                 // (c)(0)D + (1-c)D = (1-c)D.
                 fDstBlend = kISA_GrBlendCoeff;
-                *overrideColor = 0xffffffff;
-                return GrXferProcessor::kClearColorStages_OptFlag |
+                return GrXferProcessor::kIgnoreColor_OptFlag |
                        GrXferProcessor::kSetCoverageDrawing_OptFlag;
             } else if (srcAIsOne) {
                 // the dst coeff is effectively zero so blend works out to:
index aa58cd3..a9f5ead 100644 (file)
@@ -23,10 +23,12 @@ public:
     GrGLGeometryProcessor() {}
     virtual ~GrGLGeometryProcessor() {}
 
+    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
     typedef GrGLProcessor::TextureSamplerArray TextureSamplerArray;
+
     struct EmitArgs {
         EmitArgs(GrGLGPBuilder* pb,
-                 const GrGeometryProcessor& gp,
+                 const GrPrimitiveProcessor& gp,
                  const GrBatchTracker& bt,
                  const char* outputColor,
                  const char* outputCoverage,
@@ -38,12 +40,13 @@ public:
             , fOutputCoverage(outputCoverage)
             , fSamplers(samplers) {}
         GrGLGPBuilder* fPB;
-        const GrGeometryProcessor& fGP;
+        const GrPrimitiveProcessor& fGP;
         const GrBatchTracker& fBT;
         const char* fOutputColor;
         const char* fOutputCoverage;
         const TextureSamplerArray& fSamplers;
     };
+
     /**
      * This is similar to emitCode() in the base class, except it takes a full shader builder.
      * This allows the effect subclass to emit vertex code.
@@ -56,9 +59,21 @@ public:
         parameter is guaranteed to be of the same type that created this GrGLGeometryProcessor and
         to have an identical processor key as the one that created this GrGLGeometryProcessor.  */
     virtual void setData(const GrGLProgramDataManager&,
-                         const GrGeometryProcessor&,
+                         const GrPrimitiveProcessor&,
                          const GrBatchTracker&) = 0;
 
+protected:
+    /** a helper which can setup vertex, constant, or uniform color depending on inputType.
+     *  This function will only do the minimum required to emit the correct shader code.  If
+     *  inputType == attribute, then colorAttr must not be NULL.  Likewise, if inputType == Uniform
+     *  then colorUniform must not be NULL.
+     */
+    void setupColorPassThrough(GrGLGPBuilder* pb,
+                               GrGPInput inputType,
+                               const char* inputName,
+                               const GrGeometryProcessor::GrAttribute* colorAttr,
+                               UniformHandle* colorUniform);
+
 private:
     typedef GrGLProcessor INHERITED;
 };
index da687c1..7d5b0d7 100644 (file)
@@ -131,11 +131,6 @@ void GrGLProgram::bindTextures(const GrGLInstalledProc* ip, const GrProcessor& p
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGLProgram::setData(const GrOptDrawState& optState) {
-    GrColor color = optState.getColor();
-    uint8_t coverage = optState.getCoverage();
-
-    this->setColor(optState, color);
-    this->setCoverage(optState, coverage);
     this->setMatrixAndRenderTargetHeight(optState);
 
     const GrDeviceCoordTexture* dstCopy = optState.getDstCopy();
@@ -162,13 +157,11 @@ void GrGLProgram::setData(const GrOptDrawState& optState) {
 
     // we set the textures, and uniforms for installed processors in a generic way, but subclasses
     // of GLProgram determine how to set coord transforms
-    if (fGeometryProcessor.get()) {
-        SkASSERT(optState.hasGeometryProcessor());
-        const GrGeometryProcessor& gp = *optState.getGeometryProcessor();
-        const GrBatchTracker& bt = optState.getBatchTracker();
-        fGeometryProcessor->fGLProc->setData(fProgramDataManager, gp, bt);
-        this->bindTextures(fGeometryProcessor, gp);
-    }
+    const GrPrimitiveProcessor& primProc = *optState.getPrimitiveProcessor();
+    const GrBatchTracker& bt = optState.getBatchTracker();
+    fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc, bt);
+    this->bindTextures(fGeometryProcessor, primProc);
+
     if (fXferProcessor.get()) {
         const GrXferProcessor& xp = *optState.getXferProcessor();
         fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
@@ -209,51 +202,6 @@ void GrGLProgram::didSetData(GrGpu::DrawType drawType) {
     SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType));
 }
 
-void GrGLProgram::setColor(const GrOptDrawState& optState, GrColor color) {
-    const GrProgramDesc::KeyHeader& header = fDesc.header();
-    switch (header.fColorInput) {
-        case GrProgramDesc::kAttribute_ColorInput:
-            // Attribute case is handled in GrGpuGL::setupGeometry
-            break;
-        case GrProgramDesc::kUniform_ColorInput:
-            if (fColor != color && fBuiltinUniformHandles.fColorUni.isValid()) {
-                // OpenGL ES doesn't support unsigned byte varieties of glUniform
-                GrGLfloat c[4];
-                GrColorToRGBAFloat(color, c);
-                fProgramDataManager.set4fv(fBuiltinUniformHandles.fColorUni, 1, c);
-                fColor = color;
-            }
-            break;
-        case GrProgramDesc::kAllOnes_ColorInput:
-            // Handled by shader creation
-            break;
-        default:
-            SkFAIL("Unexpected color type.");
-    }
-}
-
-void GrGLProgram::setCoverage(const GrOptDrawState& optState, uint8_t coverage) {
-    const GrProgramDesc::KeyHeader& header = fDesc.header();
-    switch (header.fCoverageInput) {
-        case GrProgramDesc::kAttribute_ColorInput:
-            // Attribute case is handled in GrGpuGL::setupGeometry
-            break;
-        case GrProgramDesc::kUniform_ColorInput:
-            if (fCoverage != coverage) {
-                // OpenGL ES doesn't support unsigned byte varieties of glUniform
-                GrGLfloat c = GrNormalizeByteToFloat(coverage);
-                fProgramDataManager.set1f(fBuiltinUniformHandles.fCoverageUni, c);
-                fCoverage = coverage;
-            }
-            break;
-        case GrProgramDesc::kAllOnes_ColorInput:
-            // Handled by shader creation
-            break;
-        default:
-            SkFAIL("Unexpected coverage type.");
-    }
-}
-
 void GrGLProgram::setMatrixAndRenderTargetHeight(const GrOptDrawState& optState) {
     // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
     if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
@@ -296,9 +244,10 @@ GrGLNvprProgramBase::GrGLNvprProgramBase(GrGpuGL* gpu,
                                          const BuiltinUniformHandles& builtinUniforms,
                                          GrGLuint programID,
                                          const UniformInfoArray& uniforms,
+                                         GrGLInstalledGeoProc* primProc,
                                          GrGLInstalledXferProc* xferProcessor,
                                          GrGLInstalledFragProcs* fragmentProcessors)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL,
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc,
                 xferProcessor, fragmentProcessors) {
 }
 
@@ -317,10 +266,11 @@ GrGLNvprProgram::GrGLNvprProgram(GrGpuGL* gpu,
                                  const BuiltinUniformHandles& builtinUniforms,
                                  GrGLuint programID,
                                  const UniformInfoArray& uniforms,
+                                 GrGLInstalledGeoProc* primProc,
                                  GrGLInstalledXferProc* xferProcessor,
                                  GrGLInstalledFragProcs* fragmentProcessors,
                                  const SeparableVaryingInfoArray& separableVaryings)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms,
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc,
                 xferProcessor, fragmentProcessors) {
     int count = separableVaryings.count();
     fVaryings.push_back_n(count);
@@ -369,10 +319,11 @@ GrGLLegacyNvprProgram::GrGLLegacyNvprProgram(GrGpuGL* gpu,
                                              const BuiltinUniformHandles& builtinUniforms,
                                              GrGLuint programID,
                                              const UniformInfoArray& uniforms,
+                                             GrGLInstalledGeoProc* primProc,
                                              GrGLInstalledXferProc* xp,
                                              GrGLInstalledFragProcs* fps,
                                              int texCoordSetCnt)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, xp, fps)
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc, xp, fps)
     , fTexCoordSetCnt(texCoordSetCnt) {
 }
 
index ea8be85..bada8fd 100644 (file)
@@ -148,14 +148,6 @@ protected:
     void initSamplerUniforms();
     void initSamplers(GrGLInstalledProc*, int* texUnitIdx);
 
-    // Helper for setData(). Makes GL calls to specify the initial color when there is not
-    // per-vertex colors.
-    void setColor(const GrOptDrawState&, GrColor color);
-
-    // Helper for setData(). Makes GL calls to specify the initial coverage when there is not
-    // per-vertex coverages.
-    void setCoverage(const GrOptDrawState&, uint8_t coverage);
-
     // A templated helper to loop over effects, set the transforms(via subclass) and bind textures
     void setFragmentData(const GrOptDrawState&);
     virtual void setTransformData(const GrPendingFragmentStage&, GrGLInstalledFragProc*);
@@ -207,6 +199,7 @@ protected:
                         const BuiltinUniformHandles&,
                         GrGLuint programID,
                         const UniformInfoArray&,
+                        GrGLInstalledGeoProc*,
                         GrGLInstalledXferProc* xferProcessor,
                         GrGLInstalledFragProcs* fragmentProcessors);
     virtual void onSetMatrixAndRenderTargetHeight(const GrOptDrawState&);
@@ -226,6 +219,7 @@ private:
                     const BuiltinUniformHandles&,
                     GrGLuint programID,
                     const UniformInfoArray&,
+                    GrGLInstalledGeoProc*,
                     GrGLInstalledXferProc* xferProcessor,
                     GrGLInstalledFragProcs* fragmentProcessors,
                     const SeparableVaryingInfoArray& separableVaryings);
@@ -256,6 +250,7 @@ private:
                           const BuiltinUniformHandles&,
                           GrGLuint programID,
                           const UniformInfoArray&,
+                          GrGLInstalledGeoProc*,
                           GrGLInstalledXferProc* xp,
                           GrGLInstalledFragProcs* fps,
                           int texCoordSetCnt);
index 2476c55..c5c31d3 100644 (file)
@@ -40,19 +40,6 @@ static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
     return false;
 }
 
-static uint32_t gen_attrib_key(const GrGeometryProcessor& proc) {
-    uint32_t key = 0;
-
-    const GrGeometryProcessor::VertexAttribArray& vars = proc.getAttribs();
-    int numAttributes = vars.count();
-    SkASSERT(numAttributes <= GrGeometryProcessor::kMaxVertexAttribs);
-    for (int a = 0; a < numAttributes; ++a) {
-        uint32_t value = 1 << a;
-        key |= value;
-    }
-    return key;
-}
-
 /**
  * The key for an individual coord transform is made up of a matrix type, a precision, and a bit
  * that indicates the source of the input coords.
@@ -131,7 +118,6 @@ static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
 static bool get_meta_key(const GrProcessor& proc,
                          const GrGLCaps& caps,
                          uint32_t transformKey,
-                         uint32_t attribKey,
                          GrProcessorKeyBuilder* b) {
     size_t processorKeySize = b->size();
     uint32_t textureKey = gen_texture_key(proc, caps);
@@ -158,9 +144,6 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState,
                                    GrGpu::DrawType drawType,
                                    GrGpuGL* gpu,
                                    GrProgramDesc* desc) {
-    bool inputColorIsUsed = descInfo.fInputColorIsUsed;
-    bool inputCoverageIsUsed = descInfo.fInputCoverageIsUsed;
-
     // The descriptor is used as a cache key. Thus when a field of the
     // descriptor will not affect program generation (because of the attribute
     // bindings in use or other descriptor field settings) it should be set
@@ -173,33 +156,29 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState,
     desc->fKey.reset();
     desc->fKey.push_back_n(kProcessorKeysOffset);
 
-    // We can only have one effect which touches the vertex shader
-    if (optState.hasGeometryProcessor()) {
-        const GrGeometryProcessor& gp = *optState.getGeometryProcessor();
-        GrProcessorKeyBuilder b(&desc->fKey);
-        gp.getGLProcessorKey(optState.getBatchTracker(), gpu->glCaps(), &b);
-        if (!get_meta_key(gp, gpu->glCaps(), 0, gen_attrib_key(gp), &b)) {
-            desc->fKey.reset();
-            return false;
-        }
+    GrProcessorKeyBuilder b(&desc->fKey);
+
+    const GrPrimitiveProcessor& primProc = *optState.getPrimitiveProcessor();
+    primProc.getGLProcessorKey(optState.getBatchTracker(), gpu->glCaps(), &b);
+    if (!get_meta_key(primProc, gpu->glCaps(), 0, &b)) {
+        desc->fKey.reset();
+        return false;
     }
 
     for (int s = 0; s < optState.numFragmentStages(); ++s) {
         const GrPendingFragmentStage& fps = optState.getFragmentStage(s);
         const GrFragmentProcessor& fp = *fps.getProcessor();
-        GrProcessorKeyBuilder b(&desc->fKey);
         fp.getGLProcessorKey(gpu->glCaps(), &b);
         if (!get_meta_key(fp, gpu->glCaps(),
-                          gen_transform_key(fps, requiresLocalCoordAttrib), 0, &b)) {
+                          gen_transform_key(fps, requiresLocalCoordAttrib), &b)) {
             desc->fKey.reset();
             return false;
         }
     }
 
     const GrXferProcessor& xp = *optState.getXferProcessor();
-    GrProcessorKeyBuilder b(&desc->fKey);
     xp.getGLProcessorKey(gpu->glCaps(), &b);
-    if (!get_meta_key(xp, gpu->glCaps(), 0, 0, &b)) {
+    if (!get_meta_key(xp, gpu->glCaps(), 0, &b)) {
         desc->fKey.reset();
         return false;
     }
@@ -212,8 +191,6 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState,
     // make sure any padding in the header is zeroed.
     memset(header, 0, kHeaderSize);
 
-    header->fHasGeometryProcessor = optState.hasGeometryProcessor();
-
     bool isPathRendering = GrGpu::IsPathRenderingDrawType(drawType);
     if (gpu->caps()->pathRenderingSupport() && isPathRendering) {
         header->fUseNvpr = true;
@@ -222,30 +199,6 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState,
         header->fUseNvpr = false;
     }
 
-    bool hasUniformColor = inputColorIsUsed && (isPathRendering || !descInfo.fHasVertexColor);
-
-    if (!inputColorIsUsed) {
-        header->fColorInput = GrProgramDesc::kAllOnes_ColorInput;
-    } else if (hasUniformColor) {
-        header->fColorInput = GrProgramDesc::kUniform_ColorInput;
-    } else {
-        header->fColorInput = GrProgramDesc::kAttribute_ColorInput;
-        SkASSERT(!header->fUseNvpr);
-    }
-
-    bool hasVertexCoverage = !isPathRendering && descInfo.fHasVertexCoverage;
-
-    bool covIsSolidWhite = !hasVertexCoverage && 0xffffffff == optState.getCoverageColor();
-
-    if (covIsSolidWhite || !inputCoverageIsUsed) {
-        header->fCoverageInput = GrProgramDesc::kAllOnes_ColorInput;
-    } else if (!hasVertexCoverage) {
-        header->fCoverageInput = GrProgramDesc::kUniform_ColorInput;
-    } else {
-        header->fCoverageInput = GrProgramDesc::kAttribute_ColorInput;
-        SkASSERT(!header->fUseNvpr);
-    }
-
     if (descInfo.fReadsDst) {
         const GrDeviceCoordTexture* dstCopy = optState.getDstCopy();
         SkASSERT(dstCopy || gpu->caps()->dstReadInShaderSupport());
index b90bab2..696c9a5 100644 (file)
@@ -45,6 +45,6 @@ void GrGLLegacyNvprProgramBuilder::emitTransforms(const GrPendingFragmentStage&
 
 GrGLProgram* GrGLLegacyNvprProgramBuilder::createProgram(GrGLuint programID) {
     return SkNEW_ARGS(GrGLLegacyNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
-                                              fXferProcessor, fFragmentProcessors.get(),
+            fGeometryProcessor, fXferProcessor, fFragmentProcessors.get(),
                                               fTexCoordSetCnt));
 }
index ba19275..063526d 100644 (file)
@@ -72,6 +72,7 @@ GrGLProgram* GrGLNvprProgramBuilder::createProgram(GrGLuint programID) {
     // building
     this->resolveSeparableVaryings(programID);
     return SkNEW_ARGS(GrGLNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
+                                        fGeometryProcessor,
                                         fXferProcessor, fFragmentProcessors.get(),
                                         fSeparableVaryingInfos));
 }
index daa0b6b..bbae592 100644 (file)
@@ -37,24 +37,17 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, G
     const GrGLProgramDescBuilder::GLKeyHeader& header = GrGLProgramDescBuilder::GetHeader(pb->desc());
 
     // emit code to read the dst copy texture, if necessary
-    if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey
-            && !gpu->glCaps().fbFetchSupport()) {
+    if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey &&
+        !gpu->glCaps().fbFetchSupport()) {
         pb->fFS.emitCodeToReadDstTexture();
     }
 
-    // get the initial color and coverage to feed into the first effect in each effect chain
-    GrGLSLExpr4 inputColor;
-    GrGLSLExpr1 inputCoverage;
-    pb->setupUniformColorAndCoverageIfNeeded(&inputColor,  &inputCoverage);
-
     // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
-    // remove this cast to a vec4.
-    GrGLSLExpr4 inputCoverageVec4;
-    if (inputCoverage.isValid()) {
-        inputCoverageVec4 = GrGLSLExpr4::VectorCast(inputCoverage);
-    }
+    // seed correctly here
+    GrGLSLExpr4 inputColor;
+    GrGLSLExpr4 inputCoverage;
 
-    pb->emitAndInstallProcs(&inputColor, &inputCoverageVec4);
+    pb->emitAndInstallProcs(&inputColor, &inputCoverage);
 
     return pb->finalize();
 }
@@ -65,8 +58,6 @@ GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawStat
     const GrProgramDesc& desc = optState.programDesc();
     if (GrGLProgramDescBuilder::GetHeader(desc).fUseNvpr) {
         SkASSERT(gpu->glCaps().pathRenderingSupport());
-        SkASSERT(GrProgramDesc::kAttribute_ColorInput != desc.header().fColorInput);
-        SkASSERT(GrProgramDesc::kAttribute_ColorInput != desc.header().fCoverageInput);
         SkASSERT(!hasGeometryProcessor);
         if (gpu->glPathRendering()->texturingMode() ==
             GrGLPathRendering::FixedFunction_TexturingMode) {
@@ -185,36 +176,10 @@ const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
     return fGpu->ctxInfo();
 }
 
-void GrGLProgramBuilder::setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor,
-                                                              GrGLSLExpr1* inputCoverage) {
-    const GrProgramDesc::KeyHeader& header = this->header();
-    if (GrProgramDesc::kUniform_ColorInput == header.fColorInput) {
-        const char* name;
-        fUniformHandles.fColorUni =
-            this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                             kVec4f_GrSLType, kDefault_GrSLPrecision,
-                             "Color", &name);
-        *inputColor = GrGLSLExpr4(name);
-    } else if (GrProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
-        *inputColor = GrGLSLExpr4(1);
-    }
-    if (GrProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
-        const char* name;
-        fUniformHandles.fCoverageUni =
-            this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                             kFloat_GrSLType, kDefault_GrSLPrecision,
-                             "Coverage",&name);
-        *inputCoverage = GrGLSLExpr1(name);
-    } else if (GrProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
-        *inputCoverage = GrGLSLExpr1(1);
-    }
-}
-
 void GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
     if (fOptState.hasGeometryProcessor()) {
         fVS.setupUniformViewMatrix();
 
-        const GrProgramDesc::KeyHeader& header = this->header();
         fVS.codeAppend("gl_PointSize = 1.0;");
 
         // Setup position
@@ -227,25 +192,11 @@ void GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
 
         const GrGeometryProcessor& gp = *fOptState.getGeometryProcessor();
         fVS.emitAttributes(gp);
-        GrGLSLExpr4 outputColor;
-        GrGLSLExpr4 outputCoverage;
-        this->emitAndInstallProc(gp, &outputColor, &outputCoverage);
-
-        // We may override color and coverage here if we have unform color or coverage.  This is
-        // obviously not ideal.
-        // TODO lets the GP itself do the override
-        if (GrProgramDesc::kAttribute_ColorInput == header.fColorInput) {
-            *inputColor = outputColor;
-        }
-
-        // We may have uniform coverage, if so we need to multiply the GPs output by the uniform
-        // coverage
-        if (GrProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
-            fFS.codeAppendf("%s *= %s;", outputCoverage.c_str(), inputCoverage->c_str());
-        }
-        *inputCoverage = outputCoverage;
     }
 
+    const GrPrimitiveProcessor& primProc = *fOptState.getPrimitiveProcessor();
+    this->emitAndInstallProc(primProc, inputColor, inputCoverage);
+
     fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
     int numProcs = fOptState.numFragmentStages();
     this->emitAndInstallFragProcs(0, fOptState.numColorStages(), inputColor);
@@ -303,7 +254,7 @@ void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& proc,
     fFS.codeAppend("}");
 }
 
-void GrGLProgramBuilder::emitAndInstallProc(const GrGeometryProcessor& proc,
+void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
                                             GrGLSLExpr4* outputColor,
                                             GrGLSLExpr4* outputCoverage) {
     // Program builders have a bit of state we need to clear with each effect
@@ -344,7 +295,7 @@ void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& fs,
     fFragmentProcessors->fProcs.push_back(ifp);
 }
 
-void GrGLProgramBuilder::emitAndInstallProc(const GrGeometryProcessor& gp,
+void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
                                             const char* outColor,
                                             const char* outCoverage) {
     SkASSERT(!fGeometryProcessor);
@@ -403,7 +354,7 @@ void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
     fFS.codeAppend("}");
 }
 
-void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) {
+void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
     SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
 }
 
@@ -489,11 +440,6 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
 
     // compile shaders and bind attributes / uniforms
     SkTDArray<GrGLuint> shadersToDelete;
-    if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
-        this->cleanupProgram(programID, shadersToDelete);
-        return NULL;
-    }
-
     if (!(GrGLProgramDescBuilder::GetHeader(fDesc).fUseNvpr &&
           fGpu->glPathRendering()->texturingMode() ==
           GrGLPathRendering::FixedFunction_TexturingMode)) {
@@ -507,6 +453,12 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
             fVS.bindVertexAttributes(programID);
         }
     }
+
+    if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
+        this->cleanupProgram(programID, shadersToDelete);
+        return NULL;
+    }
+
     bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
     if (usingBindUniform) {
         this->bindUniformLocations(programID);
index 69eed27..e4c5f31 100644 (file)
@@ -242,8 +242,6 @@ public:
     struct BuiltinUniformHandles {
         UniformHandle       fViewMatrixUni;
         UniformHandle       fRTAdjustmentUni;
-        UniformHandle       fColorUni;
-        UniformHandle       fCoverageUni;
 
         // We use the render target height to provide a y-down frag coord when specifying
         // origin_upper_left is not supported.
@@ -273,7 +271,6 @@ protected:
     // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
     // generating stage code.
     void nameVariable(SkString* out, char prefix, const char* name);
-    void setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor, GrGLSLExpr1* inputCoverage);
     // Generates a possibly mangled name for a stage variable and writes it to the fragment shader.
     // If GrGLSLExpr4 has a valid name then it will use that instead
     void nameExpression(GrGLSLExpr4*, const char* baseName);
@@ -285,7 +282,7 @@ protected:
                             const GrGLSLExpr4& input,
                             GrGLSLExpr4* output);
 
-    void emitAndInstallProc(const GrGeometryProcessor&,
+    void emitAndInstallProc(const GrPrimitiveProcessor&,
                             GrGLSLExpr4* outputColor,
                             GrGLSLExpr4* outputCoverage);
 
@@ -293,14 +290,14 @@ protected:
     void emitAndInstallProc(const GrPendingFragmentStage&,
                             const char* outColor,
                             const char* inColor);
-    void emitAndInstallProc(const GrGeometryProcessor&,
+    void emitAndInstallProc(const GrPrimitiveProcessor&,
                             const char* outColor,
                             const char* outCoverage);
     void emitAndInstallXferProc(const GrXferProcessor&,
                                 const GrGLSLExpr4& colorIn,
                                 const GrGLSLExpr4& coverageIn);
 
-    void verify(const GrGeometryProcessor&);
+    void verify(const GrPrimitiveProcessor&);
     void verify(const GrXferProcessor&);
     void verify(const GrFragmentProcessor&);
     void emitSamplers(const GrProcessor&,