Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: src/gpu/SkGpuDevice.cpp

Issue 274673004: Add Dashing gpu effect for simple dashed lines (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add missing files Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « samplecode/SampleApp.cpp ('k') | src/gpu/effects/GrDashingEffect.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkGpuDevice.h" 8 #include "SkGpuDevice.h"
9 9
10 #include "effects/GrBicubicEffect.h" 10 #include "effects/GrBicubicEffect.h"
11 #include "effects/GrDashingEffect.h"
11 #include "effects/GrTextureDomain.h" 12 #include "effects/GrTextureDomain.h"
12 #include "effects/GrSimpleTextureEffect.h" 13 #include "effects/GrSimpleTextureEffect.h"
13 14
14 #include "GrContext.h" 15 #include "GrContext.h"
15 #include "GrBitmapTextContext.h" 16 #include "GrBitmapTextContext.h"
16 #include "GrDistanceFieldTextContext.h" 17 #include "GrDistanceFieldTextContext.h"
17 #include "GrLayerCache.h" 18 #include "GrLayerCache.h"
18 #include "GrPictureUtils.h" 19 #include "GrPictureUtils.h"
19 20
20 #include "SkGrTexturePixelRef.h" 21 #include "SkGrTexturePixelRef.h"
(...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 529 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
529 size_t count, const SkPoint pts[], const SkPaint& p aint) { 530 size_t count, const SkPoint pts[], const SkPaint& p aint) {
530 CHECK_FOR_ANNOTATION(paint); 531 CHECK_FOR_ANNOTATION(paint);
531 CHECK_SHOULD_DRAW(draw, false); 532 CHECK_SHOULD_DRAW(draw, false);
532 533
533 SkScalar width = paint.getStrokeWidth(); 534 SkScalar width = paint.getStrokeWidth();
534 if (width < 0) { 535 if (width < 0) {
535 return; 536 return;
536 } 537 }
537 538
539 if (paint.getPathEffect() && 2 == count) {
540 if (this->drawDash(pts, paint, mode)) {
541 return;
542 }
543 }
544
538 // we only handle hairlines and paints without path effects or mask filters, 545 // we only handle hairlines and paints without path effects or mask filters,
539 // else we let the SkDraw call our drawPath() 546 // else we let the SkDraw call our drawPath()
540 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { 547 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
541 draw.drawPoints(mode, count, pts, paint, true); 548 draw.drawPoints(mode, count, pts, paint, true);
542 return; 549 return;
543 } 550 }
544 551
545 GrPaint grPaint; 552 GrPaint grPaint;
546 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 553 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
547 return; 554 return;
548 } 555 }
549 556
550 fContext->drawVertices(grPaint, 557 fContext->drawVertices(grPaint,
551 gPointMode2PrimtiveType[mode], 558 gPointMode2PrimtiveType[mode],
552 SkToS32(count), 559 SkToS32(count),
553 (SkPoint*)pts, 560 (SkPoint*)pts,
554 NULL, 561 NULL,
555 NULL, 562 NULL,
556 NULL, 563 NULL,
557 0); 564 0);
558 } 565 }
559 566
560 /////////////////////////////////////////////////////////////////////////////// 567 ///////////////////////////////////////////////////////////////////////////////
561 568
569 static void calcDashScaling(SkScalar* parallelScale, SkScalar* perpScale,
bsalomon 2014/05/09 15:02:37 style nit: we've been tending towards naming_stati
egdaniel 2014/05/12 19:21:44 fixed On 2014/05/09 15:02:37, bsalomon wrote:
570 const SkMatrix& viewMatrix, const SkPoint pts[2]) {
571 SkVector vecSrc = pts[1] - pts[0];
572 SkScalar magSrc = vecSrc.length();
573 SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0;
574 vecSrc.scale(invSrc);
575
576 SkVector vecSrcPerp;
577 vecSrc.rotateCW(&vecSrcPerp);
578 viewMatrix.mapVectors(&vecSrc, 1);
579 viewMatrix.mapVectors(&vecSrcPerp, 1);
580
581 // parallelScale tells how much to scale along the line parallel to the dash line
582 // perpScale tells how much to scale in the direction perpendicular to the d ash line
583 *parallelScale = vecSrc.length();
584 *perpScale = vecSrcPerp.length();
585 }
586
587 // calculates the rotation needed to aligned pts to the x axis with pts[0] < pts [1]
588 // Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot
589 static void alignToXAxis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsR ot[2] = NULL) {
590 SkVector vec = pts[1] - pts[0];
591 SkScalar mag = vec.length();
592 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
593
594 vec.scale(inv);
595 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
596 if (ptsRot) {
597 rotMatrix->mapPoints(ptsRot, pts, 2);
598 // correction for numerical issues if map doesn't make ptsRot exactly ho rizontal
599 ptsRot[1].fY = pts[0].fY;
600 }
601 }
602
603 // Assumes phase < sum of all intervals
bsalomon 2014/05/09 15:02:37 is that a valid assumption? add an assert?
egdaniel 2014/05/12 19:21:44 In the creation of SkDashEffect the phase is norma
604 static SkScalar calcStartAdjustment(const SkPathEffect::DashInfo& info) {
605 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
bsalomon 2014/05/09 15:02:37 don't need this until inside both ifs, right?
egdaniel 2014/05/12 19:21:44 yup On 2014/05/09 15:02:37, bsalomon wrote:
606 if (info.fPhase >= info.fIntervals[0]) {
607 if (info.fIntervals[0] !=0 || info.fPhase != 0) {
bsalomon 2014/05/09 15:02:37 if intervals[0] is != 0 then phase can't be either
egdaniel 2014/05/12 19:21:44 Ahh you're right. I was just inverting the logic i
608 return srcIntervalLen - info.fPhase;
609 }
610 }
611 return 0;
612 }
613
614 static SkScalar calcEndAdjustment(const SkPathEffect::DashInfo& info, const SkPo int pts[2]) {
615 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
616 SkScalar totalLen = pts[1].fX - pts[0].fY;
617 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen);
618 SkScalar numFullIntervals = SkScalarFloorToScalar(temp);
619 SkScalar endingInt = totalLen - numFullIntervals * srcIntervalLen + info.fPh ase;
620 temp = SkScalarDiv(endingInt, srcIntervalLen);
621 endingInt = endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen;
622 if (0 == endingInt) {
623 endingInt = srcIntervalLen;
624 }
625 if (endingInt > info.fIntervals[0]) {
626 if (0 == info.fIntervals[0]) {
627 endingInt -= 0.01; // make sure we capture the last zero size pnt (u sed if has caps)
628 }
629 return endingInt - info.fIntervals[0];
630 }
631 return 0;
632 }
633
634 bool SkGpuDevice::drawDash(const SkPoint pts[2], const SkPaint& paint, SkCanvas: :PointMode mode) {
bsalomon 2014/05/09 15:02:37 maybe this should be called drawDashedLine()? It o
egdaniel 2014/05/12 19:21:44 Name changed. Moved the mode check to the caller.
635 if (SkCanvas::kLines_PointMode != mode) {
636 return false;
637 }
638
639 const SkMatrix& viewMatrix = fContext->getMatrix();
640 if (!viewMatrix.preservesRightAngles()) {
641 return false;
642 }
643
644 const SkPathEffect* pe = paint.getPathEffect();
645 SkPathEffect::DashInfo info;
646 SkPathEffect::DashType dashType = pe->asADash(&info);
647 // Must be a dash effect with 2 intervals (1 on and 1 off)
648 if (SkPathEffect::kDash_DashType != dashType || 2 != info.fCount) {
649 return false;
650 }
651
652 GrPaint grPaint;
bsalomon 2014/05/09 15:02:37 maybe hold off on this until after your cap check?
egdaniel 2014/05/12 19:21:44 done On 2014/05/09 15:02:37, bsalomon wrote:
653 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
654 return false;
655 }
656
657 SkPaint::Cap cap = paint.getStrokeCap();
658 // Current we do don't handle Round or Square cap dashes
659 if (SkPaint::kRound_Cap == cap) {
660 return false;
661 }
662
663 SkScalar srcStrokeWidth = paint.getStrokeWidth();
664
665 // Get all info about the dash effect
666 SkAutoTArray<SkScalar> intervals(info.fCount);
667 info.fIntervals = intervals.get();
668 pe->asADash(&info);
669
670 SkMatrix coordTrans;
671
672 // If the src pts are not axis aligned, rotate them so that they are horizon tal
673 SkMatrix srcRotInv;
674 SkPoint ptsRot[2];
675 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
676 alignToXAxis(pts, &coordTrans, ptsRot);
677 if(!coordTrans.invert(&srcRotInv)) {
678 return false;
679 }
680 } else {
681 coordTrans.reset();
682 srcRotInv.reset();
683 ptsRot[0] = pts[0];
684 ptsRot[1] = pts[1];
685 }
686
687 // adjustments for start and end of bounding rect so we only draw dash inter vals
688 // contained in the original line segment.
689 // TODO: what happens if adjustments make degenerate line?
bsalomon 2014/05/09 15:02:37 Can these conditions cause us to draw incorrectly
egdaniel 2014/05/12 19:21:44 Changed so that if the first or last dashes in the
690 // TODO: since we are using the bounding geometry to clip off bad parts, we now
691 // loss so AA that happens on end of dash segment. Better to draw first and last
692 // rects separately and use shader on middle?
693 SkScalar startAdj = calcStartAdjustment(info);
694 SkScalar endAdj = calcEndAdjustment(info, ptsRot);
695
696 coordTrans.postConcat(viewMatrix);
697
698 SkPoint devicePts[2];
699 viewMatrix.mapPoints(devicePts, ptsRot, 2);
700
701 // Scale corrections of intervals and stroke from view matrix
702 SkScalar parallelScale;
703 SkScalar perpScale;
704 calcDashScaling(&parallelScale, &perpScale, viewMatrix, ptsRot);
705 info.fIntervals[0] *= parallelScale;
706 info.fIntervals[1] *= parallelScale;
707 info.fPhase *= parallelScale;
708 SkScalar strokeWidth = srcStrokeWidth * perpScale;
709
710 bool useAA = paint.isAntiAlias();
711 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
712 strokeWidth = 1.f;
713 }
714
715 // Set up coordTransform for device space transforms
716 // We rotate the dashed line such that it is horizontal with the start point at smaller x
717 // then we translate the start point to the origin
718 if (devicePts[0].fY != devicePts[1].fY || devicePts[0].fX > devicePts[1].fX) {
719 SkMatrix rot;
720 alignToXAxis(devicePts, &rot);
721 coordTrans.postConcat(rot);
722 }
723 coordTrans.postTranslate(-devicePts[0].fX, -devicePts[0].fY);
724 coordTrans.postTranslate(info.fIntervals[1] * 0.5f + info.fPhase, 0);
725
726 bool hasCap = false;
727 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) {
728 // add cap to on interveal and remove from off interval
729 info.fIntervals[0] += strokeWidth;
730 info.fIntervals[1] -= strokeWidth;
731 hasCap = true;
732 }
733
734 if (info.fIntervals[1] > 0.f) {
735 GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType :
736 kFillBW_GrEffectEdgeType;
737 grPaint.addCoverageEffect(GrDashingEffect::Create(edgeType, info, coordT rans, strokeWidth));
738 grPaint.setAntiAlias(false);
739 }
740
741 // We always want to at least stroke out half a pixel on each side in device space
742 // so 0.5f / perpScale gives us this min in src space
743 SkScalar halfStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale);
744
745 SkRect rect;
746 bool bloat = useAA && info.fIntervals[1] > 0.f;
747 SkScalar bloatX = bloat ? 0.5f / parallelScale : 0.f;
748 SkScalar bloatY = bloat ? 0.5f / perpScale : 0.f;
749 SkScalar xStroke;
750 SkScalar yStroke;
751 if (!hasCap) {
752 bool horiz = ptsRot[0].fY == ptsRot[1].fY;
753 xStroke = horiz ? 0.f : halfStroke;
754 yStroke = horiz ? halfStroke : 0.f;
755 } else {
756 xStroke = halfStroke;
757 yStroke = halfStroke;
758 }
759 ptsRot[0].fX += startAdj;
760 ptsRot[1].fX -= endAdj;
761 rect.set(ptsRot, 2);
762 rect.outset(bloatX + xStroke, bloatY + yStroke);
763 fContext->drawRect(grPaint, rect, NULL, &srcRotInv);
764
765 return true;
766 }
767
768 ///////////////////////////////////////////////////////////////////////////////
769
562 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, 770 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
563 const SkPaint& paint) { 771 const SkPaint& paint) {
564 CHECK_FOR_ANNOTATION(paint); 772 CHECK_FOR_ANNOTATION(paint);
565 CHECK_SHOULD_DRAW(draw, false); 773 CHECK_SHOULD_DRAW(draw, false);
566 774
567 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 775 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
568 SkScalar width = paint.getStrokeWidth(); 776 SkScalar width = paint.getStrokeWidth();
569 777
570 /* 778 /*
571 We have special code for hairline strokes, miter-strokes, bevel-stroke 779 We have special code for hairline strokes, miter-strokes, bevel-stroke
(...skipping 1548 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i); 2328 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i);
2121 2329
2122 if (NULL != layer->getTexture()) { 2330 if (NULL != layer->getTexture()) {
2123 fContext->unlockScratchTexture(layer->getTexture()); 2331 fContext->unlockScratchTexture(layer->getTexture());
2124 layer->setTexture(NULL); 2332 layer->setTexture(NULL);
2125 } 2333 }
2126 } 2334 }
2127 2335
2128 return true; 2336 return true;
2129 } 2337 }
OLDNEW
« no previous file with comments | « samplecode/SampleApp.cpp ('k') | src/gpu/effects/GrDashingEffect.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698