Dash using vertex attributes for interval and stroke width
authorjoshualitt <joshualitt@chromium.org>
Tue, 3 Feb 2015 23:07:51 +0000 (15:07 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 3 Feb 2015 23:07:51 +0000 (15:07 -0800)
BUG=skia:

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

src/gpu/effects/GrDashingEffect.cpp
src/gpu/effects/GrDashingEffect.h

index 34e0301..a33d604 100644 (file)
@@ -67,6 +67,15 @@ namespace {
 struct DashLineVertex {
     SkPoint fPos;
     SkPoint fDashPos;
+    SkScalar fIntervalLength;
+    SkRect fRect;
+};
+struct DashCircleVertex {
+    SkPoint fPos;
+    SkPoint fDashPos;
+    SkScalar fIntervalLength;
+    SkScalar fRadius;
+    SkScalar fCenterX;
 };
 };
 
@@ -138,21 +147,73 @@ static SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const Sk
     return 0;
 }
 
-static void setup_dashed_rect(const SkRect& rect, DashLineVertex* verts, int idx, const SkMatrix& matrix,
-                       SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) {
-        SkScalar startDashX = offset - bloat;
-        SkScalar endDashX = offset + len + bloat;
-        SkScalar startDashY = -stroke - bloat;
-        SkScalar endDashY = stroke + bloat;
-        verts[idx].fDashPos = SkPoint::Make(startDashX , startDashY);
-        verts[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY);
-        verts[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY);
-        verts[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY);
-        verts[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop);
-        verts[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom);
-        verts[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom);
-        verts[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop);
-        matrix.mapPointsWithStride(&verts[idx].fPos, sizeof(DashLineVertex), 4);
+enum DashCap {
+    kRound_DashCap,
+    kNonRound_DashCap,
+};
+
+static int kDashVertices = 4;
+
+template <typename T>
+void setup_dashed_rect_common(const SkRect& rect, const SkMatrix& matrix, T* vertices, int idx,
+                              SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) {
+    SkScalar startDashX = offset - bloat;
+    SkScalar endDashX = offset + len + bloat;
+    SkScalar startDashY = -stroke - bloat;
+    SkScalar endDashY = stroke + bloat;
+    vertices[idx].fDashPos = SkPoint::Make(startDashX , startDashY);
+    vertices[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY);
+    vertices[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY);
+    vertices[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY);
+
+    vertices[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop);
+    vertices[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom);
+    vertices[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom);
+    vertices[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop);
+
+    matrix.mapPointsWithStride(&vertices[idx].fPos, sizeof(T), 4);
+}
+
+static void setup_dashed_rect(const SkRect& rect, void* vertices, int idx,
+                              const SkMatrix& matrix, SkScalar offset, SkScalar bloat,
+                              SkScalar len, SkScalar stroke, SkScalar startInterval,
+                              SkScalar endInterval, SkScalar strokeWidth, DashCap cap,
+                              const size_t vertexStride) {
+    SkScalar intervalLength = startInterval + endInterval;
+
+    if (kRound_DashCap == cap) {
+        SkASSERT(vertexStride == sizeof(DashCircleVertex));
+        DashCircleVertex* verts = reinterpret_cast<DashCircleVertex*>(vertices);
+
+        setup_dashed_rect_common<DashCircleVertex>(rect, matrix, verts, idx, offset, bloat, len,
+                                                   stroke);
+
+        SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f;
+        SkScalar centerX = SkScalarHalf(endInterval);
+
+        for (int i = 0; i < kDashVertices; i++) {
+            verts[idx + i].fIntervalLength = intervalLength;
+            verts[idx + i].fRadius = radius;
+            verts[idx + i].fCenterX = centerX;
+        }
+
+    } else {
+        SkASSERT(kNonRound_DashCap == cap && vertexStride == sizeof(DashLineVertex));
+        DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(vertices);
+
+        setup_dashed_rect_common<DashLineVertex>(rect, matrix, verts, idx, offset, bloat, len,
+                                                 stroke);
+
+        SkScalar halfOffLen = SkScalarHalf(endInterval);
+        SkScalar halfStroke = SkScalarHalf(strokeWidth);
+        SkRect rectParam;
+        rectParam.set(halfOffLen + 0.5f, -halfStroke + 0.5f,
+                      halfOffLen + startInterval - 0.5f, halfStroke - 0.5f);
+        for (int i = 0; i < kDashVertices; i++) {
+            verts[idx + i].fIntervalLength = intervalLength;
+            verts[idx + i].fRect = rectParam;
+        }
+    }
 }
 
 static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& matrix,
@@ -164,6 +225,18 @@ static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& m
     matrix.mapPoints(&verts[idx], 4);
 }
 
