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

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

Issue 2134693002: Reland of Better encapsulate oval/rrect batchs. (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: Created 4 years, 5 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 | « src/gpu/GrOvalRenderer.h ('k') | no next file » | 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 2013 Google Inc. 2 * Copyright 2013 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 "GrOvalRenderer.h" 8 #include "GrOvalRenderer.h"
9 9
10 #include "GrBatchFlushState.h" 10 #include "GrBatchFlushState.h"
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor); 517 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor);
518 518
519 sk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTes tData* d) { 519 sk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTes tData* d) {
520 return sk_sp<GrGeometryProcessor>( 520 return sk_sp<GrGeometryProcessor>(
521 new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom), 521 new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom),
522 (DIEllipseStyle)(d->fRandom->nextRangeU(0 ,2)))); 522 (DIEllipseStyle)(d->fRandom->nextRangeU(0 ,2))));
523 } 523 }
524 524
525 /////////////////////////////////////////////////////////////////////////////// 525 ///////////////////////////////////////////////////////////////////////////////
526 526
527 GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
528 const SkMatrix& viewMatrix,
529 const SkRect& oval,
530 const SkStrokeRec& stroke,
531 GrShaderCaps* shaderCaps) {
532 // we can draw circles
533 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle( viewMatrix)) {
534 return CreateCircleBatch(color, viewMatrix, oval, stroke);
535 }
536
537 // if we have shader derivative support, render as device-independent
538 if (shaderCaps->shaderDerivativeSupport()) {
539 return CreateDIEllipseBatch(color, viewMatrix, oval, stroke);
540 }
541
542 // otherwise axis-aligned ellipses only
543 if (viewMatrix.rectStaysRect()) {
544 return CreateEllipseBatch(color, viewMatrix, oval, stroke);
545 }
546
547 return nullptr;
548 }
549
550 ///////////////////////////////////////////////////////////////////////////////
551
552 class CircleBatch : public GrVertexBatch { 527 class CircleBatch : public GrVertexBatch {
553 public: 528 public:
554 DEFINE_BATCH_CLASS_ID 529 DEFINE_BATCH_CLASS_ID
555 530
556 struct Geometry { 531 CircleBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& circle,
557 SkRect fDevBounds; 532 const SkStrokeRec& stroke)
558 SkScalar fInnerRadius; 533 : INHERITED(ClassID())
559 SkScalar fOuterRadius; 534 , fViewMatrixIfUsingLocalCoords(viewMatrix) {
560 GrColor fColor; 535 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
561 }; 536 viewMatrix.mapPoints(&center, 1);
537 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
538 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
562 539
563 CircleBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool strok ed) 540 SkStrokeRec::Style style = stroke.getStyle();
564 : INHERITED(ClassID()) 541 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
565 , fStroked(stroked) 542 SkStrokeRec::kHairline_Style == style;
566 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 543 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == st yle;
567 fGeoData.push_back(geometry); 544
568 this->setBounds(geometry.fDevBounds); 545 SkScalar innerRadius = 0.0f;
546 SkScalar outerRadius = radius;
547 SkScalar halfWidth = 0;
548 if (hasStroke) {
549 if (SkScalarNearlyZero(strokeWidth)) {
550 halfWidth = SK_ScalarHalf;
551 } else {
552 halfWidth = SkScalarHalf(strokeWidth);
553 }
554
555 outerRadius += halfWidth;
556 if (isStrokeOnly) {
557 innerRadius = radius - halfWidth;
558 }
559 }
560
561 // The radii are outset for two reasons. First, it allows the shader to simply perform
562 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
563 // Second, the outer radius is used to compute the verts of the bounding box that is
564 // rendered and the outset ensures the box will cover all partially cove red by the circle.
565 outerRadius += SK_ScalarHalf;
566 innerRadius -= SK_ScalarHalf;
567
568 fGeoData.emplace_back(Geometry {
569 color,
570 innerRadius,
571 outerRadius,
572 SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
573 center.fX + outerRadius, center.fY + outerRadius)
574 });
575 this->setBounds(fGeoData.back().fDevBounds);
576 fStroked = isStrokeOnly && innerRadius > 0;
569 } 577 }
578
570 const char* name() const override { return "CircleBatch"; } 579 const char* name() const override { return "CircleBatch"; }
571 580
572 SkString dumpInfo() const override { 581 SkString dumpInfo() const override {
573 SkString string; 582 SkString string;
574 for (int i = 0; i < fGeoData.count(); ++i) { 583 for (int i = 0; i < fGeoData.count(); ++i) {
575 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %. 2f]," 584 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %. 2f],"
576 "InnerRad: %.2f, OuterRad: %.2f\n", 585 "InnerRad: %.2f, OuterRad: %.2f\n",
577 fGeoData[i].fColor, 586 fGeoData[i].fColor,
578 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds. fTop, 587 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds. fTop,
579 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds .fBottom, 588 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds .fBottom,
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 682
674 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 683 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
675 return false; 684 return false;
676 } 685 }
677 686
678 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 687 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
679 this->joinBounds(that->bounds()); 688 this->joinBounds(that->bounds());
680 return true; 689 return true;
681 } 690 }
682 691
692 struct Geometry {
693 GrColor fColor;
694 SkScalar fInnerRadius;
695 SkScalar fOuterRadius;
696 SkRect fDevBounds;
697 };
698
683 bool fStroked; 699 bool fStroked;
684 SkMatrix fViewMatrixIfUsingLocalCoords; 700 SkMatrix fViewMatrixIfUsingLocalCoords;
685 SkSTArray<1, Geometry, true> fGeoData; 701 SkSTArray<1, Geometry, true> fGeoData;
686 702
687 typedef GrVertexBatch INHERITED; 703 typedef GrVertexBatch INHERITED;
688 }; 704 };
689 705
690 static GrDrawBatch* create_circle_batch(GrColor color,
691 const SkMatrix& viewMatrix,
692 const SkRect& circle,
693 const SkStrokeRec& stroke) {
694 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
695 viewMatrix.mapPoints(&center, 1);
696 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
697 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
698
699 SkStrokeRec::Style style = stroke.getStyle();
700 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
701 SkStrokeRec::kHairline_Style == style;
702 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
703
704 SkScalar innerRadius = 0.0f;
705 SkScalar outerRadius = radius;
706 SkScalar halfWidth = 0;
707 if (hasStroke) {
708 if (SkScalarNearlyZero(strokeWidth)) {
709 halfWidth = SK_ScalarHalf;
710 } else {
711 halfWidth = SkScalarHalf(strokeWidth);
712 }
713
714 outerRadius += halfWidth;
715 if (isStrokeOnly) {
716 innerRadius = radius - halfWidth;
717 }
718 }
719
720 // The radii are outset for two reasons. First, it allows the shader to simp ly perform simpler
721 // computation because the computed alpha is zero, rather than 50%, at the r adius.
722 // Second, the outer radius is used to compute the verts of the bounding box that is rendered
723 // and the outset ensures the box will cover all partially covered by the ci rcle.
724 outerRadius += SK_ScalarHalf;
725 innerRadius -= SK_ScalarHalf;
726
727 CircleBatch::Geometry geometry;
728 geometry.fColor = color;
729 geometry.fInnerRadius = innerRadius;
730 geometry.fOuterRadius = outerRadius;
731 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
732 center.fX + outerRadius, center.fY + outerRadius);
733
734 return new CircleBatch(geometry, viewMatrix, isStrokeOnly && innerRadius > 0 );
735 }
736
737 GrDrawBatch* GrOvalRenderer::CreateCircleBatch(GrColor color,
738 const SkMatrix& viewMatrix,
739 const SkRect& circle,
740 const SkStrokeRec& stroke) {
741 return create_circle_batch(color, viewMatrix, circle, stroke);
742 }
743
744 /////////////////////////////////////////////////////////////////////////////// 706 ///////////////////////////////////////////////////////////////////////////////
745 707
746 class EllipseBatch : public GrVertexBatch { 708 class EllipseBatch : public GrVertexBatch {
747 public: 709 public:
748 DEFINE_BATCH_CLASS_ID 710 DEFINE_BATCH_CLASS_ID
711 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& ellipse,
712 const SkStrokeRec& stroke) {
713 SkASSERT(viewMatrix.rectStaysRect());
749 714
750 struct Geometry { 715 // do any matrix crunching before we reset the draw state for device coo rds
751 SkRect fDevBounds; 716 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
752 SkScalar fXRadius; 717 viewMatrix.mapPoints(&center, 1);
753 SkScalar fYRadius; 718 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
754 SkScalar fInnerXRadius; 719 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
755 SkScalar fInnerYRadius; 720 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRa dius +
756 GrColor fColor; 721 viewMatrix[SkMatrix::kMSkewY]*ellipseYRad ius);
757 }; 722 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRad ius +
723 viewMatrix[SkMatrix::kMScaleY]*ellipseYRa dius);
758 724
759 EllipseBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool stro ked) 725 // do (potentially) anisotropic mapping of stroke
760 : INHERITED(ClassID()) 726 SkVector scaledStroke;
761 , fStroked(stroked) 727 SkScalar strokeWidth = stroke.getWidth();
762 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 728 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX ] +
763 fGeoData.push_back(geometry); 729 viewMatrix[SkMatrix::kMSkewY] ));
764 this->setBounds(geometry.fDevBounds); 730 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
731 viewMatrix[SkMatrix::kMScaleY ]));
732
733 SkStrokeRec::Style style = stroke.getStyle();
734 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
735 SkStrokeRec::kHairline_Style == style;
736 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == st yle;
737
738 SkScalar innerXRadius = 0;
739 SkScalar innerYRadius = 0;
740 if (hasStroke) {
741 if (SkScalarNearlyZero(scaledStroke.length())) {
742 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
743 } else {
744 scaledStroke.scale(SK_ScalarHalf);
745 }
746
747 // we only handle thick strokes for near-circular ellipses
748 if (scaledStroke.length() > SK_ScalarHalf &&
749 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad ius)) {
750 return nullptr;
751 }
752
753 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
754 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok e.fY)*xRadius ||
755 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok e.fX)*yRadius) {
756 return nullptr;
757 }
758
759 // this is legit only if scale & translation (which should be the ca se at the moment)
760 if (isStrokeOnly) {
761 innerXRadius = xRadius - scaledStroke.fX;
762 innerYRadius = yRadius - scaledStroke.fY;
763 }
764
765 xRadius += scaledStroke.fX;
766 yRadius += scaledStroke.fY;
767 }
768
769 EllipseBatch* batch = new EllipseBatch();
770 batch->fGeoData.emplace_back(Geometry {
771 color,
772 xRadius,
773 yRadius,
774 innerXRadius,
775 innerYRadius,
776 SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
777 center.fX + xRadius, center.fY + yRadius)
778 });
779
780 // Outset bounds to include half-pixel width antialiasing.
781 batch->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
782
783 batch->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
784 batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
785 batch->setBounds(batch->fGeoData.back().fDevBounds);
786 return batch;
765 } 787 }
766 788
767 const char* name() const override { return "EllipseBatch"; } 789 const char* name() const override { return "EllipseBatch"; }
768 790
769 void computePipelineOptimizations(GrInitInvariantOutput* color, 791 void computePipelineOptimizations(GrInitInvariantOutput* color,
770 GrInitInvariantOutput* coverage, 792 GrInitInvariantOutput* coverage,
771 GrBatchToXPOverrides* overrides) const ove rride { 793 GrBatchToXPOverrides* overrides) const ove rride {
772 // When this is called on a batch, there is only one geometry bundle 794 // When this is called on a batch, there is only one geometry bundle
773 color->setKnownFourComponents(fGeoData[0].fColor); 795 color->setKnownFourComponents(fGeoData[0].fColor);
774 coverage->setUnknownSingleComponent(); 796 coverage->setUnknownSingleComponent();
775 } 797 }
776 798
777 private: 799 private:
800 EllipseBatch() : INHERITED(ClassID()) {}
801
778 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 802 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
779 // Handle any overrides that affect our GP. 803 // Handle any overrides that affect our GP.
780 if (!overrides.readsCoverage()) { 804 if (!overrides.readsCoverage()) {
781 fGeoData[0].fColor = GrColor_ILLEGAL; 805 fGeoData[0].fColor = GrColor_ILLEGAL;
782 } 806 }
783 if (!overrides.readsLocalCoords()) { 807 if (!overrides.readsLocalCoords()) {
784 fViewMatrixIfUsingLocalCoords.reset(); 808 fViewMatrixIfUsingLocalCoords.reset();
785 } 809 }
786 } 810 }
787 811
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 891
868 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 892 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
869 return false; 893 return false;
870 } 894 }
871 895
872 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 896 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
873 this->joinBounds(that->bounds()); 897 this->joinBounds(that->bounds());
874 return true; 898 return true;
875 } 899 }
876 900
901 struct Geometry {
902 GrColor fColor;
903 SkScalar fXRadius;
904 SkScalar fYRadius;
905 SkScalar fInnerXRadius;
906 SkScalar fInnerYRadius;
907 SkRect fDevBounds;
908 };
877 909
878 bool fStroked; 910 bool fStroked;
879 SkMatrix fViewMatrixIfUsingLocalCoords; 911 SkMatrix fViewMatrixIfUsingLocalCoords;
880 SkSTArray<1, Geometry, true> fGeoData; 912 SkSTArray<1, Geometry, true> fGeoData;
881 913
882 typedef GrVertexBatch INHERITED; 914 typedef GrVertexBatch INHERITED;
883 }; 915 };
884 916
885 static GrDrawBatch* create_ellipse_batch(GrColor color,
886 const SkMatrix& viewMatrix,
887 const SkRect& ellipse,
888 const SkStrokeRec& stroke) {
889 SkASSERT(viewMatrix.rectStaysRect());
890
891 // do any matrix crunching before we reset the draw state for device coords
892 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
893 viewMatrix.mapPoints(&center, 1);
894 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
895 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
896 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
897 viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius) ;
898 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
899 viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius );
900
901 // do (potentially) anisotropic mapping of stroke
902 SkVector scaledStroke;
903 SkScalar strokeWidth = stroke.getWidth();
904 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
905 viewMatrix[SkMatrix::kMSkewY]));
906 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
907 viewMatrix[SkMatrix::kMScaleY]));
908
909 SkStrokeRec::Style style = stroke.getStyle();
910 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
911 SkStrokeRec::kHairline_Style == style;
912 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
913
914 SkScalar innerXRadius = 0;
915 SkScalar innerYRadius = 0;
916 if (hasStroke) {
917 if (SkScalarNearlyZero(scaledStroke.length())) {
918 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
919 } else {
920 scaledStroke.scale(SK_ScalarHalf);
921 }
922
923 // we only handle thick strokes for near-circular ellipses
924 if (scaledStroke.length() > SK_ScalarHalf &&
925 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) {
926 return nullptr;
927 }
928
929 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
930 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY )*xRadius ||
931 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX )*yRadius) {
932 return nullptr;
933 }
934
935 // this is legit only if scale & translation (which should be the case a t the moment)
936 if (isStrokeOnly) {
937 innerXRadius = xRadius - scaledStroke.fX;
938 innerYRadius = yRadius - scaledStroke.fY;
939 }
940
941 xRadius += scaledStroke.fX;
942 yRadius += scaledStroke.fY;
943 }
944
945 EllipseBatch::Geometry geometry;
946 geometry.fColor = color;
947 geometry.fXRadius = xRadius;
948 geometry.fYRadius = yRadius;
949 geometry.fInnerXRadius = innerXRadius;
950 geometry.fInnerYRadius = innerYRadius;
951 geometry.fDevBounds = SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRad ius,
952 center.fX + xRadius, center.fY + yRad ius);
953
954 // outset bounds to include half-pixel width antialiasing.
955 geometry.fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
956
957 return new EllipseBatch(geometry, viewMatrix,
958 isStrokeOnly && innerXRadius > 0 && innerYRadius > 0 );
959 }
960
961 GrDrawBatch* GrOvalRenderer::CreateEllipseBatch(GrColor color,
962 const SkMatrix& viewMatrix,
963 const SkRect& ellipse,
964 const SkStrokeRec& stroke) {
965 return create_ellipse_batch(color, viewMatrix, ellipse, stroke);
966 }
967
968 //////////////////////////////////////////////////////////////////////////////// ///////////////// 917 //////////////////////////////////////////////////////////////////////////////// /////////////////
969 918
970 class DIEllipseBatch : public GrVertexBatch { 919 class DIEllipseBatch : public GrVertexBatch {
971 public: 920 public:
972 DEFINE_BATCH_CLASS_ID 921 DEFINE_BATCH_CLASS_ID
973 922
974 struct Geometry { 923 static GrDrawBatch* Create(GrColor color,
975 SkMatrix fViewMatrix; 924 const SkMatrix& viewMatrix,
976 SkRect fBounds; 925 const SkRect& ellipse,
977 SkScalar fXRadius; 926 const SkStrokeRec& stroke) {
978 SkScalar fYRadius; 927 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
979 SkScalar fInnerXRadius; 928 SkScalar xRadius = SkScalarHalf(ellipse.width());
980 SkScalar fInnerYRadius; 929 SkScalar yRadius = SkScalarHalf(ellipse.height());
981 SkScalar fGeoDx;
982 SkScalar fGeoDy;
983 GrColor fColor;
984 DIEllipseStyle fStyle;
985 };
986 930
987 static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) { 931 SkStrokeRec::Style style = stroke.getStyle();
988 return new DIEllipseBatch(geometry, bounds); 932 DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ?
933 DIEllipseStyle::kStroke :
934 (SkStrokeRec::kHairline_Style == style) ?
935 DIEllipseStyle::kHairline : DIEllipseStyle::kF ill;
936
937 SkScalar innerXRadius = 0;
938 SkScalar innerYRadius = 0;
939 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
940 SkScalar strokeWidth = stroke.getWidth();
941
942 if (SkScalarNearlyZero(strokeWidth)) {
943 strokeWidth = SK_ScalarHalf;
944 } else {
945 strokeWidth *= SK_ScalarHalf;
946 }
947
948 // we only handle thick strokes for near-circular ellipses
949 if (strokeWidth > SK_ScalarHalf &&
950 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad ius)) {
951 return nullptr;
952 }
953
954 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
955 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadiu s ||
956 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadiu s) {
957 return nullptr;
958 }
959
960 // set inner radius (if needed)
961 if (SkStrokeRec::kStroke_Style == style) {
962 innerXRadius = xRadius - strokeWidth;
963 innerYRadius = yRadius - strokeWidth;
964 }
965
966 xRadius += strokeWidth;
967 yRadius += strokeWidth;
968 }
969 if (DIEllipseStyle::kStroke == dieStyle) {
970 dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle : :kStroke :
971 DIEllipseStyle ::kFill;
972 }
973
974 // This expands the outer rect so that after CTM we end up with a half-p ixel border
975 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
976 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
977 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
978 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
979 SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
980 SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
981
982 DIEllipseBatch* batch = new DIEllipseBatch();
983 batch->fGeoData.emplace_back(Geometry {
984 viewMatrix,
985 color,
986 xRadius,
987 yRadius,
988 innerXRadius,
989 innerYRadius,
990 geoDx,
991 geoDy,
992 dieStyle,
993 SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
994 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)
995 });
996 SkRect devBounds = batch->fGeoData.back().fBounds;
997 viewMatrix.mapRect(&devBounds);
998 batch->setBounds(devBounds);
999 return batch;
989 } 1000 }
990 1001
991 const char* name() const override { return "DIEllipseBatch"; } 1002 const char* name() const override { return "DIEllipseBatch"; }
992 1003
993 void computePipelineOptimizations(GrInitInvariantOutput* color, 1004 void computePipelineOptimizations(GrInitInvariantOutput* color,
994 GrInitInvariantOutput* coverage, 1005 GrInitInvariantOutput* coverage,
995 GrBatchToXPOverrides* overrides) const ove rride { 1006 GrBatchToXPOverrides* overrides) const ove rride {
996 // When this is called on a batch, there is only one geometry bundle 1007 // When this is called on a batch, there is only one geometry bundle
997 color->setKnownFourComponents(fGeoData[0].fColor); 1008 color->setKnownFourComponents(fGeoData[0].fColor);
998 coverage->setUnknownSingleComponent(); 1009 coverage->setUnknownSingleComponent();
999 } 1010 }
1000 1011
1001 private: 1012 private:
1002 1013
1014 DIEllipseBatch() : INHERITED(ClassID()) {}
1015
1003 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 1016 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1004 // Handle any overrides that affect our GP. 1017 // Handle any overrides that affect our GP.
1005 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 1018 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1006 fUsesLocalCoords = overrides.readsLocalCoords(); 1019 fUsesLocalCoords = overrides.readsLocalCoords();
1007 } 1020 }
1008 1021
1009 void onPrepareDraws(Target* target) const override { 1022 void onPrepareDraws(Target* target) const override {
1010 // Setup geometry processor 1023 // Setup geometry processor
1011 SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this ->viewMatrix(), 1024 SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this ->viewMatrix(),
1012 this ->style())); 1025 this ->style()));
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 1068 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1056 verts[3].fColor = color; 1069 verts[3].fColor = color;
1057 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offse tDy); 1070 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offse tDy);
1058 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -inner RatioY - offsetDy); 1071 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -inner RatioY - offsetDy);
1059 1072
1060 verts += kVerticesPerQuad; 1073 verts += kVerticesPerQuad;
1061 } 1074 }
1062 helper.recordDraw(target, gp); 1075 helper.recordDraw(target, gp);
1063 } 1076 }
1064 1077
1065 DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(C lassID()) {
1066 fGeoData.push_back(geometry);
1067
1068 this->setBounds(bounds);
1069 }
1070
1071 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 1078 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1072 DIEllipseBatch* that = t->cast<DIEllipseBatch>(); 1079 DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1073 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), 1080 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(),
1074 that->bounds(), caps)) { 1081 that->bounds(), caps)) {
1075 return false; 1082 return false;
1076 } 1083 }
1077 1084
1078 if (this->style() != that->style()) { 1085 if (this->style() != that->style()) {
1079 return false; 1086 return false;
1080 } 1087 }
1081 1088
1082 // TODO rewrite to allow positioning on CPU 1089 // TODO rewrite to allow positioning on CPU
1083 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 1090 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1084 return false; 1091 return false;
1085 } 1092 }
1086 1093
1087 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1094 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1088 this->joinBounds(that->bounds()); 1095 this->joinBounds(that->bounds());
1089 return true; 1096 return true;
1090 } 1097 }
1091 1098
1092 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } 1099 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1093 DIEllipseStyle style() const { return fGeoData[0].fStyle; } 1100 DIEllipseStyle style() const { return fGeoData[0].fStyle; }
1094 1101
1102 struct Geometry {
1103 SkMatrix fViewMatrix;
1104 GrColor fColor;
1105 SkScalar fXRadius;
1106 SkScalar fYRadius;
1107 SkScalar fInnerXRadius;
1108 SkScalar fInnerYRadius;
1109 SkScalar fGeoDx;
1110 SkScalar fGeoDy;
1111 DIEllipseStyle fStyle;
1112 SkRect fBounds;
1113 };
1114
1095 bool fUsesLocalCoords; 1115 bool fUsesLocalCoords;
1096 SkSTArray<1, Geometry, true> fGeoData; 1116 SkSTArray<1, Geometry, true> fGeoData;
1097 1117
1098 typedef GrVertexBatch INHERITED; 1118 typedef GrVertexBatch INHERITED;
1099 }; 1119 };
1100 1120
1101 static GrDrawBatch* create_diellipse_batch(GrColor color,
1102 const SkMatrix& viewMatrix,
1103 const SkRect& ellipse,
1104 const SkStrokeRec& stroke) {
1105 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
1106 SkScalar xRadius = SkScalarHalf(ellipse.width());
1107 SkScalar yRadius = SkScalarHalf(ellipse.height());
1108
1109 SkStrokeRec::Style style = stroke.getStyle();
1110 DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ?
1111 DIEllipseStyle::kStroke :
1112 (SkStrokeRec::kHairline_Style == style) ?
1113 DIEllipseStyle::kHairline : DIEllipseSty le::kFill;
1114
1115 SkScalar innerXRadius = 0;
1116 SkScalar innerYRadius = 0;
1117 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != sty le) {
1118 SkScalar strokeWidth = stroke.getWidth();
1119
1120 if (SkScalarNearlyZero(strokeWidth)) {
1121 strokeWidth = SK_ScalarHalf;
1122 } else {
1123 strokeWidth *= SK_ScalarHalf;
1124 }
1125
1126 // we only handle thick strokes for near-circular ellipses
1127 if (strokeWidth > SK_ScalarHalf &&
1128 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) {
1129 return nullptr;
1130 }
1131
1132 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1133 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
1134 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
1135 return nullptr;
1136 }
1137
1138 // set inner radius (if needed)
1139 if (SkStrokeRec::kStroke_Style == style) {
1140 innerXRadius = xRadius - strokeWidth;
1141 innerYRadius = yRadius - strokeWidth;
1142 }
1143
1144 xRadius += strokeWidth;
1145 yRadius += strokeWidth;
1146 }
1147 if (DIEllipseStyle::kStroke == dieStyle) {
1148 dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle ::kSt roke :
1149 DIEllipseStyle ::kFi ll;
1150 }
1151
1152 // This expands the outer rect so that after CTM we end up with a half-pixel border
1153 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
1154 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
1155 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
1156 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
1157 SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
1158 SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
1159
1160 DIEllipseBatch::Geometry geometry;
1161 geometry.fViewMatrix = viewMatrix;
1162 geometry.fColor = color;
1163 geometry.fXRadius = xRadius;
1164 geometry.fYRadius = yRadius;
1165 geometry.fInnerXRadius = innerXRadius;
1166 geometry.fInnerYRadius = innerYRadius;
1167 geometry.fGeoDx = geoDx;
1168 geometry.fGeoDy = geoDy;
1169 geometry.fStyle = dieStyle;
1170 geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1171 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
1172
1173 SkRect devBounds = geometry.fBounds;
1174 viewMatrix.mapRect(&devBounds);
1175 return DIEllipseBatch::Create(geometry, devBounds);
1176 }
1177
1178 GrDrawBatch* GrOvalRenderer::CreateDIEllipseBatch(GrColor color,
1179 const SkMatrix& viewMatrix,
1180 const SkRect& ellipse,
1181 const SkStrokeRec& stroke) {
1182 return create_diellipse_batch(color, viewMatrix, ellipse, stroke);
1183 }
1184
1185 /////////////////////////////////////////////////////////////////////////////// 1121 ///////////////////////////////////////////////////////////////////////////////
1186 1122
1187 static const uint16_t gRRectIndices[] = { 1123 static const uint16_t gRRectIndices[] = {
1188 // corners 1124 // corners
1189 0, 1, 5, 0, 5, 4, 1125 0, 1, 5, 0, 5, 4,
1190 2, 3, 7, 2, 7, 6, 1126 2, 3, 7, 2, 7, 6,
1191 8, 9, 13, 8, 13, 12, 1127 8, 9, 13, 8, 13, 12,
1192 10, 11, 15, 10, 15, 14, 1128 10, 11, 15, 10, 15, 14,
1193 1129
1194 // edges 1130 // edges
(...skipping 29 matching lines...) Expand all
1224 1160
1225 } 1161 }
1226 } 1162 }
1227 1163
1228 //////////////////////////////////////////////////////////////////////////////// /////////////////// 1164 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1229 1165
1230 class RRectCircleRendererBatch : public GrVertexBatch { 1166 class RRectCircleRendererBatch : public GrVertexBatch {
1231 public: 1167 public:
1232 DEFINE_BATCH_CLASS_ID 1168 DEFINE_BATCH_CLASS_ID
1233 1169
1234 struct Geometry { 1170 // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then s trokeOnly indicates
1235 SkRect fDevBounds; 1171 // whether the rrect is only stroked or stroked and filled.
1236 SkScalar fInnerRadius; 1172 RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const Sk Rect& devRect,
1237 SkScalar fOuterRadius; 1173 float devRadius, float devStrokeWidth, bool strokeO nly)
1238 GrColor fColor; 1174 : INHERITED(ClassID())
1239 }; 1175 , fViewMatrixIfUsingLocalCoords(viewMatrix) {
1176 SkRect bounds = devRect;
1177 SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
1178 SkScalar innerRadius = 0.0f;
1179 SkScalar outerRadius = devRadius;
1180 SkScalar halfWidth = 0;
1181 fStroked = false;
1182 if (devStrokeWidth > 0) {
1183 if (SkScalarNearlyZero(devStrokeWidth)) {
1184 halfWidth = SK_ScalarHalf;
1185 } else {
1186 halfWidth = SkScalarHalf(devStrokeWidth);
1187 }
1240 1188
1241 RRectCircleRendererBatch(const Geometry& geometry, const SkMatrix& viewMatri x, bool stroked) 1189 if (strokeOnly) {
1242 : INHERITED(ClassID()) 1190 innerRadius = devRadius - halfWidth;
1243 , fStroked(stroked) 1191 fStroked = innerRadius >= 0;
1244 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 1192 }
1245 fGeoData.push_back(geometry); 1193 outerRadius += halfWidth;
1194 bounds.outset(halfWidth, halfWidth);
1195 }
1246 1196
1247 this->setBounds(geometry.fDevBounds); 1197 // The radii are outset for two reasons. First, it allows the shader to simply perform
1198 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1199 // Second, the outer radius is used to compute the verts of the bounding box that is
1200 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1201 // corners.
1202 outerRadius += SK_ScalarHalf;
1203 innerRadius -= SK_ScalarHalf;
1204
1205 // Expand the rect so all the pixels will be captured.
1206 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1207
1208 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds });
1209 this->setBounds(bounds);
1248 } 1210 }
1249 1211
1250 const char* name() const override { return "RRectCircleBatch"; } 1212 const char* name() const override { return "RRectCircleBatch"; }
1251 1213
1252 void computePipelineOptimizations(GrInitInvariantOutput* color, 1214 void computePipelineOptimizations(GrInitInvariantOutput* color,
1253 GrInitInvariantOutput* coverage, 1215 GrInitInvariantOutput* coverage,
1254 GrBatchToXPOverrides* overrides) const ove rride { 1216 GrBatchToXPOverrides* overrides) const ove rride {
1255 // When this is called on a batch, there is only one geometry bundle 1217 // When this is called on a batch, there is only one geometry bundle
1256 color->setKnownFourComponents(fGeoData[0].fColor); 1218 color->setKnownFourComponents(fGeoData[0].fColor);
1257 coverage->setUnknownSingleComponent(); 1219 coverage->setUnknownSingleComponent();
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1359 1321
1360 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 1322 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
1361 return false; 1323 return false;
1362 } 1324 }
1363 1325
1364 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1326 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1365 this->joinBounds(that->bounds()); 1327 this->joinBounds(that->bounds());
1366 return true; 1328 return true;
1367 } 1329 }
1368 1330
1331 struct Geometry {
1332 GrColor fColor;
1333 SkScalar fInnerRadius;
1334 SkScalar fOuterRadius;
1335 SkRect fDevBounds;
1336 };
1337
1369 bool fStroked; 1338 bool fStroked;
1370 SkMatrix fViewMatrixIfUsingLocalCoords; 1339 SkMatrix fViewMatrixIfUsingLocalCoords;
1371 SkSTArray<1, Geometry, true> fGeoData; 1340 SkSTArray<1, Geometry, true> fGeoData;
1372 1341
1373 typedef GrVertexBatch INHERITED; 1342 typedef GrVertexBatch INHERITED;
1374 }; 1343 };
1375 1344
1376 class RRectEllipseRendererBatch : public GrVertexBatch { 1345 class RRectEllipseRendererBatch : public GrVertexBatch {
1377 public: 1346 public:
1378 DEFINE_BATCH_CLASS_ID 1347 DEFINE_BATCH_CLASS_ID
1379 1348
1380 struct Geometry { 1349 // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, s trokeOnly indicates
1381 SkRect fDevBounds; 1350 // whether the rrect is only stroked or stroked and filled.
1382 SkScalar fXRadius; 1351 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
1383 SkScalar fYRadius; 1352 float devXRadius, float devYRadius, SkVector devS trokeWidths,
1384 SkScalar fInnerXRadius; 1353 bool strokeOnly) {
1385 SkScalar fInnerYRadius; 1354 SkASSERT(devXRadius > 0.5);
1386 GrColor fColor; 1355 SkASSERT(devYRadius > 0.5);
1387 }; 1356 SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0));
1357 SkASSERT(!(strokeOnly && devStrokeWidths.fX <= 0));
1358 SkScalar innerXRadius = 0.0f;
1359 SkScalar innerYRadius = 0.0f;
1360 SkRect bounds = devRect;
1361 bool stroked = false;
1362 if (devStrokeWidths.fX > 0) {
1363 if (SkScalarNearlyZero(devStrokeWidths.length())) {
1364 devStrokeWidths.set(SK_ScalarHalf, SK_ScalarHalf);
1365 } else {
1366 devStrokeWidths.scale(SK_ScalarHalf);
1367 }
1388 1368
1389 RRectEllipseRendererBatch(const Geometry& geometry, const SkMatrix& viewMatr ix, bool stroked) 1369 // we only handle thick strokes for near-circular ellipses
1390 : INHERITED(ClassID()) 1370 if (devStrokeWidths.length() > SK_ScalarHalf &&
1391 , fStroked(stroked) 1371 (SK_ScalarHalf*devXRadius > devYRadius || SK_ScalarHalf*devYRadi us > devXRadius)) {
1392 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 1372 return nullptr;
1393 fGeoData.push_back(geometry); 1373 }
1394 this->setBounds(geometry.fDevBounds); 1374
1375 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
1376 if (devStrokeWidths.fX*(devYRadius*devYRadius) <
1377 (devStrokeWidths.fY*devStrokeWidths.fY)*devXRadius) {
1378 return nullptr;
1379 }
1380 if (devStrokeWidths.fY*(devXRadius*devXRadius) <
1381 (devStrokeWidths.fX*devStrokeWidths.fX)*devYRadius) {
1382 return nullptr;
1383 }
1384
1385 // this is legit only if scale & translation (which should be the ca se at the moment)
1386 if (strokeOnly) {
1387 innerXRadius = devXRadius - devStrokeWidths.fX;
1388 innerYRadius = devYRadius - devStrokeWidths.fY;
1389 stroked = (innerXRadius >= 0 && innerYRadius >= 0);
1390 }
1391
1392 devXRadius += devStrokeWidths.fX;
1393 devYRadius += devStrokeWidths.fY;
1394 bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY);
1395 }
1396
1397 // Expand the rect so all the pixels will be captured.
1398 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1399
1400 RRectEllipseRendererBatch* batch = new RRectEllipseRendererBatch();
1401 batch->fStroked = stroked;
1402 batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
1403 batch->fGeoData.emplace_back(
1404 Geometry {color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds});
1405 batch->setBounds(bounds);
1406 return batch;
1395 } 1407 }
1396 1408
1397 const char* name() const override { return "RRectEllipseRendererBatch"; } 1409 const char* name() const override { return "RRectEllipseRendererBatch"; }
1398 1410
1399 void computePipelineOptimizations(GrInitInvariantOutput* color, 1411 void computePipelineOptimizations(GrInitInvariantOutput* color,
1400 GrInitInvariantOutput* coverage, 1412 GrInitInvariantOutput* coverage,
1401 GrBatchToXPOverrides* overrides) const ove rride { 1413 GrBatchToXPOverrides* overrides) const ove rride {
1402 // When this is called on a batch, there is only one geometry bundle 1414 // When this is called on a batch, there is only one geometry bundle
1403 color->setKnownFourComponents(fGeoData[0].fColor); 1415 color->setKnownFourComponents(fGeoData[0].fColor);
1404 coverage->setUnknownSingleComponent(); 1416 coverage->setUnknownSingleComponent();
1405 } 1417 }
1406 1418
1407 private: 1419 private:
1420 RRectEllipseRendererBatch() : INHERITED(ClassID()) {}
1421
1408 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 1422 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1409 // Handle overrides that affect our GP. 1423 // Handle overrides that affect our GP.
1410 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 1424 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1411 if (!overrides.readsLocalCoords()) { 1425 if (!overrides.readsLocalCoords()) {
1412 fViewMatrixIfUsingLocalCoords.reset(); 1426 fViewMatrixIfUsingLocalCoords.reset();
1413 } 1427 }
1414 } 1428 }
1415 1429
1416 void onPrepareDraws(Target* target) const override { 1430 void onPrepareDraws(Target* target) const override {
1417 SkMatrix localMatrix; 1431 SkMatrix localMatrix;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1517 1531
1518 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 1532 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
1519 return false; 1533 return false;
1520 } 1534 }
1521 1535
1522 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1536 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1523 this->joinBounds(that->bounds()); 1537 this->joinBounds(that->bounds());
1524 return true; 1538 return true;
1525 } 1539 }
1526 1540
1541 struct Geometry {
1542 GrColor fColor;
1543 SkScalar fXRadius;
1544 SkScalar fYRadius;
1545 SkScalar fInnerXRadius;
1546 SkScalar fInnerYRadius;
1547 SkRect fDevBounds;
1548 };
1549
1527 bool fStroked; 1550 bool fStroked;
1528 SkMatrix fViewMatrixIfUsingLocalCoords; 1551 SkMatrix fViewMatrixIfUsingLocalCoords;
1529 SkSTArray<1, Geometry, true> fGeoData; 1552 SkSTArray<1, Geometry, true> fGeoData;
1530 1553
1531 typedef GrVertexBatch INHERITED; 1554 typedef GrVertexBatch INHERITED;
1532 }; 1555 };
1533 1556
1534 static GrDrawBatch* create_rrect_batch(GrColor color, 1557 static GrDrawBatch* create_rrect_batch(GrColor color,
1535 const SkMatrix& viewMatrix, 1558 const SkMatrix& viewMatrix,
1536 const SkRRect& rrect, 1559 const SkRRect& rrect,
1537 const SkStrokeRec& stroke) { 1560 const SkStrokeRec& stroke) {
1538 SkASSERT(viewMatrix.rectStaysRect()); 1561 SkASSERT(viewMatrix.rectStaysRect());
1539 SkASSERT(rrect.isSimple()); 1562 SkASSERT(rrect.isSimple());
1540 SkASSERT(!rrect.isOval()); 1563 SkASSERT(!rrect.isOval());
1541 1564
1542 // RRect batchs only handle simple, but not too simple, rrects 1565 // RRect batchs only handle simple, but not too simple, rrects
1543 // do any matrix crunching before we reset the draw state for device coords 1566 // do any matrix crunching before we reset the draw state for device coords
1544 const SkRect& rrectBounds = rrect.getBounds(); 1567 const SkRect& rrectBounds = rrect.getBounds();
1545 SkRect bounds; 1568 SkRect bounds;
1546 viewMatrix.mapRect(&bounds, rrectBounds); 1569 viewMatrix.mapRect(&bounds, rrectBounds);
1547 1570
1548 SkVector radii = rrect.getSimpleRadii(); 1571 SkVector radii = rrect.getSimpleRadii();
1549 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX + 1572 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
1550 viewMatrix[SkMatrix::kMSkewY]*radii.fY); 1573 viewMatrix[SkMatrix::kMSkewY]*radii.fY);
1551 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX + 1574 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
1552 viewMatrix[SkMatrix::kMScaleY]*radii.fY); 1575 viewMatrix[SkMatrix::kMScaleY]*radii.fY);
1553 1576
1554 SkStrokeRec::Style style = stroke.getStyle(); 1577 SkStrokeRec::Style style = stroke.getStyle();
1555 1578
1556 // do (potentially) anisotropic mapping of stroke 1579 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws.
1557 SkVector scaledStroke; 1580 SkVector scaledStroke = {-1, -1};
1558 SkScalar strokeWidth = stroke.getWidth(); 1581 SkScalar strokeWidth = stroke.getWidth();
1559 1582
1560 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 1583 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1561 SkStrokeRec::kHairline_Style == style; 1584 SkStrokeRec::kHairline_Style == style;
1562 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 1585 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1563 1586
1564 if (hasStroke) { 1587 if (hasStroke) {
1565 if (SkStrokeRec::kHairline_Style == style) { 1588 if (SkStrokeRec::kHairline_Style == style) {
1566 scaledStroke.set(1, 1); 1589 scaledStroke.set(1, 1);
1567 } else { 1590 } else {
(...skipping 13 matching lines...) Expand all
1581 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine- 1604 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine-
1582 // patch will have fractional coverage. This only matters when the interior is actually filled. 1605 // patch will have fractional coverage. This only matters when the interior is actually filled.
1583 // We could consider falling back to rect rendering here, since a tiny radiu s is 1606 // We could consider falling back to rect rendering here, since a tiny radiu s is
1584 // indistinguishable from a square corner. 1607 // indistinguishable from a square corner.
1585 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { 1608 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
1586 return nullptr; 1609 return nullptr;
1587 } 1610 }
1588 1611
1589 // if the corners are circles, use the circle renderer 1612 // if the corners are circles, use the circle renderer
1590 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { 1613 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) {
1591 SkScalar innerRadius = 0.0f; 1614 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX,
1592 SkScalar outerRadius = xRadius; 1615 isStrokeOnly);
1593 SkScalar halfWidth = 0;
1594 if (hasStroke) {
1595 if (SkScalarNearlyZero(scaledStroke.fX)) {
1596 halfWidth = SK_ScalarHalf;
1597 } else {
1598 halfWidth = SkScalarHalf(scaledStroke.fX);
1599 }
1600
1601 if (isStrokeOnly) {
1602 innerRadius = xRadius - halfWidth;
1603 }
1604 outerRadius += halfWidth;
1605 bounds.outset(halfWidth, halfWidth);
1606 }
1607
1608 isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
1609
1610 // The radii are outset for two reasons. First, it allows the shader to simply perform
1611 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1612 // Second, the outer radius is used to compute the verts of the bounding box that is
1613 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1614 // corners.
1615 outerRadius += SK_ScalarHalf;
1616 innerRadius -= SK_ScalarHalf;
1617
1618 // Expand the rect so all the pixels will be captured.
1619 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1620
1621 RRectCircleRendererBatch::Geometry geometry;
1622 geometry.fColor = color;
1623 geometry.fInnerRadius = innerRadius;
1624 geometry.fOuterRadius = outerRadius;
1625 geometry.fDevBounds = bounds;
1626
1627 return new RRectCircleRendererBatch(geometry, viewMatrix, isStrokeOnly);
1628 // otherwise we use the ellipse renderer 1616 // otherwise we use the ellipse renderer
1629 } else { 1617 } else {
1630 SkScalar innerXRadius = 0.0f; 1618 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius,
1631 SkScalar innerYRadius = 0.0f; 1619 scaledStroke, isStrokeOnly);
1632 if (hasStroke) {
1633 if (SkScalarNearlyZero(scaledStroke.length())) {
1634 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1635 } else {
1636 scaledStroke.scale(SK_ScalarHalf);
1637 }
1638 1620
1639 // we only handle thick strokes for near-circular ellipses
1640 if (scaledStroke.length() > SK_ScalarHalf &&
1641 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad ius)) {
1642 return nullptr;
1643 }
1644
1645 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
1646 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok e.fY)*xRadius ||
1647 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok e.fX)*yRadius) {
1648 return nullptr;
1649 }
1650
1651 // this is legit only if scale & translation (which should be the ca se at the moment)
1652 if (isStrokeOnly) {
1653 innerXRadius = xRadius - scaledStroke.fX;
1654 innerYRadius = yRadius - scaledStroke.fY;
1655 }
1656
1657 xRadius += scaledStroke.fX;
1658 yRadius += scaledStroke.fY;
1659 bounds.outset(scaledStroke.fX, scaledStroke.fY);
1660 }
1661
1662 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
1663
1664 // Expand the rect so all the pixels will be captured.
1665 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1666
1667 RRectEllipseRendererBatch::Geometry geometry;
1668 geometry.fColor = color;
1669 geometry.fXRadius = xRadius;
1670 geometry.fYRadius = yRadius;
1671 geometry.fInnerXRadius = innerXRadius;
1672 geometry.fInnerYRadius = innerYRadius;
1673 geometry.fDevBounds = bounds;
1674
1675 return new RRectEllipseRendererBatch(geometry, viewMatrix, isStrokeOnly) ;
1676 } 1621 }
1677 } 1622 }
1678 1623
1679 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, 1624 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color,
1680 const SkMatrix& viewMatrix, 1625 const SkMatrix& viewMatrix,
1681 const SkRRect& rrect, 1626 const SkRRect& rrect,
1682 const SkStrokeRec& stroke, 1627 const SkStrokeRec& stroke,
1683 GrShaderCaps* shaderCaps) { 1628 GrShaderCaps* shaderCaps) {
1684 if (rrect.isOval()) { 1629 if (rrect.isOval()) {
1685 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha derCaps); 1630 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha derCaps);
1686 } 1631 }
1687 1632
1688 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { 1633 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
1689 return nullptr; 1634 return nullptr;
1690 } 1635 }
1691 1636
1692 return create_rrect_batch(color, viewMatrix, rrect, stroke); 1637 return create_rrect_batch(color, viewMatrix, rrect, stroke);
1693 } 1638 }
1694 1639
1695 //////////////////////////////////////////////////////////////////////////////// /////////////////// 1640 ///////////////////////////////////////////////////////////////////////////////
1641
1642 GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
1643 const SkMatrix& viewMatrix,
1644 const SkRect& oval,
1645 const SkStrokeRec& stroke,
1646 GrShaderCaps* shaderCaps) {
1647 // we can draw circles
1648 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle( viewMatrix)) {
1649 return new CircleBatch(color, viewMatrix, oval, stroke);
1650 }
1651
1652 // if we have shader derivative support, render as device-independent
1653 if (shaderCaps->shaderDerivativeSupport()) {
1654 return DIEllipseBatch::Create(color, viewMatrix, oval, stroke);
1655 }
1656
1657 // otherwise axis-aligned ellipses only
1658 if (viewMatrix.rectStaysRect()) {
1659 return EllipseBatch::Create(color, viewMatrix, oval, stroke);
1660 }
1661
1662 return nullptr;
1663 }
1664
1665 ///////////////////////////////////////////////////////////////////////////////
1696 1666
1697 #ifdef GR_TEST_UTILS 1667 #ifdef GR_TEST_UTILS
1698 1668
1699 DRAW_BATCH_TEST_DEFINE(CircleBatch) { 1669 DRAW_BATCH_TEST_DEFINE(CircleBatch) {
1700 SkMatrix viewMatrix = GrTest::TestMatrix(random); 1670 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1701 GrColor color = GrRandomColor(random); 1671 GrColor color = GrRandomColor(random);
1702 SkRect circle = GrTest::TestSquare(random); 1672 SkRect circle = GrTest::TestSquare(random);
1703 return create_circle_batch(color, viewMatrix, circle, GrTest::TestStrokeRec( random)); 1673 return new CircleBatch(color, viewMatrix, circle, GrTest::TestStrokeRec(rand om));
1704 } 1674 }
1705 1675
1706 DRAW_BATCH_TEST_DEFINE(EllipseBatch) { 1676 DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
1707 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); 1677 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1708 GrColor color = GrRandomColor(random); 1678 GrColor color = GrRandomColor(random);
1709 SkRect ellipse = GrTest::TestSquare(random); 1679 SkRect ellipse = GrTest::TestSquare(random);
1710 return create_ellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRe c(random)); 1680 return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRe c(random));
1711 } 1681 }
1712 1682
1713 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) { 1683 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
1714 SkMatrix viewMatrix = GrTest::TestMatrix(random); 1684 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1715 GrColor color = GrRandomColor(random); 1685 GrColor color = GrRandomColor(random);
1716 SkRect ellipse = GrTest::TestSquare(random); 1686 SkRect ellipse = GrTest::TestSquare(random);
1717 return create_diellipse_batch(color, viewMatrix, ellipse, GrTest::TestStroke Rec(random)); 1687 return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStroke Rec(random));
1718 } 1688 }
1719 1689
1720 DRAW_BATCH_TEST_DEFINE(RRectBatch) { 1690 DRAW_BATCH_TEST_DEFINE(RRectBatch) {
1721 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); 1691 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1722 GrColor color = GrRandomColor(random); 1692 GrColor color = GrRandomColor(random);
1723 const SkRRect& rrect = GrTest::TestRRectSimple(random); 1693 const SkRRect& rrect = GrTest::TestRRectSimple(random);
1724 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom)); 1694 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom));
1725 } 1695 }
1726 1696
1727 #endif 1697 #endif
OLDNEW
« no previous file with comments | « src/gpu/GrOvalRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698