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

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

Issue 2109913005: 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->setBounds(batch->fGeoData.back().fDevBounds);
787 return batch;
788 } 765 }
789 766
790 const char* name() const override { return "EllipseBatch"; } 767 const char* name() const override { return "EllipseBatch"; }
791 768
792 void computePipelineOptimizations(GrInitInvariantOutput* color, 769 void computePipelineOptimizations(GrInitInvariantOutput* color,
793 GrInitInvariantOutput* coverage, 770 GrInitInvariantOutput* coverage,
794 GrBatchToXPOverrides* overrides) const ove rride { 771 GrBatchToXPOverrides* overrides) const ove rride {
795 // 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
796 color->setKnownFourComponents(fGeoData[0].fColor); 773 color->setKnownFourComponents(fGeoData[0].fColor);
797 coverage->setUnknownSingleComponent(); 774 coverage->setUnknownSingleComponent();
798 } 775 }
799 776
800 private: 777 private:
801 EllipseBatch() : INHERITED(ClassID()) {}
802
803 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 778 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
804 // Handle any overrides that affect our GP. 779 // Handle any overrides that affect our GP.
805 if (!overrides.readsCoverage()) { 780 if (!overrides.readsCoverage()) {
806 fGeoData[0].fColor = GrColor_ILLEGAL; 781 fGeoData[0].fColor = GrColor_ILLEGAL;
807 } 782 }
808 if (!overrides.readsLocalCoords()) { 783 if (!overrides.readsLocalCoords()) {
809 fViewMatrixIfUsingLocalCoords.reset(); 784 fViewMatrixIfUsingLocalCoords.reset();
810 } 785 }
811 } 786 }
812 787
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
888 863
889 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 864 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
890 return false; 865 return false;
891 } 866 }
892 867
893 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 868 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
894 this->joinBounds(that->bounds()); 869 this->joinBounds(that->bounds());
895 return true; 870 return true;
896 } 871 }
897 872
898 struct Geometry {
899 GrColor fColor;
900 SkScalar fXRadius;
901 SkScalar fYRadius;
902 SkScalar fInnerXRadius;
903 SkScalar fInnerYRadius;
904 SkRect fDevBounds;
905 };
906 873
907 bool fStroked; 874 bool fStroked;
908 SkMatrix fViewMatrixIfUsingLocalCoords; 875 SkMatrix fViewMatrixIfUsingLocalCoords;
909 SkSTArray<1, Geometry, true> fGeoData; 876 SkSTArray<1, Geometry, true> fGeoData;
910 877
911 typedef GrVertexBatch INHERITED; 878 typedef GrVertexBatch INHERITED;
912 }; 879 };
913 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
914 //////////////////////////////////////////////////////////////////////////////// ///////////////// 967 //////////////////////////////////////////////////////////////////////////////// /////////////////
915 968
916 class DIEllipseBatch : public GrVertexBatch { 969 class DIEllipseBatch : public GrVertexBatch {
917 public: 970 public:
918 DEFINE_BATCH_CLASS_ID 971 DEFINE_BATCH_CLASS_ID
919 972
920 static GrDrawBatch* Create(GrColor color, 973 struct Geometry {
921 const SkMatrix& viewMatrix, 974 SkMatrix fViewMatrix;
922 const SkRect& ellipse, 975 SkRect fBounds;
923 const SkStrokeRec& stroke) { 976 SkScalar fXRadius;
924 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); 977 SkScalar fYRadius;
925 SkScalar xRadius = SkScalarHalf(ellipse.width()); 978 SkScalar fInnerXRadius;
926 SkScalar yRadius = SkScalarHalf(ellipse.height()); 979 SkScalar fInnerYRadius;
980 SkScalar fGeoDx;
981 SkScalar fGeoDy;
982 GrColor fColor;
983 DIEllipseStyle fStyle;
984 };
927 985
928 SkStrokeRec::Style style = stroke.getStyle(); 986 static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) {
929 DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ? 987 return new DIEllipseBatch(geometry, bounds);
930 DIEllipseStyle::kStroke :
931 (SkStrokeRec::kHairline_Style == style) ?
932 DIEllipseStyle::kHairline : DIEllipseStyle::kF ill;
933
934 SkScalar innerXRadius = 0;
935 SkScalar innerYRadius = 0;
936 if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
937 SkScalar strokeWidth = stroke.getWidth();
938
939 if (SkScalarNearlyZero(strokeWidth)) {
940 strokeWidth = SK_ScalarHalf;
941 } else {
942 strokeWidth *= SK_ScalarHalf;
943 }
944
945 // we only handle thick strokes for near-circular ellipses
946 if (strokeWidth > SK_ScalarHalf &&
947 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad ius)) {
948 return nullptr;
949 }
950
951 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
952 if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadiu s ||
953 strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadiu s) {
954 return nullptr;
955 }
956
957 // set inner radius (if needed)
958 if (SkStrokeRec::kStroke_Style == style) {
959 innerXRadius = xRadius - strokeWidth;
960 innerYRadius = yRadius - strokeWidth;
961 }
962
963 xRadius += strokeWidth;
964 yRadius += strokeWidth;
965 }
966 if (DIEllipseStyle::kStroke == dieStyle) {
967 dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle : :kStroke :
968 DIEllipseStyle ::kFill;
969 }
970
971 // This expands the outer rect so that after CTM we end up with a half-p ixel border
972 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
973 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
974 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
975 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
976 SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
977 SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
978
979 DIEllipseBatch* batch = new DIEllipseBatch();
980 batch->fGeoData.emplace_back(Geometry {
981 viewMatrix,
982 color,
983 xRadius,
984 yRadius,
985 innerXRadius,
986 innerYRadius,
987 geoDx,
988 geoDy,
989 dieStyle,
990 SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
991 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)
992 });
993 SkRect devBounds = batch->fGeoData.back().fBounds;
994 viewMatrix.mapRect(&devBounds);
995 batch->setBounds(devBounds);
996 return batch;
997 } 988 }
998 989
999 const char* name() const override { return "DIEllipseBatch"; } 990 const char* name() const override { return "DIEllipseBatch"; }
1000 991
1001 void computePipelineOptimizations(GrInitInvariantOutput* color, 992 void computePipelineOptimizations(GrInitInvariantOutput* color,
1002 GrInitInvariantOutput* coverage, 993 GrInitInvariantOutput* coverage,
1003 GrBatchToXPOverrides* overrides) const ove rride { 994 GrBatchToXPOverrides* overrides) const ove rride {
1004 // 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
1005 color->setKnownFourComponents(fGeoData[0].fColor); 996 color->setKnownFourComponents(fGeoData[0].fColor);
1006 coverage->setUnknownSingleComponent(); 997 coverage->setUnknownSingleComponent();
1007 } 998 }
1008 999
1009 private: 1000 private:
1010 1001
1011 DIEllipseBatch() : INHERITED(ClassID()) {}
1012
1013 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 1002 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1014 // Handle any overrides that affect our GP. 1003 // Handle any overrides that affect our GP.
1015 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 1004 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1016 fUsesLocalCoords = overrides.readsLocalCoords(); 1005 fUsesLocalCoords = overrides.readsLocalCoords();
1017 } 1006 }
1018 1007
1019 void onPrepareDraws(Target* target) const override { 1008 void onPrepareDraws(Target* target) const override {
1020 // Setup geometry processor 1009 // Setup geometry processor
1021 SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this ->viewMatrix(), 1010 SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this ->viewMatrix(),
1022 this ->style())); 1011 this ->style()));
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 1054 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1066 verts[3].fColor = color; 1055 verts[3].fColor = color;
1067 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);
1068 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -inner RatioY - offsetDy); 1057 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -inner RatioY - offsetDy);
1069 1058
1070 verts += kVerticesPerQuad; 1059 verts += kVerticesPerQuad;
1071 } 1060 }
1072 helper.recordDraw(target, gp); 1061 helper.recordDraw(target, gp);
1073 } 1062 }
1074 1063
1064 DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(C lassID()) {
1065 fGeoData.push_back(geometry);
1066
1067 this->setBounds(bounds);
1068 }
1069
1075 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 1070 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1076 DIEllipseBatch* that = t->cast<DIEllipseBatch>(); 1071 DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1077 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), 1072 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(),
1078 that->bounds(), caps)) { 1073 that->bounds(), caps)) {
1079 return false; 1074 return false;
1080 } 1075 }
1081 1076
1082 if (this->style() != that->style()) { 1077 if (this->style() != that->style()) {
1083 return false; 1078 return false;
1084 } 1079 }
1085 1080
1086 // TODO rewrite to allow positioning on CPU 1081 // TODO rewrite to allow positioning on CPU
1087 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 1082 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1088 return false; 1083 return false;
1089 } 1084 }
1090 1085
1091 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1086 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1092 this->joinBounds(that->bounds()); 1087 this->joinBounds(that->bounds());
1093 return true; 1088 return true;
1094 } 1089 }
1095 1090
1096 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } 1091 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1097 DIEllipseStyle style() const { return fGeoData[0].fStyle; } 1092 DIEllipseStyle style() const { return fGeoData[0].fStyle; }
1098 1093
1099 struct Geometry {
1100 SkMatrix fViewMatrix;
1101 GrColor fColor;
1102 SkScalar fXRadius;
1103 SkScalar fYRadius;
1104 SkScalar fInnerXRadius;
1105 SkScalar fInnerYRadius;
1106 SkScalar fGeoDx;
1107 SkScalar fGeoDy;
1108 DIEllipseStyle fStyle;
1109 SkRect fBounds;
1110 };
1111
1112 bool fUsesLocalCoords; 1094 bool fUsesLocalCoords;
1113 SkSTArray<1, Geometry, true> fGeoData; 1095 SkSTArray<1, Geometry, true> fGeoData;
1114 1096
1115 typedef GrVertexBatch INHERITED; 1097 typedef GrVertexBatch INHERITED;
1116 }; 1098 };
1117 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
1118 /////////////////////////////////////////////////////////////////////////////// 1184 ///////////////////////////////////////////////////////////////////////////////
1119 1185
1120 static const uint16_t gRRectIndices[] = { 1186 static const uint16_t gRRectIndices[] = {
1121 // corners 1187 // corners
1122 0, 1, 5, 0, 5, 4, 1188 0, 1, 5, 0, 5, 4,
1123 2, 3, 7, 2, 7, 6, 1189 2, 3, 7, 2, 7, 6,
1124 8, 9, 13, 8, 13, 12, 1190 8, 9, 13, 8, 13, 12,
1125 10, 11, 15, 10, 15, 14, 1191 10, 11, 15, 10, 15, 14,
1126 1192
1127 // edges 1193 // edges
(...skipping 29 matching lines...) Expand all
1157 1223
1158 } 1224 }
1159 } 1225 }
1160 1226
1161 //////////////////////////////////////////////////////////////////////////////// /////////////////// 1227 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1162 1228
1163 class RRectCircleRendererBatch : public GrVertexBatch { 1229 class RRectCircleRendererBatch : public GrVertexBatch {
1164 public: 1230 public:
1165 DEFINE_BATCH_CLASS_ID 1231 DEFINE_BATCH_CLASS_ID
1166 1232
1167 // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then s trokeOnly indicates 1233 struct Geometry {
1168 // whether the rrect is only stroked or stroked and filled. 1234 SkRect fDevBounds;
1169 RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const Sk Rect& devRect, 1235 SkScalar fInnerRadius;
1170 float devRadius, float devStrokeWidth, bool strokeO nly) 1236 SkScalar fOuterRadius;
1171 : INHERITED(ClassID()) 1237 GrColor fColor;
1172 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 1238 };
1173 SkRect bounds = devRect;
1174 SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
1175 SkScalar innerRadius = 0.0f;
1176 SkScalar outerRadius = devRadius;
1177 SkScalar halfWidth = 0;
1178 fStroked = false;
1179 if (devStrokeWidth > 0) {
1180 if (SkScalarNearlyZero(devStrokeWidth)) {
1181 halfWidth = SK_ScalarHalf;
1182 } else {
1183 halfWidth = SkScalarHalf(devStrokeWidth);
1184 }
1185 1239
1186 if (strokeOnly) { 1240 RRectCircleRendererBatch(const Geometry& geometry, const SkMatrix& viewMatri x, bool stroked)
1187 innerRadius = devRadius - halfWidth; 1241 : INHERITED(ClassID())
1188 fStroked = innerRadius >= 0; 1242 , fStroked(stroked)
1189 } 1243 , fViewMatrixIfUsingLocalCoords(viewMatrix) {
1190 outerRadius += halfWidth; 1244 fGeoData.push_back(geometry);
1191 bounds.outset(halfWidth, halfWidth);
1192 }
1193 1245
1194 // The radii are outset for two reasons. First, it allows the shader to simply perform 1246 this->setBounds(geometry.fDevBounds);
1195 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1196 // Second, the outer radius is used to compute the verts of the bounding box that is
1197 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1198 // corners.
1199 outerRadius += SK_ScalarHalf;
1200 innerRadius -= SK_ScalarHalf;
1201
1202 // Expand the rect so all the pixels will be captured.
1203 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1204
1205 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds });
1206 this->setBounds(bounds);
1207 } 1247 }
1208 1248
1209 const char* name() const override { return "RRectCircleBatch"; } 1249 const char* name() const override { return "RRectCircleBatch"; }
1210 1250
1211 void computePipelineOptimizations(GrInitInvariantOutput* color, 1251 void computePipelineOptimizations(GrInitInvariantOutput* color,
1212 GrInitInvariantOutput* coverage, 1252 GrInitInvariantOutput* coverage,
1213 GrBatchToXPOverrides* overrides) const ove rride { 1253 GrBatchToXPOverrides* overrides) const ove rride {
1214 // 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
1215 color->setKnownFourComponents(fGeoData[0].fColor); 1255 color->setKnownFourComponents(fGeoData[0].fColor);
1216 coverage->setUnknownSingleComponent(); 1256 coverage->setUnknownSingleComponent();
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1318 1358
1319 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 1359 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
1320 return false; 1360 return false;
1321 } 1361 }
1322 1362
1323 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1363 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1324 this->joinBounds(that->bounds()); 1364 this->joinBounds(that->bounds());
1325 return true; 1365 return true;
1326 } 1366 }
1327 1367
1328 struct Geometry {
1329 GrColor fColor;
1330 SkScalar fInnerRadius;
1331 SkScalar fOuterRadius;
1332 SkRect fDevBounds;
1333 };
1334
1335 bool fStroked; 1368 bool fStroked;
1336 SkMatrix fViewMatrixIfUsingLocalCoords; 1369 SkMatrix fViewMatrixIfUsingLocalCoords;
1337 SkSTArray<1, Geometry, true> fGeoData; 1370 SkSTArray<1, Geometry, true> fGeoData;
1338 1371
1339 typedef GrVertexBatch INHERITED; 1372 typedef GrVertexBatch INHERITED;
1340 }; 1373 };
1341 1374
1342 class RRectEllipseRendererBatch : public GrVertexBatch { 1375 class RRectEllipseRendererBatch : public GrVertexBatch {
1343 public: 1376 public:
1344 DEFINE_BATCH_CLASS_ID 1377 DEFINE_BATCH_CLASS_ID
1345 1378
1346 // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, s trokeOnly indicates 1379 struct Geometry {
1347 // whether the rrect is only stroked or stroked and filled. 1380 SkRect fDevBounds;
1348 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect, 1381 SkScalar fXRadius;
1349 float devXRadius, float devYRadius, SkVector devS trokeWidths, 1382 SkScalar fYRadius;
1350 bool strokeOnly) { 1383 SkScalar fInnerXRadius;
1351 SkASSERT(devXRadius > 0.5); 1384 SkScalar fInnerYRadius;
1352 SkASSERT(devYRadius > 0.5); 1385 GrColor fColor;
1353 SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0)); 1386 };
1354 SkASSERT(!(strokeOnly && devStrokeWidths.fX <= 0));
1355 SkScalar innerXRadius = 0.0f;
1356 SkScalar innerYRadius = 0.0f;
1357 SkRect bounds = devRect;
1358 bool stroked = false;
1359 if (devStrokeWidths.fX > 0) {
1360 if (SkScalarNearlyZero(devStrokeWidths.length())) {
1361 devStrokeWidths.set(SK_ScalarHalf, SK_ScalarHalf);
1362 } else {
1363 devStrokeWidths.scale(SK_ScalarHalf);
1364 }
1365 1387
1366 // we only handle thick strokes for near-circular ellipses 1388 RRectEllipseRendererBatch(const Geometry& geometry, const SkMatrix& viewMatr ix, bool stroked)
1367 if (devStrokeWidths.length() > SK_ScalarHalf && 1389 : INHERITED(ClassID())
1368 (SK_ScalarHalf*devXRadius > devYRadius || SK_ScalarHalf*devYRadi us > devXRadius)) { 1390 , fStroked(stroked)
1369 return nullptr; 1391 , fViewMatrixIfUsingLocalCoords(viewMatrix) {
1370 } 1392 fGeoData.push_back(geometry);
1371 1393 this->setBounds(geometry.fDevBounds);
1372 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
1373 if (devStrokeWidths.fX*(devYRadius*devYRadius) <
1374 (devStrokeWidths.fY*devStrokeWidths.fY)*devXRadius) {
1375 return nullptr;
1376 }
1377 if (devStrokeWidths.fY*(devXRadius*devXRadius) <
1378 (devStrokeWidths.fX*devStrokeWidths.fX)*devYRadius) {
1379 return nullptr;
1380 }
1381
1382 // this is legit only if scale & translation (which should be the ca se at the moment)
1383 if (strokeOnly) {
1384 innerXRadius = devXRadius - devStrokeWidths.fX;
1385 innerYRadius = devYRadius - devStrokeWidths.fY;
1386 stroked = (innerXRadius >= 0 && innerYRadius >= 0);
1387 }
1388
1389 devXRadius += devStrokeWidths.fX;
1390 devYRadius += devStrokeWidths.fY;
1391 bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY);
1392 }
1393
1394 // Expand the rect so all the pixels will be captured.
1395 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1396
1397 RRectEllipseRendererBatch* batch = new RRectEllipseRendererBatch();
1398 batch->fStroked = stroked;
1399 batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
1400 batch->fGeoData.emplace_back(
1401 Geometry {color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds});
1402 batch->setBounds(bounds);
1403 return batch;
1404 } 1394 }
1405 1395
1406 const char* name() const override { return "RRectEllipseRendererBatch"; } 1396 const char* name() const override { return "RRectEllipseRendererBatch"; }
1407 1397
1408 void computePipelineOptimizations(GrInitInvariantOutput* color, 1398 void computePipelineOptimizations(GrInitInvariantOutput* color,
1409 GrInitInvariantOutput* coverage, 1399 GrInitInvariantOutput* coverage,
1410 GrBatchToXPOverrides* overrides) const ove rride { 1400 GrBatchToXPOverrides* overrides) const ove rride {
1411 // 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
1412 color->setKnownFourComponents(fGeoData[0].fColor); 1402 color->setKnownFourComponents(fGeoData[0].fColor);
1413 coverage->setUnknownSingleComponent(); 1403 coverage->setUnknownSingleComponent();
1414 } 1404 }
1415 1405
1416 private: 1406 private:
1417 RRectEllipseRendererBatch() : INHERITED(ClassID()) {}
1418
1419 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 1407 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1420 // Handle overrides that affect our GP. 1408 // Handle overrides that affect our GP.
1421 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 1409 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1422 if (!overrides.readsLocalCoords()) { 1410 if (!overrides.readsLocalCoords()) {
1423 fViewMatrixIfUsingLocalCoords.reset(); 1411 fViewMatrixIfUsingLocalCoords.reset();
1424 } 1412 }
1425 } 1413 }
1426 1414
1427 void onPrepareDraws(Target* target) const override { 1415 void onPrepareDraws(Target* target) const override {
1428 SkMatrix localMatrix; 1416 SkMatrix localMatrix;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1528 1516
1529 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 1517 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
1530 return false; 1518 return false;
1531 } 1519 }
1532 1520
1533 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1521 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1534 this->joinBounds(that->bounds()); 1522 this->joinBounds(that->bounds());
1535 return true; 1523 return true;
1536 } 1524 }
1537 1525
1538 struct Geometry {
1539 GrColor fColor;
1540 SkScalar fXRadius;
1541 SkScalar fYRadius;
1542 SkScalar fInnerXRadius;
1543 SkScalar fInnerYRadius;
1544 SkRect fDevBounds;
1545 };
1546
1547 bool fStroked; 1526 bool fStroked;
1548 SkMatrix fViewMatrixIfUsingLocalCoords; 1527 SkMatrix fViewMatrixIfUsingLocalCoords;
1549 SkSTArray<1, Geometry, true> fGeoData; 1528 SkSTArray<1, Geometry, true> fGeoData;
1550 1529
1551 typedef GrVertexBatch INHERITED; 1530 typedef GrVertexBatch INHERITED;
1552 }; 1531 };
1553 1532
1554 static GrDrawBatch* create_rrect_batch(GrColor color, 1533 static GrDrawBatch* create_rrect_batch(GrColor color,
1555 const SkMatrix& viewMatrix, 1534 const SkMatrix& viewMatrix,
1556 const SkRRect& rrect, 1535 const SkRRect& rrect,
1557 const SkStrokeRec& stroke) { 1536 const SkStrokeRec& stroke) {
1558 SkASSERT(viewMatrix.rectStaysRect()); 1537 SkASSERT(viewMatrix.rectStaysRect());
1559 SkASSERT(rrect.isSimple()); 1538 SkASSERT(rrect.isSimple());
1560 SkASSERT(!rrect.isOval()); 1539 SkASSERT(!rrect.isOval());
1561 1540
1562 // RRect batchs only handle simple, but not too simple, rrects 1541 // RRect batchs only handle simple, but not too simple, rrects
1563 // 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
1564 const SkRect& rrectBounds = rrect.getBounds(); 1543 const SkRect& rrectBounds = rrect.getBounds();
1565 SkRect bounds; 1544 SkRect bounds;
1566 viewMatrix.mapRect(&bounds, rrectBounds); 1545 viewMatrix.mapRect(&bounds, rrectBounds);
1567 1546
1568 SkVector radii = rrect.getSimpleRadii(); 1547 SkVector radii = rrect.getSimpleRadii();
1569 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX + 1548 SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
1570 viewMatrix[SkMatrix::kMSkewY]*radii.fY); 1549 viewMatrix[SkMatrix::kMSkewY]*radii.fY);
1571 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX + 1550 SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
1572 viewMatrix[SkMatrix::kMScaleY]*radii.fY); 1551 viewMatrix[SkMatrix::kMScaleY]*radii.fY);
1573 1552
1574 SkStrokeRec::Style style = stroke.getStyle(); 1553 SkStrokeRec::Style style = stroke.getStyle();
1575 1554
1576 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws. 1555 // do (potentially) anisotropic mapping of stroke
1577 SkVector scaledStroke = {-1, -1}; 1556 SkVector scaledStroke;
1578 SkScalar strokeWidth = stroke.getWidth(); 1557 SkScalar strokeWidth = stroke.getWidth();
1579 1558
1580 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 1559 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1581 SkStrokeRec::kHairline_Style == style; 1560 SkStrokeRec::kHairline_Style == style;
1582 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 1561 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1583 1562
1584 if (hasStroke) { 1563 if (hasStroke) {
1585 if (SkStrokeRec::kHairline_Style == style) { 1564 if (SkStrokeRec::kHairline_Style == style) {
1586 scaledStroke.set(1, 1); 1565 scaledStroke.set(1, 1);
1587 } else { 1566 } else {
(...skipping 13 matching lines...) Expand all
1601 // 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-
1602 // 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.
1603 // 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
1604 // indistinguishable from a square corner. 1583 // indistinguishable from a square corner.
1605 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { 1584 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
1606 return nullptr; 1585 return nullptr;
1607 } 1586 }
1608 1587
1609 // if the corners are circles, use the circle renderer 1588 // if the corners are circles, use the circle renderer
1610 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { 1589 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) {
1611 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, 1590 SkScalar innerRadius = 0.0f;
1612 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);
1613 // otherwise we use the ellipse renderer 1627 // otherwise we use the ellipse renderer
1614 } else { 1628 } else {
1615 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius, 1629 SkScalar innerXRadius = 0.0f;
1616 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 }
1617 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) ;
1618 } 1675 }
1619 } 1676 }
1620 1677
1621 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, 1678 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color,
1622 const SkMatrix& viewMatrix, 1679 const SkMatrix& viewMatrix,
1623 const SkRRect& rrect, 1680 const SkRRect& rrect,
1624 const SkStrokeRec& stroke, 1681 const SkStrokeRec& stroke,
1625 GrShaderCaps* shaderCaps) { 1682 GrShaderCaps* shaderCaps) {
1626 if (rrect.isOval()) { 1683 if (rrect.isOval()) {
1627 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha derCaps); 1684 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha derCaps);
1628 } 1685 }
1629 1686
1630 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { 1687 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
1631 return nullptr; 1688 return nullptr;
1632 } 1689 }
1633 1690
1634 return create_rrect_batch(color, viewMatrix, rrect, stroke); 1691 return create_rrect_batch(color, viewMatrix, rrect, stroke);
1635 } 1692 }
1636 1693
1637 /////////////////////////////////////////////////////////////////////////////// 1694 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1638
1639 GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
1640 const SkMatrix& viewMatrix,
1641 const SkRect& oval,
1642 const SkStrokeRec& stroke,
1643 GrShaderCaps* shaderCaps) {
1644 // we can draw circles
1645 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle( viewMatrix)) {
1646 return new CircleBatch(color, viewMatrix, oval, stroke);
1647 }
1648
1649 // if we have shader derivative support, render as device-independent
1650 if (shaderCaps->shaderDerivativeSupport()) {
1651 return DIEllipseBatch::Create(color, viewMatrix, oval, stroke);
1652 }
1653
1654 // otherwise axis-aligned ellipses only
1655 if (viewMatrix.rectStaysRect()) {
1656 return EllipseBatch::Create(color, viewMatrix, oval, stroke);
1657 }
1658
1659 return nullptr;
1660 }
1661
1662 ///////////////////////////////////////////////////////////////////////////////
1663 1695
1664 #ifdef GR_TEST_UTILS 1696 #ifdef GR_TEST_UTILS
1665 1697
1666 DRAW_BATCH_TEST_DEFINE(CircleBatch) { 1698 DRAW_BATCH_TEST_DEFINE(CircleBatch) {
1667 SkMatrix viewMatrix = GrTest::TestMatrix(random); 1699 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1668 GrColor color = GrRandomColor(random); 1700 GrColor color = GrRandomColor(random);
1669 SkRect circle = GrTest::TestSquare(random); 1701 SkRect circle = GrTest::TestSquare(random);
1670 return new CircleBatch(color, viewMatrix, circle, GrTest::TestStrokeRec(rand om)); 1702 return create_circle_batch(color, viewMatrix, circle, GrTest::TestStrokeRec( random));
1671 } 1703 }
1672 1704
1673 DRAW_BATCH_TEST_DEFINE(EllipseBatch) { 1705 DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
1674 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); 1706 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1675 GrColor color = GrRandomColor(random); 1707 GrColor color = GrRandomColor(random);
1676 SkRect ellipse = GrTest::TestSquare(random); 1708 SkRect ellipse = GrTest::TestSquare(random);
1677 return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRe c(random)); 1709 return create_ellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRe c(random));
1678 } 1710 }
1679 1711
1680 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) { 1712 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
1681 SkMatrix viewMatrix = GrTest::TestMatrix(random); 1713 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1682 GrColor color = GrRandomColor(random); 1714 GrColor color = GrRandomColor(random);
1683 SkRect ellipse = GrTest::TestSquare(random); 1715 SkRect ellipse = GrTest::TestSquare(random);
1684 return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStroke Rec(random)); 1716 return create_diellipse_batch(color, viewMatrix, ellipse, GrTest::TestStroke Rec(random));
1685 } 1717 }
1686 1718
1687 DRAW_BATCH_TEST_DEFINE(RRectBatch) { 1719 DRAW_BATCH_TEST_DEFINE(RRectBatch) {
1688 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); 1720 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1689 GrColor color = GrRandomColor(random); 1721 GrColor color = GrRandomColor(random);
1690 const SkRRect& rrect = GrTest::TestRRectSimple(random); 1722 const SkRRect& rrect = GrTest::TestRRectSimple(random);
1691 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom)); 1723 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom));
1692 } 1724 }
1693 1725
1694 #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