+
+/**
+ * An GrGeometryProcessor that renders a dashed line.
+ * This GrGeometryProcessor is meant for dashed lines that only have a single on/off interval pair.
+ * Bounding geometry is rendered and the effect computes coverage based on the fragment's
+ * position relative to the dashed line.
+ */
+static GrGeometryProcessor* create_dash_gp(GrColor,
+                                           GrPrimitiveEdgeType edgeType,
+                                           DashCap cap,
+                                           const SkMatrix& localMatrix);
+
 bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
                                    GrPipelineBuilder* pipelineBuilder, GrColor color,
                                    const SkMatrix& viewMatrix, const SkPoint pts[2],
@@ -342,6 +415,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
         return false;
     }
 
+    bool isRoundCap = SkPaint::kRound_Cap == cap;
+    DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap;
+
     SkAutoTUnref<const GrGeometryProcessor> gp;
     bool fullDash = devIntervals[1] > 0.f || useAA;
     if (fullDash) {
@@ -349,12 +425,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
         devInfo.fPhase = devPhase;
         devInfo.fCount = 2;
         devInfo.fIntervals = devIntervals;
-        GrPrimitiveEdgeType edgeType= useAA ? kFillAA_GrProcessorEdgeType :
+        GrPrimitiveEdgeType edgeType = useAA ? kFillAA_GrProcessorEdgeType :
             kFillBW_GrProcessorEdgeType;
-        bool isRoundCap = SkPaint::kRound_Cap == cap;
-        GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
-                                                        GrDashingEffect::kNonRound_DashCap;
-        gp.reset(GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType, invert));
+        gp.reset(create_dash_gp(color, edgeType, capType, invert));
     } else {
         // Set up the vertex data for the line and start/end dashes
         gp.reset(GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
@@ -397,10 +470,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
         bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY);
         bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
         if (fullDash) {
-            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices());
-            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex));
-            setup_dashed_rect(bounds, verts, curVIdx, combinedMatrix, startOffset, devBloat,
-                                      lineLength, halfDevStroke);
+            setup_dashed_rect(bounds, geo.vertices(), curVIdx, combinedMatrix, startOffset,
+                              devBloat, lineLength, halfDevStroke, devIntervals[0], devIntervals[1],
+                              strokeWidth, capType, gp->getVertexStride());
         } else {
             SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
             SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
@@ -413,10 +485,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
         SkASSERT(useAA);  // so that we know bloatX and bloatY have been set
         startRect.outset(bloatX, bloatY);
         if (fullDash) {
-            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices());
-            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex));
-            setup_dashed_rect(startRect, verts, curVIdx, combinedMatrix, startOffset, devBloat,
-                              devIntervals[0], halfDevStroke);
+            setup_dashed_rect(startRect, geo.vertices(), curVIdx, combinedMatrix, startOffset,
+                              devBloat, devIntervals[0], halfDevStroke, devIntervals[0],
+                              devIntervals[1], strokeWidth, capType, gp->getVertexStride());
         } else {
             SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
             SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
@@ -430,10 +501,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
         SkASSERT(useAA);  // so that we know bloatX and bloatY have been set
         endRect.outset(bloatX, bloatY);
         if (fullDash) {
-            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices());
-            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex));
-            setup_dashed_rect(endRect, verts, curVIdx, combinedMatrix, startOffset, devBloat,
-                              devIntervals[0], halfDevStroke);
+            setup_dashed_rect(endRect, geo.vertices(), curVIdx, combinedMatrix, startOffset,
+                              devBloat, devIntervals[0], halfDevStroke, devIntervals[0],
+                              devIntervals[1], strokeWidth, capType, gp->getVertexStride());
         } else {
             SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
             SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
@@ -474,8 +544,6 @@ public:
 
     static GrGeometryProcessor* Create(GrColor,
                                        GrPrimitiveEdgeType edgeType,
-                                       const DashInfo& info,
-                                       SkScalar radius,
                                        const SkMatrix& localMatrix);
 
     virtual ~DashingCircleEffect();
@@ -484,15 +552,11 @@ public:
 
     const Attribute* inPosition() const { return fInPosition; }
 
-    const Attribute* inCoord() const { return fInCoord; }
-
-    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
-
-    SkScalar getRadius() const { return fRadius; }
+    const Attribute* inDashParams() const { return fInDashParams; }
 
-    SkScalar getCenterX() const { return fCenterX; }
+    const Attribute* inCircleParams() const { return fInCircleParams; }
 
-    SkScalar getIntervalLength() const { return fIntervalLength; }
+    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
 
     virtual void getGLProcessorKey(const GrBatchTracker&,
                                    const GrGLCaps&,
@@ -508,19 +572,16 @@ public:
                         const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
-    DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
-                        SkScalar radius, const SkMatrix& localMatrix);
+    DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix);
 
     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
     void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
 
     GrPrimitiveEdgeType fEdgeType;
