Chromium Code Reviews| Index: src/gpu/effects/GrDashingEffect.cpp |
| diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp |
| index 8d9c08f3f38d943c34fec4698a3caa6886a322cc..599576a7d71898b1485f193fff2d8d120dd266ce 100644 |
| --- a/src/gpu/effects/GrDashingEffect.cpp |
| +++ b/src/gpu/effects/GrDashingEffect.cpp |
| @@ -54,7 +54,7 @@ static bool can_fast_path_dash(const SkPoint pts[2], const GrStrokeInfo& strokeI |
| SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap(); |
| // Current we do don't handle Round or Square cap dashes |
| - if (SkPaint::kRound_Cap == cap) { |
| + if (SkPaint::kRound_Cap == cap && info.fIntervals[0] != 0.f) { |
| return false; |
| } |
| @@ -204,7 +204,7 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
| SkScalar perpScale; |
| calc_dash_scaling(¶llelScale, &perpScale, vm, ptsRot); |
| - bool hasCap = SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth; |
| + bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth; |
| // We always want to at least stroke out half a pixel on each side in device space |
| // so 0.5f / perpScale gives us this min in src space |
| @@ -341,8 +341,9 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
| devInfo.fIntervals = devIntervals; |
| GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType : |
| kFillBW_GrEffectEdgeType; |
| + bool isRoundCap = SkPaint::kRound_Cap == cap && srcStrokeWidth != 0; |
| drawState->addCoverageEffect( |
| - GrDashingEffect::Create(edgeType, devInfo, strokeWidth), 1)->unref(); |
| + GrDashingEffect::Create(edgeType, devInfo, strokeWidth, isRoundCap), 1)->unref(); |
| } |
| // Set up the vertex data for the line and start/end dashes |
| @@ -364,6 +365,11 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
| int curVIdx = 0; |
| + if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) { |
| + // need to adjust this for round caps to correctly set the dashPos attrib on vertices |
| + startOffset -= halfDevStroke; |
| + } |
| + |
| // Draw interior part of dashed line |
| if (!lineDone) { |
| SkPoint devicePts[2]; |
| @@ -404,6 +410,217 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
| ////////////////////////////////////////////////////////////////////////////// |
| +class GLDashingCircleEffect; |
| + |
| +class DashingCircleEffect : public GrVertexEffect { |
| +public: |
| + typedef SkPathEffect::DashInfo DashInfo; |
| + |
| + /** |
| + * The effect calculates the coverage for the case of a horizontal line in device space. |
| + * The matrix that is passed in should be able to convert a line in source space to a |
| + * horizontal line in device space. Additionally, the coord transform matrix should translate |
| + * the the start of line to origin, and the shift it along the positive x-axis by the phase |
| + * and half the off interval. |
| + */ |
| + static GrEffectRef* Create(GrEffectEdgeType edgeType, const DashInfo& info, |
| + SkScalar strokeWidth); |
| + |
| + virtual ~DashingCircleEffect(); |
| + |
| + static const char* Name() { return "DashingCircleEffect"; } |
| + |
| + GrEffectEdgeType getEdgeType() const { return fEdgeType; } |
| + |
| + SkScalar getRadius() const { return fRadius; } |
| + |
| + SkScalar getCenterX() const { return fCenterX; } |
| + |
| + SkScalar getIntervalLength() const { return fIntervalLength; } |
| + |
| + typedef GLDashingCircleEffect GLEffect; |
| + |
| + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; |
| + |
| + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
| + |
| +private: |
| + DashingCircleEffect(GrEffectEdgeType edgeType, const DashInfo& info, SkScalar strokeWidth); |
| + |
| + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; |
| + |
| + GrEffectEdgeType fEdgeType; |
| + SkScalar fIntervalLength; |
| + SkScalar fRadius; |
| + SkScalar fCenterX; |
| + |
| + GR_DECLARE_EFFECT_TEST; |
| + |
| + typedef GrVertexEffect INHERITED; |
| +}; |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| +class GLDashingCircleEffect : public GrGLVertexEffect { |
| +public: |
| + GLDashingCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&); |
| + |
| + virtual void emitCode(GrGLFullShaderBuilder* builder, |
| + const GrDrawEffect& drawEffect, |
| + EffectKey key, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray&, |
| + const TextureSamplerArray&) SK_OVERRIDE; |
| + |
| + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); |
| + |
| + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
| + |
| +private: |
| + GrGLUniformManager::UniformHandle fParamUniform; |
| + SkScalar fPrevRadius; |
| + SkScalar fPrevCenterX; |
| + SkScalar fPrevIntervalLength; |
| + typedef GrGLVertexEffect INHERITED; |
| +}; |
| + |
| +GLDashingCircleEffect::GLDashingCircleEffect(const GrBackendEffectFactory& factory, |
| + const GrDrawEffect& drawEffect) |
| + : INHERITED (factory) { |
| + fPrevRadius = SK_ScalarMin; |
| + fPrevCenterX = SK_ScalarMin; |
| + fPrevIntervalLength = SK_ScalarMax; |
| +} |
| + |
| +void GLDashingCircleEffect::emitCode(GrGLFullShaderBuilder* builder, |
| + const GrDrawEffect& drawEffect, |
| + EffectKey key, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TransformedCoordsArray&, |
| + const TextureSamplerArray& samplers) { |
| + const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
| + 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 = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| + kVec3f_GrSLType, |
| + "params", |
| + ¶mName); |
| + |
| + const char *vsCoordName, *fsCoordName; |
| + builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName); |
| + const SkString* attr0Name = |
| + builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
| + builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str()); |
| + |
| + // transforms all points so that we can compare them to our test rect |
|
bsalomon
2014/06/25 14:20:44
test circle?
|
| + builder->fsCodeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n", |
| + fsCoordName, fsCoordName, paramName, paramName); |
| + builder->fsCodeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName); |
| + builder->fsCodeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName); |
| + builder->fsCodeAppend("\t\tfloat dist = length(center - fragPosShifted);\n"); |
| + if (GrEffectEdgeTypeIsAA(dce.getEdgeType())) { |
| + // The amount of coverage removed in x and y by the edges is computed as a pair of negative |
|
bsalomon
2014/06/25 14:20:44
This comment should be removed right?
|
| + // numbers, xSub and ySub. |
| + builder->fsCodeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName); |
| + builder->fsCodeAppend("\t\tdiff = 1 - diff;\n"); |
| + builder->fsCodeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n"); |
| + } else { |
| + // Assuming the bounding geometry is tight so no need to check y values |
| + builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n"); |
| + builder->fsCodeAppendf("\t\talpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName); |
| + } |
| + builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, |
| + (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); |
| +} |
| + |
| +void GLDashingCircleEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { |
| + const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
| + SkScalar radius = dce.getRadius(); |
| + SkScalar centerX = dce.getCenterX(); |
| + SkScalar intervalLength = dce.getIntervalLength(); |
| + if (radius != fPrevRadius || centerX != fPrevCenterX || intervalLength != fPrevIntervalLength) { |
| + uman.set3f(fParamUniform, radius - 0.5f, centerX, intervalLength); |
| + fPrevRadius = radius; |
| + fPrevCenterX = centerX; |
| + fPrevIntervalLength = intervalLength; |
| + } |
| +} |
| + |
| +GrGLEffect::EffectKey GLDashingCircleEffect::GenKey(const GrDrawEffect& drawEffect, |
| + const GrGLCaps&) { |
| + const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
| + return dce.getEdgeType(); |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| +GrEffectRef* DashingCircleEffect::Create(GrEffectEdgeType edgeType, const DashInfo& info, |
| + SkScalar strokeWidth) { |
| + if (info.fCount != 2 || info.fIntervals[0] != 0) { |
| + return NULL; |
| + } |
| + |
| + return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(DashingCircleEffect, |
| + (edgeType, info, strokeWidth)))); |
| +} |
| + |
| +DashingCircleEffect::~DashingCircleEffect() {} |
| + |
| +void DashingCircleEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
| + *validFlags = 0; |
| +} |
| + |
| +const GrBackendEffectFactory& DashingCircleEffect::getFactory() const { |
| + return GrTBackendEffectFactory<DashingCircleEffect>::getInstance(); |
| +} |
| + |
| +DashingCircleEffect::DashingCircleEffect(GrEffectEdgeType edgeType, const DashInfo& info, |
| + SkScalar strokeWidth) |
| + : fEdgeType(edgeType) { |
| + SkScalar onLen = info.fIntervals[0]; |
| + SkScalar offLen = info.fIntervals[1]; |
| + fIntervalLength = onLen + offLen; |
| + fRadius = SkScalarHalf(strokeWidth); |
| + fCenterX = SkScalarHalf(offLen); |
| + |
| + this->addVertexAttrib(kVec2f_GrSLType); |
| +} |
| + |
| +bool DashingCircleEffect::onIsEqual(const GrEffect& other) const { |
| + const DashingCircleEffect& dce = CastEffect<DashingCircleEffect>(other); |
| + return (fEdgeType == dce.fEdgeType && |
| + fIntervalLength == dce.fIntervalLength && |
| + fRadius == dce.fRadius && |
| + fCenterX == dce.fCenterX); |
| +} |
| + |
| +GR_DEFINE_EFFECT_TEST(DashingCircleEffect); |
| + |
| +GrEffectRef* DashingCircleEffect::TestCreate(SkRandom* random, |
| + GrContext*, |
| + const GrDrawTargetCaps& caps, |
| + GrTexture*[]) { |
| + GrEffectRef* effect; |
| + GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(random->nextULessThan( |
| + kGrEffectEdgeTypeCnt)); |
| + 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]); |
| + |
| + effect = DashingCircleEffect::Create(edgeType, info, strokeWidth); |
| + return effect; |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| class GLDashingLineEffect; |
| class DashingLineEffect : public GrVertexEffect { |
| @@ -447,7 +664,7 @@ private: |
| GR_DECLARE_EFFECT_TEST; |
| - typedef GrEffect INHERITED; |
| + typedef GrVertexEffect INHERITED; |
| }; |
| ////////////////////////////////////////////////////////////////////////////// |
| @@ -481,7 +698,6 @@ GLDashingLineEffect::GLDashingLineEffect(const GrBackendEffectFactory& factory, |
| : INHERITED (factory) { |
| fPrevRect.fLeft = SK_ScalarNaN; |
| fPrevIntervalLength = SK_ScalarMax; |
| - |
| } |
| void GLDashingLineEffect::emitCode(GrGLFullShaderBuilder* builder, |
| @@ -623,6 +839,10 @@ GrEffectRef* DashingLineEffect::TestCreate(SkRandom* random, |
| ////////////////////////////////////////////////////////////////////////////// |
| GrEffectRef* GrDashingEffect::Create(GrEffectEdgeType edgeType, const SkPathEffect::DashInfo& info, |
| - SkScalar strokeWidth) { |
| + SkScalar strokeWidth, bool isRoundCaps) { |
| + if (isRoundCaps) { |
| + return DashingCircleEffect::Create(edgeType, info, strokeWidth); |
| + //return NULL; |
| + } |
| return DashingLineEffect::Create(edgeType, info, strokeWidth); |
| } |