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

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

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