-    const Attribute*  fInPosition;
-    const Attribute*  fInCoord;
-    SkScalar            fIntervalLength;
-    SkScalar            fRadius;
-    SkScalar            fCenterX;
+    const Attribute*    fInPosition;
+    const Attribute*    fInDashParams;
+    const Attribute*    fInCircleParams;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 
@@ -566,21 +627,20 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
     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.
-    fParamUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                                         kVec3f_GrSLType, kDefault_GrSLPrecision,
-                                         "params", &paramName);
-
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
 
     // emit attributes
     vsBuilder->emitAttributes(dce);
 
-    GrGLVertToFrag v(kVec2f_GrSLType);
-    args.fPB->addVarying("Coord", &v);
-    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dce.inCoord()->fName);
+    // XY are dashPos, Z is dashInterval
+    GrGLVertToFrag dashParams(kVec3f_GrSLType);
+    args.fPB->addVarying("DashParam", &dashParams);
+    vsBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.inDashParams()->fName);
+
+    // xy, refer to circle radius - 0.5, z refers to cicles center x coord
+    GrGLVertToFrag circleParams(kVec2f_GrSLType);
+    args.fPB->addVarying("CircleParams", &circleParams);
+    vsBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.inCircleParams()->fName);
 
     // Setup pass through color
     this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
@@ -597,18 +657,19 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
 
     // transforms all points so that we can compare them to our test circle
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n",
-                           v.fsIn(), v.fsIn(), paramName, paramName);
-    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn());
-    fsBuilder->codeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName);
-    fsBuilder->codeAppend("\t\tfloat dist = length(center - fragPosShifted);\n");
+    fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
+                           dashParams.fsIn(), dashParams.fsIn(), dashParams.fsIn(),
+                           dashParams.fsIn());
+    fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", dashParams.fsIn());
+    fsBuilder->codeAppendf("vec2 center = vec2(%s.y, 0.0);", circleParams.fsIn());
+    fsBuilder->codeAppend("float dist = length(center - fragPosShifted);");
     if (GrProcessorEdgeTypeIsAA(dce.getEdgeType())) {
-        fsBuilder->codeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName);
-        fsBuilder->codeAppend("\t\tdiff = 1.0 - diff;\n");
-        fsBuilder->codeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n");
+        fsBuilder->codeAppendf("float diff = dist - %s.x;", circleParams.fsIn());
+        fsBuilder->codeAppend("diff = 1.0 - diff;");
+        fsBuilder->codeAppend("float alpha = clamp(diff, 0.0, 1.0);");
     } else {
-        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
-        fsBuilder->codeAppendf("\t\talpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName);
+        fsBuilder->codeAppendf("float alpha = 1.0;");
+        fsBuilder->codeAppendf("alpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;", circleParams.fsIn());
     }
     fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
 }
@@ -618,17 +679,6 @@ void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman,
                                     const GrBatchTracker& bt) {
     this->setUniformViewMatrix(pdman, processor.viewMatrix());
 
-    const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>();
-    SkScalar radius = dce.getRadius();
-    SkScalar centerX = dce.getCenterX();
-    SkScalar intervalLength = dce.getIntervalLength();
-    if (radius != fPrevRadius || centerX != fPrevCenterX || intervalLength != fPrevIntervalLength) {
-        pdman.set3f(fParamUniform, radius - 0.5f, centerX, intervalLength);
-        fPrevRadius = radius;
-        fPrevCenterX = centerX;
-        fPrevIntervalLength = intervalLength;
-    }
-
     const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
     if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
         GrGLfloat c[4];
@@ -655,14 +705,8 @@ void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp,
 
 GrGeometryProcessor* DashingCircleEffect::Create(GrColor color,
                                                  GrPrimitiveEdgeType edgeType,
-                                                 const DashInfo& info,
-                                                 SkScalar radius,
                                                  const SkMatrix& localMatrix) {
-    if (info.fCount != 2 || info.fIntervals[0] != 0) {
-        return NULL;
-    }
-
-    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, info, radius, localMatrix));
+    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, localMatrix));
 }
 
 DashingCircleEffect::~DashingCircleEffect() {}
@@ -684,26 +728,18 @@ GrGLPrimitiveProcessor* DashingCircleEffect::createGLInstance(const GrBatchTrack
 
 DashingCircleEffect::DashingCircleEffect(GrColor color,
                                          GrPrimitiveEdgeType edgeType,
-                                         const DashInfo& info,
-                                         SkScalar radius,
                                          const SkMatrix& localMatrix)
     : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) {
     this->initClassID<DashingCircleEffect>();
     fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
-    fInCoord = &this->addVertexAttrib(Attribute("inCoord", kVec2f_GrVertexAttribType));
-    SkScalar onLen = info.fIntervals[0];
-    SkScalar offLen = info.fIntervals[1];
-    fIntervalLength = onLen + offLen;
-    fRadius = radius;
-    fCenterX = SkScalarHalf(offLen);
+    fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType));
+    fInCircleParams = &this->addVertexAttrib(Attribute("inCircleParams",
+                                                       kVec2f_GrVertexAttribType));
 }
 
 bool DashingCircleEffect::onIsEqual(const GrGeometryProcessor& other) const {
     const DashingCircleEffect& dce = other.cast<DashingCircleEffect>();
-    return (fEdgeType == dce.fEdgeType &&
-            fIntervalLength == dce.fIntervalLength &&
-            fRadius == dce.fRadius &&
-            fCenterX == dce.fCenterX);
+    return fEdgeType == dce.fEdgeType;
 }
 
 void DashingCircleEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
@@ -731,18 +767,8 @@ GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random,
                                                      GrTexture*[]) {
     GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan(
             kGrProcessorEdgeTypeCnt));
-    SkScalar strokeWidth = random->nextRangeScalar(0, 100.f);
-    DashInfo info;
-    info.fCount = 2;
-    SkAutoTArray<SkScalar> intervals(info.fCount);
-    info.fIntervals = intervals.get();
-    info.fIntervals[0] = 0; 
-    info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
-    info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]);
-
     return DashingCircleEffect::Create(GrRandomColor(random),
-                                       edgeType, info, strokeWidth,
-                                       GrProcessorUnitTest::TestMatrix(random));
+                                       edgeType, GrProcessorUnitTest::TestMatrix(random));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -770,8 +796,6 @@ public:
 
     static GrGeometryProcessor* Create(GrColor,
                                        GrPrimitiveEdgeType edgeType,
-                                       const DashInfo& info,
-                                       SkScalar strokeWidth,
                                        const SkMatrix& localMatrix);
 
     virtual ~DashingLineEffect();
@@ -780,13 +804,11 @@ public:
 
     const Attribute* inPosition() const { return fInPosition; }
 
-    const Attribute* inCoord() const { return fInCoord; }
-
-    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
+    const Attribute* inDashParams() const { return fInDashParams; }
 
-    const SkRect& getRect() const { return fRect; }
+    const Attribute* inRectParams() const { return fInRectParams; }
 
-    SkScalar getIntervalLength() const { return fIntervalLength; }
+    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
 
     virtual void getGLProcessorKey(const GrBatchTracker& bt,
                                    const GrGLCaps& caps,
@@ -802,18 +824,16 @@ public:
                         const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
-    DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
-                      SkScalar strokeWidth, const SkMatrix& localMatrix);
+    DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix);
 
     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
     void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
 
     GrPrimitiveEdgeType fEdgeType;
-    const Attribute*  fInPosition;
-    const Attribute*  fInCoord;
-    SkRect              fRect;
-    SkScalar            fIntervalLength;
+    const Attribute*    fInPosition;
+    const Attribute*    fInDashParams;
+    const Attribute*    fInRectParams;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 
@@ -839,48 +859,35 @@ public:
 
 private:
     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::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
     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.
-    fRectUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                                       kVec4f_GrSLType, kDefault_GrSLPrecision,
-                                       "rect",
-                                       &rectName);
-    const char *intervalName;
-    // The interval uniform's refers to the total length of the interval (on + off)
-    fIntervalUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
-                                            kFloat_GrSLType, kDefault_GrSLPrecision,
-                                            "interval",
-                                            &intervalName);
-
 
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
 
     // emit attributes
     vsBuilder->emitAttributes(de);
 
-    GrGLVertToFrag v(kVec2f_GrSLType);
-    args.fPB->addVarying("Coord", &v);
-    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), de.inCoord()->fName);
+    // XY refers to dashPos, Z is the dash interval length
+    GrGLVertToFrag inDashParams(kVec3f_GrSLType);
+    args.fPB->addVarying("DashParams", &inDashParams);
+    vsBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.inDashParams()->fName);
+
+    // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
+    // respectively.
+    GrGLVertToFrag inRectParams(kVec4f_GrSLType);
+    args.fPB->addVarying("RectParams", &inRectParams);
+    vsBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.inRectParams()->fName);
 
     // Setup pass through color
     this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
@@ -897,25 +904,28 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
 
     // transforms all points so that we can compare them to our test rect
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n",
-                           v.fsIn(), v.fsIn(), intervalName, intervalName);
-    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn());
+    fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
+                           inDashParams.fsIn(), inDashParams.fsIn(), inDashParams.fsIn(),
+                           inDashParams.fsIn());
+    fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", inDashParams.fsIn());
     if (GrProcessorEdgeTypeIsAA(de.getEdgeType())) {
         // The amount of coverage removed in x and y by the edges is computed as a pair of negative
         // numbers, xSub and ySub.
-        fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
-        fsBuilder->codeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n", rectName);
-        fsBuilder->codeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n", rectName);
-        fsBuilder->codeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n", rectName);
-        fsBuilder->codeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n", rectName);
+        fsBuilder->codeAppend("float xSub, ySub;");
+        fsBuilder->codeAppendf("xSub = min(fragPosShifted.x - %s.x, 0.0);", inRectParams.fsIn());
+        fsBuilder->codeAppendf("xSub += min(%s.z - fragPosShifted.x, 0.0);", inRectParams.fsIn());
+        fsBuilder->codeAppendf("ySub = min(fragPosShifted.y - %s.y, 0.0);", inRectParams.fsIn());
+        fsBuilder->codeAppendf("ySub += min(%s.w - fragPosShifted.y, 0.0);", inRectParams.fsIn());
         // Now compute coverage in x and y and multiply them to get the fraction of the pixel
         // covered.
-        fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
+        fsBuilder->codeAppendf("float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));");
     } else {
         // Assuming the bounding geometry is tight so no need to check y values
-        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
-        fsBuilder->codeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName);
-        fsBuilder->codeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;\n", rectName);
+        fsBuilder->codeAppendf("float alpha = 1.0;");
+        fsBuilder->codeAppendf("alpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;",
+                               inRectParams.fsIn());
+        fsBuilder->codeAppendf("alpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;",
+                               inRectParams.fsIn());
     }
     fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
 }
@@ -925,17 +935,6 @@ void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman,
                                   const GrBatchTracker& bt) {
     this->setUniformViewMatrix(pdman, processor.viewMatrix());
 
-    const DashingLineEffect& de = processor.cast<DashingLineEffect>();
-    const SkRect& rect = de.getRect();
-    SkScalar intervalLength = de.getIntervalLength();
-    if (rect != fPrevRect || intervalLength != fPrevIntervalLength) {
-        pdman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f,
-                    rect.fRight - 0.5f, rect.fBottom - 0.5f);
-        pdman.set1f(fIntervalUniform, intervalLength);
-        fPrevRect = rect;
-        fPrevIntervalLength = intervalLength;
-    }
-
     const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
     if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
         GrGLfloat c[4];
@@ -962,14 +961,8 @@ void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp,
 
 GrGeometryProcessor* DashingLineEffect::Create(GrColor color,
                                                GrPrimitiveEdgeType edgeType,
-                                               const DashInfo& info,
-                                               SkScalar strokeWidth,
                                                const SkMatrix& localMatrix) {
-    if (info.fCount != 2) {
-        return NULL;
-    }
-
-    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, info, strokeWidth, localMatrix));
+    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, localMatrix));
 }
 
 DashingLineEffect::~DashingLineEffect() {}
@@ -991,26 +984,17 @@ GrGLPrimitiveProcessor* DashingLineEffect::createGLInstance(const GrBatchTracker
 
 DashingLineEffect::DashingLineEffect(GrColor color,
                                      GrPrimitiveEdgeType edgeType,
-                                     const DashInfo& info,
-                                     SkScalar strokeWidth,
                                      const SkMatrix& localMatrix)
     : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) {
     this->initClassID<DashingLineEffect>();
     fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
-    fInCoord = &this->addVertexAttrib(Attribute("inCoord", kVec2f_GrVertexAttribType));
-    SkScalar onLen = info.fIntervals[0];
-    SkScalar offLen = info.fIntervals[1];
-    SkScalar halfOffLen = SkScalarHalf(offLen);
-    SkScalar halfStroke = SkScalarHalf(strokeWidth);
-    fIntervalLength = onLen + offLen;
-    fRect.set(halfOffLen, -halfStroke, halfOffLen + onLen, halfStroke);
+    fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType));
+    fInRectParams = &this->addVertexAttrib(Attribute("inRect", kVec4f_GrVertexAttribType));
 }
 
 bool DashingLineEffect::onIsEqual(const GrGeometryProcessor& other) const {
     const DashingLineEffect& de = other.cast<DashingLineEffect>();
-    return (fEdgeType == de.fEdgeType &&
-            fRect == de.fRect &&
-            fIntervalLength == de.fIntervalLength);
+    return fEdgeType == de.fEdgeType;
 }
 
 void DashingLineEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
@@ -1038,35 +1022,22 @@ GrGeometryProcessor* DashingLineEffect::TestCreate(SkRandom* random,
                                                    GrTexture*[]) {
     GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan(
             kGrProcessorEdgeTypeCnt));
-    SkScalar strokeWidth = random->nextRangeScalar(0, 100.f);
-    DashInfo info;
-    info.fCount = 2;
-    SkAutoTArray<SkScalar> intervals(info.fCount);
-    info.fIntervals = intervals.get();
-    info.fIntervals[0] = random->nextRangeScalar(0, 10.f);
-    info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
-    info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fIntervals[1]);
 
     return DashingLineEffect::Create(GrRandomColor(random),
-                                     edgeType, info, strokeWidth,
-                                     GrProcessorUnitTest::TestMatrix(random));
+                                     edgeType, GrProcessorUnitTest::TestMatrix(random));
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
-GrGeometryProcessor* GrDashingEffect::Create(GrColor color,
-                                             GrPrimitiveEdgeType edgeType,
-                                             const SkPathEffect::DashInfo& info,
-                                             SkScalar strokeWidth,
-                                             GrDashingEffect::DashCap cap,
-                                             const SkMatrix& localMatrix) {
+static GrGeometryProcessor* create_dash_gp(GrColor color,
+                                           GrPrimitiveEdgeType edgeType,
+                                           DashCap cap,
+                                           const SkMatrix& localMatrix) {
     switch (cap) {
-        case GrDashingEffect::kRound_DashCap:
-            return DashingCircleEffect::Create(color, edgeType, info,
-                                               SkScalarHalf(strokeWidth),
-                                               localMatrix);
-        case GrDashingEffect::kNonRound_DashCap:
-            return DashingLineEffect::Create(color, edgeType, info, strokeWidth, localMatrix);
+        case kRound_DashCap:
+            return DashingCircleEffect::Create(color, edgeType, localMatrix);
+        case kNonRound_DashCap:
+            return DashingLineEffect::Create(color, edgeType, localMatrix);
         default:
             SkFAIL("Unexpected dashed cap.");
     }
index 5552f1d..b8cb826 100644 (file)
 
 class GrGpu;
 class GrDrawTarget;
-class GrGeometryProcessor;
 class GrPaint;
 class GrPipelineBuilder;
 class GrStrokeInfo;
 
-class GrGLDashingEffect;
-class SkPath;
-
 namespace GrDashingEffect {
     bool DrawDashLine(GrGpu*, GrDrawTarget*, GrPipelineBuilder*, GrColor,
                       const SkMatrix& viewMatrix, const SkPoint pts[2], const GrPaint& paint,
                       const GrStrokeInfo& strokeInfo);
-
-    enum DashCap {
-        kRound_DashCap,
-        kNonRound_DashCap,
-    };
-
-    /**
-     * An effect that renders a dashed line. It is intended to be used as a coverage effect.
-     * The effect is meant for dashed lines that only have a single on/off interval pair.
-     * Bounding geometry is rendered and the effect computes coverage based on the fragment's
-     * position relative to the dashed line.
-     */
-    GrGeometryProcessor* Create(GrColor,
-                                GrPrimitiveEdgeType edgeType,
-                                const SkPathEffect::DashInfo& info,
-                                SkScalar strokeWidth,
-                                DashCap cap,
-                                const SkMatrix& localMatrix);
 }
 
 #endif