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

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

Issue 904753002: Ovals batch (Closed) Base URL: https://skia.googlesource.com/skia.git@convex
Patch Set: cleanup Created 5 years, 10 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/GrBatchTarget.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 "GrProcessor.h" 10 #include "GrBatch.h"
11 #include "GrBatchTarget.h"
12 #include "GrBufferAllocPool.h"
11 #include "GrDrawTarget.h" 13 #include "GrDrawTarget.h"
12 #include "GrGeometryProcessor.h" 14 #include "GrGeometryProcessor.h"
13 #include "GrGpu.h" 15 #include "GrGpu.h"
14 #include "GrInvariantOutput.h" 16 #include "GrInvariantOutput.h"
15 #include "GrPipelineBuilder.h" 17 #include "GrPipelineBuilder.h"
18 #include "GrProcessor.h"
16 #include "SkRRect.h" 19 #include "SkRRect.h"
17 #include "SkStrokeRec.h" 20 #include "SkStrokeRec.h"
18 #include "SkTLazy.h" 21 #include "SkTLazy.h"
19 #include "effects/GrRRectEffect.h" 22 #include "effects/GrRRectEffect.h"
20 #include "gl/GrGLProcessor.h" 23 #include "gl/GrGLProcessor.h"
21 #include "gl/GrGLSL.h" 24 #include "gl/GrGLSL.h"
22 #include "gl/GrGLGeometryProcessor.h" 25 #include "gl/GrGLGeometryProcessor.h"
23 #include "gl/builders/GrGLProgramBuilder.h" 26 #include "gl/builders/GrGLProgramBuilder.h"
24 27
25 namespace { 28 namespace {
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 stroke); 688 stroke);
686 } else { 689 } else {
687 return false; 690 return false;
688 } 691 }
689 692
690 return true; 693 return true;
691 } 694 }
692 695
693 /////////////////////////////////////////////////////////////////////////////// 696 ///////////////////////////////////////////////////////////////////////////////
694 697
698 class CircleBatch : public GrBatch {
699 public:
700 struct Geometry {
701 GrColor fColor;
702 SkMatrix fViewMatrix;
703 SkScalar fInnerRadius;
704 SkScalar fOuterRadius;
705 bool fStroke;
706 SkRect fDevBounds;
707 };
708
709 static GrBatch* Create(const Geometry& geometry) {
710 return SkNEW_ARGS(CircleBatch, (geometry));
711 }
712
713 const char* name() const SK_OVERRIDE { return "CircleBatch"; }
714
715 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
716 // When this is called on a batch, there is only one geometry bundle
717 out->setKnownFourComponents(fGeoData[0].fColor);
718 }
719 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
bsalomon 2015/02/10 14:31:21 \n
720 out->setUnknownSingleComponent();
721 }
722
723 void initBatchOpt(const GrBatchOpt& batchOpt) {
724 fBatchOpt = batchOpt;
725 }
726
727 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
728 // Handle any color overrides
729 if (init.fColorIgnored) {
730 fGeoData[0].fColor = GrColor_ILLEGAL;
731 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
732 fGeoData[0].fColor = init.fOverrideColor;
733 }
734
735 // setup batch properties
736 fBatch.fColorIgnored = init.fColorIgnored;
737 fBatch.fColor = fGeoData[0].fColor;
738 fBatch.fStroke = fGeoData[0].fStroke;
739 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
740 fBatch.fCoverageIgnored = init.fCoverageIgnored;
741 }
742
743 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
744 SkMatrix invert;
745 if (!this->viewMatrix().invert(&invert)) {
746 return;
747 }
748
749 // Setup geometry processor
750 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->colo r(),
751 this->stro ke(),
752 invert));
753
754 batchTarget->initDraw(gp, pipeline);
755
756 // TODO this is hacky, but the only way we have to initialize the GP is to use the
757 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
758 // everywhere we can remove this nastiness
759 GrPipelineInfo init;
760 init.fColorIgnored = fBatch.fColorIgnored;
761 init.fOverrideColor = GrColor_ILLEGAL;
762 init.fCoverageIgnored = fBatch.fCoverageIgnored;
763 init.fUsesLocalCoords = this->usesLocalCoords();
764 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
765
766 int instanceCount = fGeoData.count();
767 int vertexCount = kVertsPerCircle * instanceCount;
768 size_t vertexStride = gp->getVertexStride();
769 SkASSERT(vertexStride == sizeof(CircleVertex));
770
771 const GrVertexBuffer* vertexBuffer;
772 int firstVertex;
773
774 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
775 vertexCount,
776 &vertexBuffer,
777 &firstVertex);
778
779 CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
780
781 for (int i = 0; i < instanceCount; i++) {
782 Geometry& args = fGeoData[i];
783
784 SkScalar innerRadius = args.fInnerRadius;
785 SkScalar outerRadius = args.fOuterRadius;
786
787 const SkRect& bounds = args.fDevBounds;
788
789 // The inner radius in the vertex data must be specified in normaliz ed space.
790 innerRadius = innerRadius / outerRadius;
791 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
792 verts[0].fOffset = SkPoint::Make(-1, -1);
793 verts[0].fOuterRadius = outerRadius;
794 verts[0].fInnerRadius = innerRadius;
795
796 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
797 verts[1].fOffset = SkPoint::Make(-1, 1);
798 verts[1].fOuterRadius = outerRadius;
799 verts[1].fInnerRadius = innerRadius;
800
801 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
802 verts[2].fOffset = SkPoint::Make(1, 1);
803 verts[2].fOuterRadius = outerRadius;
804 verts[2].fInnerRadius = innerRadius;
805
806 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
807 verts[3].fOffset = SkPoint::Make(1, -1);
808 verts[3].fOuterRadius = outerRadius;
809 verts[3].fInnerRadius = innerRadius;
810
811 verts += kVertsPerCircle;
812 }
813
814 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
815
816 GrDrawTarget::DrawInfo drawInfo;
817 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
818 drawInfo.setStartVertex(0);
819 drawInfo.setStartIndex(0);
820 drawInfo.setVerticesPerInstance(kVertsPerCircle);
821 drawInfo.setIndicesPerInstance(kIndicesPerCircle);
822 drawInfo.adjustStartVertex(firstVertex);
823 drawInfo.setVertexBuffer(vertexBuffer);
824 drawInfo.setIndexBuffer(quadIndexBuffer);
825
826 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
827
828 while (instanceCount) {
829 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw) );
830 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
831 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
832
833 batchTarget->draw(drawInfo);
834
835 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
836 instanceCount -= drawInfo.instanceCount();
837 }
838 }
839
840 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
841
842 private:
843 CircleBatch(const Geometry& geometry) {
844 this->initClassID<CircleBatch>();
845 fGeoData.push_back(geometry);
846 }
847
848 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
849 CircleBatch* that = t->cast<CircleBatch>();
850
851 // TODO vertex color
bsalomon 2015/02/10 14:31:21 unclear... use vertex colors to avoid breaking bat
852 if (this->color() != that->color()) {
853 return false;
854 }
855
856 if (this->stroke() != that->stroke()) {
857 return false;
858 }
859
860 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
861 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
862 return false;
863 }
864
865 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
866 return true;
867 }
868
869 GrColor color() const { return fBatch.fColor; }
870 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
871 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
872 bool stroke() const { return fBatch.fStroke; }
873
874 struct BatchTracker {
875 GrColor fColor;
876 bool fStroke;
877 bool fUsesLocalCoords;
878 bool fColorIgnored;
879 bool fCoverageIgnored;
880 };
881
882 static const int kVertsPerCircle = 4;
883 static const int kIndicesPerCircle = 6;
884
885 GrBatchOpt fBatchOpt;
886 BatchTracker fBatch;
887 SkSTArray<1, Geometry, true> fGeoData;
888 };
889
695 void GrOvalRenderer::drawCircle(GrDrawTarget* target, 890 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
696 GrPipelineBuilder* pipelineBuilder, 891 GrPipelineBuilder* pipelineBuilder,
697 GrColor color, 892 GrColor color,
698 const SkMatrix& viewMatrix, 893 const SkMatrix& viewMatrix,
699 bool useCoverageAA, 894 bool useCoverageAA,
700 const SkRect& circle, 895 const SkRect& circle,
701 const SkStrokeRec& stroke) { 896 const SkStrokeRec& stroke) {
702 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY()); 897 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
703 viewMatrix.mapPoints(&center, 1); 898 viewMatrix.mapPoints(&center, 1);
704 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width())); 899 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
705 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth()); 900 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
706 901
707 SkMatrix invert;
708 if (!viewMatrix.invert(&invert)) {
709 return;
710 }
711
712 SkStrokeRec::Style style = stroke.getStyle(); 902 SkStrokeRec::Style style = stroke.getStyle();
713 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 903 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
714 SkStrokeRec::kHairline_Style == style; 904 SkStrokeRec::kHairline_Style == style;
715 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 905 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
716 906
717 SkScalar innerRadius = 0.0f; 907 SkScalar innerRadius = 0.0f;
718 SkScalar outerRadius = radius; 908 SkScalar outerRadius = radius;
719 SkScalar halfWidth = 0; 909 SkScalar halfWidth = 0;
720 if (hasStroke) { 910 if (hasStroke) {
721 if (SkScalarNearlyZero(strokeWidth)) { 911 if (SkScalarNearlyZero(strokeWidth)) {
722 halfWidth = SK_ScalarHalf; 912 halfWidth = SK_ScalarHalf;
723 } else { 913 } else {
724 halfWidth = SkScalarHalf(strokeWidth); 914 halfWidth = SkScalarHalf(strokeWidth);
725 } 915 }
726 916
727 outerRadius += halfWidth; 917 outerRadius += halfWidth;
728 if (isStrokeOnly) { 918 if (isStrokeOnly) {
729 innerRadius = radius - halfWidth; 919 innerRadius = radius - halfWidth;
730 } 920 }
731 } 921 }
732 922
733 SkAutoTUnref<GrGeometryProcessor> gp(
734 CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0,inve rt));
735
736 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
737 SkASSERT(gp->getVertexStride() == sizeof(CircleVertex));
738 if (!geo.succeeded()) {
739 SkDebugf("Failed to get space for vertices!\n");
740 return;
741 }
742
743 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
744
745 // The radii are outset for two reasons. First, it allows the shader to simp ly perform simpler 923 // The radii are outset for two reasons. First, it allows the shader to simp ly perform simpler
746 // computation because the computed alpha is zero, rather than 50%, at the r adius. 924 // computation because the computed alpha is zero, rather than 50%, at the r adius.
747 // Second, the outer radius is used to compute the verts of the bounding box that is rendered 925 // Second, the outer radius is used to compute the verts of the bounding box that is rendered
748 // and the outset ensures the box will cover all partially covered by the ci rcle. 926 // and the outset ensures the box will cover all partially covered by the ci rcle.
749 outerRadius += SK_ScalarHalf; 927 outerRadius += SK_ScalarHalf;
750 innerRadius -= SK_ScalarHalf; 928 innerRadius -= SK_ScalarHalf;
751 929
752 SkRect bounds = SkRect::MakeLTRB( 930 SkRect bounds = SkRect::MakeLTRB(
753 center.fX - outerRadius, 931 center.fX - outerRadius,
754 center.fY - outerRadius, 932 center.fY - outerRadius,
755 center.fX + outerRadius, 933 center.fX + outerRadius,
756 center.fY + outerRadius 934 center.fY + outerRadius
757 ); 935 );
758 936
759 // The inner radius in the vertex data must be specified in normalized space . 937 CircleBatch::Geometry geometry;
760 innerRadius = innerRadius / outerRadius; 938 geometry.fViewMatrix = viewMatrix;
761 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 939 geometry.fColor = color;
762 verts[0].fOffset = SkPoint::Make(-1, -1); 940 geometry.fInnerRadius = innerRadius;
763 verts[0].fOuterRadius = outerRadius; 941 geometry.fOuterRadius = outerRadius;
764 verts[0].fInnerRadius = innerRadius; 942 geometry.fStroke = isStrokeOnly && innerRadius > 0;
765 943 geometry.fDevBounds = bounds;
766 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 944
767 verts[1].fOffset = SkPoint::Make(-1, 1); 945 SkAutoTUnref<GrBatch> batch(CircleBatch::Create(geometry));
768 verts[1].fOuterRadius = outerRadius; 946 target->drawBatch(pipelineBuilder, batch, &bounds);
769 verts[1].fInnerRadius = innerRadius;
770
771 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
772 verts[2].fOffset = SkPoint::Make(1, 1);
773 verts[2].fOuterRadius = outerRadius;
774 verts[2].fInnerRadius = innerRadius;
775
776 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
777 verts[3].fOffset = SkPoint::Make(1, -1);
778 verts[3].fOuterRadius = outerRadius;
779 verts[3].fInnerRadius = innerRadius;
780
781 target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
782 target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType , 1, 4, 6, &bounds);
783 target->resetIndexSource();
784 } 947 }
785 948
786 /////////////////////////////////////////////////////////////////////////////// 949 ///////////////////////////////////////////////////////////////////////////////
787 950
951 class EllipseBatch : public GrBatch {
952 public:
953 struct Geometry {
954 GrColor fColor;
955 SkMatrix fViewMatrix;
956 SkScalar fXRadius;
957 SkScalar fYRadius;
958 SkScalar fInnerXRadius;
959 SkScalar fInnerYRadius;
960 bool fStroke;
961 SkRect fDevBounds;
962 };
963
964 static GrBatch* Create(const Geometry& geometry) {
965 return SkNEW_ARGS(EllipseBatch, (geometry));
966 }
967
968 const char* name() const SK_OVERRIDE { return "EllipseBatch"; }
969
970 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
971 // When this is called on a batch, there is only one geometry bundle
972 out->setKnownFourComponents(fGeoData[0].fColor);
973 }
974 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
975 out->setUnknownSingleComponent();
976 }
977
978 void initBatchOpt(const GrBatchOpt& batchOpt) {
979 fBatchOpt = batchOpt;
980 }
981
982 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
983 // Handle any color overrides
984 if (init.fColorIgnored) {
985 fGeoData[0].fColor = GrColor_ILLEGAL;
986 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
987 fGeoData[0].fColor = init.fOverrideColor;
988 }
989
990 // setup batch properties
991 fBatch.fColorIgnored = init.fColorIgnored;
992 fBatch.fColor = fGeoData[0].fColor;
993 fBatch.fStroke = fGeoData[0].fStroke;
994 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
995 fBatch.fCoverageIgnored = init.fCoverageIgnored;
996 }
997
998 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
999 SkMatrix invert;
1000 if (!this->viewMatrix().invert(&invert)) {
bsalomon 2015/02/10 14:31:21 wonder if fin future we will need to do this inver
joshualitt 2015/02/10 15:08:08 The model I'm kind of imagining for this is basica
1001 return;
1002 }
1003
1004 // Setup geometry processor
1005 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->col or(),
1006 this->str oke(),
1007 invert));
1008 SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
1009
1010 batchTarget->initDraw(gp, pipeline);
1011
1012 // TODO this is hacky, but the only way we have to initialize the GP is to use the
1013 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
1014 // everywhere we can remove this nastiness
1015 GrPipelineInfo init;
1016 init.fColorIgnored = fBatch.fColorIgnored;
1017 init.fOverrideColor = GrColor_ILLEGAL;
1018 init.fCoverageIgnored = fBatch.fCoverageIgnored;
1019 init.fUsesLocalCoords = this->usesLocalCoords();
1020 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1021
1022 int instanceCount = fGeoData.count();
1023 int vertexCount = kVertsPerEllipse * instanceCount;
1024 size_t vertexStride = gp->getVertexStride();
1025 SkASSERT(vertexStride == sizeof(CircleVertex));
1026
1027 const GrVertexBuffer* vertexBuffer;
1028 int firstVertex;
1029
1030 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1031 vertexCount,
1032 &vertexBuffer,
1033 &firstVertex);
1034
1035 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
1036
1037 for (int i = 0; i < instanceCount; i++) {
1038 Geometry& args = fGeoData[i];
1039
1040 SkScalar xRadius = args.fXRadius;
1041 SkScalar yRadius = args.fYRadius;
1042
1043 // Compute the reciprocals of the radii here to save time in the sha der
1044 SkScalar xRadRecip = SkScalarInvert(xRadius);
1045 SkScalar yRadRecip = SkScalarInvert(yRadius);
1046 SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1047 SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1048
1049 const SkRect& bounds = args.fDevBounds;
1050
1051 // The inner radius in the vertex data must be specified in normaliz ed space.
1052 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1053 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
1054 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1055 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip) ;
1056
1057 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
1058 verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
1059 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1060 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip) ;
1061
1062 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1063 verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
1064 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1065 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip) ;
1066
1067 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1068 verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
1069 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1070 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip) ;
1071
1072 verts += kVertsPerEllipse;
1073 }
1074
1075 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
1076
1077 GrDrawTarget::DrawInfo drawInfo;
1078 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1079 drawInfo.setStartVertex(0);
1080 drawInfo.setStartIndex(0);
1081 drawInfo.setVerticesPerInstance(kVertsPerEllipse);
1082 drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
1083 drawInfo.adjustStartVertex(firstVertex);
1084 drawInfo.setVertexBuffer(vertexBuffer);
1085 drawInfo.setIndexBuffer(quadIndexBuffer);
1086
1087 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
1088
1089 while (instanceCount) {
1090 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw) );
1091 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
1092 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
1093
1094 batchTarget->draw(drawInfo);
1095
1096 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
1097 instanceCount -= drawInfo.instanceCount();
1098 }
1099 }
1100
1101 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1102
1103 private:
1104 EllipseBatch(const Geometry& geometry) {
1105 this->initClassID<EllipseBatch>();
1106 fGeoData.push_back(geometry);
1107 }
1108
1109 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1110 EllipseBatch* that = t->cast<EllipseBatch>();
1111
1112 // TODO vertex color
1113 if (this->color() != that->color()) {
1114 return false;
1115 }
1116
1117 if (this->stroke() != that->stroke()) {
1118 return false;
1119 }
1120
1121 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1122 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
1123 return false;
1124 }
1125
1126 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
1127 return true;
1128 }
1129
1130 GrColor color() const { return fBatch.fColor; }
1131 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1132 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1133 bool stroke() const { return fBatch.fStroke; }
1134
1135 struct BatchTracker {
1136 GrColor fColor;
1137 bool fStroke;
1138 bool fUsesLocalCoords;
1139 bool fColorIgnored;
1140 bool fCoverageIgnored;
1141 };
1142
1143 static const int kVertsPerEllipse = 4;
1144 static const int kIndicesPerEllipse = 6;
1145
1146 GrBatchOpt fBatchOpt;
1147 BatchTracker fBatch;
1148 SkSTArray<1, Geometry, true> fGeoData;
1149 };
1150
788 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target, 1151 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
789 GrPipelineBuilder* pipelineBuilder, 1152 GrPipelineBuilder* pipelineBuilder,
790 GrColor color, 1153 GrColor color,
791 const SkMatrix& viewMatrix, 1154 const SkMatrix& viewMatrix,
792 bool useCoverageAA, 1155 bool useCoverageAA,
793 const SkRect& ellipse, 1156 const SkRect& ellipse,
794 const SkStrokeRec& stroke) { 1157 const SkStrokeRec& stroke) {
795 #ifdef SK_DEBUG 1158 #ifdef SK_DEBUG
796 { 1159 {
797 // we should have checked for this previously 1160 // we should have checked for this previously
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 // this is legit only if scale & translation (which should be the case a t the moment) 1210 // this is legit only if scale & translation (which should be the case a t the moment)
848 if (isStrokeOnly) { 1211 if (isStrokeOnly) {
849 innerXRadius = xRadius - scaledStroke.fX; 1212 innerXRadius = xRadius - scaledStroke.fX;
850 innerYRadius = yRadius - scaledStroke.fY; 1213 innerYRadius = yRadius - scaledStroke.fY;
851 } 1214 }
852 1215
853 xRadius += scaledStroke.fX; 1216 xRadius += scaledStroke.fX;
854 yRadius += scaledStroke.fY; 1217 yRadius += scaledStroke.fY;
855 } 1218 }
856 1219
857 SkMatrix invert;
858 if (!viewMatrix.invert(&invert)) {
859 return false;
860 }
861
862 SkAutoTUnref<GrGeometryProcessor> gp(
863 EllipseEdgeEffect::Create(color,
864 isStrokeOnly && innerXRadius > 0 && innerY Radius > 0,
865 invert));
866
867 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
868 SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
869 if (!geo.succeeded()) {
870 SkDebugf("Failed to get space for vertices!\n");
871 return false;
872 }
873
874 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
875
876 // Compute the reciprocals of the radii here to save time in the shader
877 SkScalar xRadRecip = SkScalarInvert(xRadius);
878 SkScalar yRadRecip = SkScalarInvert(yRadius);
879 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
880 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
881
882 // We've extended the outer x radius out half a pixel to antialias. 1220 // We've extended the outer x radius out half a pixel to antialias.
883 // This will also expand the rect so all the pixels will be captured. 1221 // This will also expand the rect so all the pixels will be captured.
884 // TODO: Consider if we should use sqrt(2)/2 instead 1222 // TODO: Consider if we should use sqrt(2)/2 instead
885 xRadius += SK_ScalarHalf; 1223 xRadius += SK_ScalarHalf;
886 yRadius += SK_ScalarHalf; 1224 yRadius += SK_ScalarHalf;
887 1225
888 SkRect bounds = SkRect::MakeLTRB( 1226 SkRect bounds = SkRect::MakeLTRB(
889 center.fX - xRadius, 1227 center.fX - xRadius,
890 center.fY - yRadius, 1228 center.fY - yRadius,
891 center.fX + xRadius, 1229 center.fX + xRadius,
892 center.fY + yRadius 1230 center.fY + yRadius
893 ); 1231 );
894 1232
895 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 1233 EllipseBatch::Geometry geometry;
896 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius); 1234 geometry.fViewMatrix = viewMatrix;
897 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1235 geometry.fColor = color;
898 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1236 geometry.fXRadius = xRadius;
899 1237 geometry.fYRadius = yRadius;
900 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 1238 geometry.fInnerXRadius = innerXRadius;
901 verts[1].fOffset = SkPoint::Make(-xRadius, yRadius); 1239 geometry.fInnerYRadius = innerYRadius;
902 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); 1240 geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
903 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); 1241 geometry.fDevBounds = bounds;
904 1242
905 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 1243 SkAutoTUnref<GrBatch> batch(EllipseBatch::Create(geometry));
906 verts[2].fOffset = SkPoint::Make(xRadius, yRadius); 1244 target->drawBatch(pipelineBuilder, batch, &bounds);
907 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
908 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
909
910 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
911 verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
912 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
913 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
914
915 target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
916 target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType , 1, 4, 6, &bounds);
917 target->resetIndexSource();
918 1245
919 return true; 1246 return true;
920 } 1247 }
921 1248
1249 //////////////////////////////////////////////////////////////////////////////// /////////////////
1250
1251 class DIEllipseBatch : public GrBatch {
1252 public:
1253 struct Geometry {
1254 GrColor fColor;
1255 SkMatrix fViewMatrix;
1256 SkScalar fXRadius;
1257 SkScalar fYRadius;
1258 SkScalar fInnerXRadius;
1259 SkScalar fInnerYRadius;
1260 SkScalar fGeoDx;
1261 SkScalar fGeoDy;
1262 DIEllipseEdgeEffect::Mode fMode;
1263 SkRect fDevBounds;
1264 };
1265
1266 static GrBatch* Create(const Geometry& geometry) {
1267 return SkNEW_ARGS(DIEllipseBatch, (geometry));
1268 }
1269
1270 const char* name() const SK_OVERRIDE { return "DIEllipseBatch"; }
1271
1272 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1273 // When this is called on a batch, there is only one geometry bundle
1274 out->setKnownFourComponents(fGeoData[0].fColor);
1275 }
1276 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
1277 out->setUnknownSingleComponent();
1278 }
1279
1280 void initBatchOpt(const GrBatchOpt& batchOpt) {
1281 fBatchOpt = batchOpt;
1282 }
1283
1284 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1285 // Handle any color overrides
1286 if (init.fColorIgnored) {
1287 fGeoData[0].fColor = GrColor_ILLEGAL;
1288 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1289 fGeoData[0].fColor = init.fOverrideColor;
1290 }
1291
1292 // setup batch properties
1293 fBatch.fColorIgnored = init.fColorIgnored;
1294 fBatch.fColor = fGeoData[0].fColor;
1295 fBatch.fMode = fGeoData[0].fMode;
1296 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1297 fBatch.fCoverageIgnored = init.fCoverageIgnored;
1298 }
1299
1300 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
1301 // Setup geometry processor
1302 SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->c olor(),
1303 this->v iewMatrix(),
1304 this->m ode()));
1305
1306 SkASSERT(gp->getVertexStride() == sizeof(DIEllipseVertex));
1307
1308 batchTarget->initDraw(gp, pipeline);
1309
1310 // TODO this is hacky, but the only way we have to initialize the GP is to use the
1311 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
1312 // everywhere we can remove this nastiness
1313 GrPipelineInfo init;
1314 init.fColorIgnored = fBatch.fColorIgnored;
1315 init.fOverrideColor = GrColor_ILLEGAL;
1316 init.fCoverageIgnored = fBatch.fCoverageIgnored;
1317 init.fUsesLocalCoords = this->usesLocalCoords();
1318 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1319
1320 int instanceCount = fGeoData.count();
1321 int vertexCount = kVertsPerEllipse * instanceCount;
1322 size_t vertexStride = gp->getVertexStride();
1323 SkASSERT(vertexStride == sizeof(CircleVertex));
1324
1325 const GrVertexBuffer* vertexBuffer;
1326 int firstVertex;
1327
1328 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1329 vertexCount,
1330 &vertexBuffer,
1331 &firstVertex);
1332
1333 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(vertices);
1334
1335 for (int i = 0; i < instanceCount; i++) {
1336 Geometry& args = fGeoData[i];
1337
1338 SkScalar xRadius = args.fXRadius;
1339 SkScalar yRadius = args.fYRadius;
1340
1341 const SkRect& bounds = args.fDevBounds;
1342
1343 // This adjusts the "radius" to include the half-pixel border
1344 SkScalar offsetDx = SkScalarDiv(args.fGeoDx, xRadius);
1345 SkScalar offsetDy = SkScalarDiv(args.fGeoDy, yRadius);
1346
1347 SkScalar innerRatioX = SkScalarDiv(xRadius, args.fInnerXRadius);
1348 SkScalar innerRatioY = SkScalarDiv(yRadius, args.fInnerYRadius);
1349
1350 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1351 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offs etDy);
1352 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -inne rRatioY - offsetDy);
1353
1354 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
1355 verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offse tDy);
1356 verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, inner RatioY + offsetDy);
1357
1358 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1359 verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offset Dy);
1360 verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerR atioY + offsetDy);
1361
1362 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1363 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offse tDy);
1364 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -inner RatioY - offsetDy);
1365
1366 verts += kVertsPerEllipse;
1367 }
1368
1369 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
1370
1371 GrDrawTarget::DrawInfo drawInfo;
1372 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1373 drawInfo.setStartVertex(0);
1374 drawInfo.setStartIndex(0);
1375 drawInfo.setVerticesPerInstance(kVertsPerEllipse);
1376 drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
1377 drawInfo.adjustStartVertex(firstVertex);
1378 drawInfo.setVertexBuffer(vertexBuffer);
1379 drawInfo.setIndexBuffer(quadIndexBuffer);
1380
1381 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
1382
1383 while (instanceCount) {
1384 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw) );
1385 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
1386 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
1387
1388 batchTarget->draw(drawInfo);
1389
1390 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
1391 instanceCount -= drawInfo.instanceCount();
1392 }
1393 }
1394
1395 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1396
1397 private:
1398 DIEllipseBatch(const Geometry& geometry) {
1399 this->initClassID<DIEllipseBatch>();
1400 fGeoData.push_back(geometry);
1401 }
1402
1403 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1404 DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1405
1406 // TODO vertex color
1407 if (this->color() != that->color()) {
1408 return false;
1409 }
1410
1411 if (this->mode() != that->mode()) {
1412 return false;
1413 }
1414
1415 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1416 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
1417 return false;
1418 }
1419
1420 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
1421 return true;
1422 }
1423
1424 GrColor color() const { return fBatch.fColor; }
1425 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1426 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1427 DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
1428
1429 struct BatchTracker {
1430 GrColor fColor;
1431 DIEllipseEdgeEffect::Mode fMode;
1432 bool fUsesLocalCoords;
1433 bool fColorIgnored;
1434 bool fCoverageIgnored;
1435 };
1436
1437 static const int kVertsPerEllipse = 4;
1438 static const int kIndicesPerEllipse = 6;
1439
1440 GrBatchOpt fBatchOpt;
1441 BatchTracker fBatch;
1442 SkSTArray<1, Geometry, true> fGeoData;
1443 };
1444
922 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target, 1445 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
923 GrPipelineBuilder* pipelineBuilder, 1446 GrPipelineBuilder* pipelineBuilder,
924 GrColor color, 1447 GrColor color,
925 const SkMatrix& viewMatrix, 1448 const SkMatrix& viewMatrix,
926 bool useCoverageAA, 1449 bool useCoverageAA,
927 const SkRect& ellipse, 1450 const SkRect& ellipse,
928 const SkStrokeRec& stroke) { 1451 const SkStrokeRec& stroke) {
929 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); 1452 SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
930 SkScalar xRadius = SkScalarHalf(ellipse.width()); 1453 SkScalar xRadius = SkScalarHalf(ellipse.width());
931 SkScalar yRadius = SkScalarHalf(ellipse.height()); 1454 SkScalar yRadius = SkScalarHalf(ellipse.height());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
965 innerYRadius = yRadius - strokeWidth; 1488 innerYRadius = yRadius - strokeWidth;
966 } 1489 }
967 1490
968 xRadius += strokeWidth; 1491 xRadius += strokeWidth;
969 yRadius += strokeWidth; 1492 yRadius += strokeWidth;
970 } 1493 }
971 if (DIEllipseEdgeEffect::kStroke == mode) { 1494 if (DIEllipseEdgeEffect::kStroke == mode) {
972 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kSt roke : 1495 mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kSt roke :
973 DIEllipseEdgeEffect::kFi ll; 1496 DIEllipseEdgeEffect::kFi ll;
974 } 1497 }
975 SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
976 SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
977
978 SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(color, view Matrix, mode));
979
980 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
981 SkASSERT(gp->getVertexStride() == sizeof(DIEllipseVertex));
982 if (!geo.succeeded()) {
983 SkDebugf("Failed to get space for vertices!\n");
984 return false;
985 }
986
987 DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices());
988 1498
989 // This expands the outer rect so that after CTM we end up with a half-pixel border 1499 // This expands the outer rect so that after CTM we end up with a half-pixel border
990 SkScalar a = viewMatrix[SkMatrix::kMScaleX]; 1500 SkScalar a = viewMatrix[SkMatrix::kMScaleX];
991 SkScalar b = viewMatrix[SkMatrix::kMSkewX]; 1501 SkScalar b = viewMatrix[SkMatrix::kMSkewX];
992 SkScalar c = viewMatrix[SkMatrix::kMSkewY]; 1502 SkScalar c = viewMatrix[SkMatrix::kMSkewY];
993 SkScalar d = viewMatrix[SkMatrix::kMScaleY]; 1503 SkScalar d = viewMatrix[SkMatrix::kMScaleY];
994 SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c)); 1504 SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c));
995 SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d)); 1505 SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d));
996 // This adjusts the "radius" to include the half-pixel border
997 SkScalar offsetDx = SkScalarDiv(geoDx, xRadius);
998 SkScalar offsetDy = SkScalarDiv(geoDy, yRadius);
999 1506
1000 SkRect bounds = SkRect::MakeLTRB( 1507 SkRect bounds = SkRect::MakeLTRB(
1001 center.fX - xRadius - geoDx, 1508 center.fX - xRadius - geoDx,
1002 center.fY - yRadius - geoDy, 1509 center.fY - yRadius - geoDy,
1003 center.fX + xRadius + geoDx, 1510 center.fX + xRadius + geoDx,
1004 center.fY + yRadius + geoDy 1511 center.fY + yRadius + geoDy
1005 ); 1512 );
1006 1513
1007 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 1514 DIEllipseBatch::Geometry geometry;
1008 verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy); 1515 geometry.fViewMatrix = viewMatrix;
1009 verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy); 1516 geometry.fColor = color;
1517 geometry.fXRadius = xRadius;
1518 geometry.fYRadius = yRadius;
1519 geometry.fInnerXRadius = innerXRadius;
1520 geometry.fInnerYRadius = innerYRadius;
1521 geometry.fGeoDx = geoDx;
1522 geometry.fGeoDy = geoDy;
1523 geometry.fMode = mode;
1524 geometry.fDevBounds = bounds;
1010 1525
1011 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 1526 SkAutoTUnref<GrBatch> batch(DIEllipseBatch::Create(geometry));
1012 verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy); 1527 target->drawBatch(pipelineBuilder, batch, &bounds);
1013 verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
1014
1015 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1016 verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
1017 verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
1018
1019 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1020 verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
1021 verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
1022
1023 target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
1024 target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType , 1, 4, 6, &bounds);
1025 target->resetIndexSource();
1026 1528
1027 return true; 1529 return true;
1028 } 1530 }
1029 1531
1030 /////////////////////////////////////////////////////////////////////////////// 1532 ///////////////////////////////////////////////////////////////////////////////
1031 1533
1032 static const uint16_t gRRectIndices[] = { 1534 static const uint16_t gRRectIndices[] = {
1033 // corners 1535 // corners
1034 0, 1, 5, 0, 5, 4, 1536 0, 1, 5, 0, 5, 4,
1035 2, 3, 7, 2, 7, 6, 1537 2, 3, 7, 2, 7, 6,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1108 } 1610 }
1109 1611
1110 SkASSERT(!origOuter.isEmpty()); 1612 SkASSERT(!origOuter.isEmpty());
1111 SkTCopyOnFirstWrite<SkRRect> outer(origOuter); 1613 SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
1112 if (!viewMatrix.isIdentity()) { 1614 if (!viewMatrix.isIdentity()) {
1113 if (!origOuter.transform(viewMatrix, outer.writable())) { 1615 if (!origOuter.transform(viewMatrix, outer.writable())) {
1114 return false; 1616 return false;
1115 } 1617 }
1116 } 1618 }
1117 GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType : 1619 GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
1118 kFillBW_GrProcessorEdgeType; 1620 kFillBW_GrProcessorEdgeType;
1119 GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer); 1621 GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
1120 if (NULL == effect) { 1622 if (NULL == effect) {
1121 return false; 1623 return false;
1122 } 1624 }
1123 if (!are.isSet()) { 1625 if (!are.isSet()) {
1124 are.set(pipelineBuilder); 1626 are.set(pipelineBuilder);
1125 } 1627 }
1126 1628
1127 SkMatrix invert; 1629 SkMatrix invert;
1128 if (!viewMatrix.invert(&invert)) { 1630 if (!viewMatrix.invert(&invert)) {
1129 return false; 1631 return false;
1130 } 1632 }
1131 1633
1132 pipelineBuilder->addCoverageProcessor(effect)->unref(); 1634 pipelineBuilder->addCoverageProcessor(effect)->unref();
1133 SkRect bounds = outer->getBounds(); 1635 SkRect bounds = outer->getBounds();
1134 if (applyAA) { 1636 if (applyAA) {
1135 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1637 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1136 } 1638 }
1137 target->drawRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &inver t); 1639 target->drawRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &inver t);
1138 return true; 1640 return true;
1139 } 1641 }
1140 1642
1643 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1644
1645 class RRectCircleRendererBatch : public GrBatch {
bsalomon 2015/02/10 14:31:21 wondering if circular rrects can batch with circle
1646 public:
1647 struct Geometry {
1648 GrColor fColor;
1649 SkMatrix fViewMatrix;
1650 SkScalar fInnerRadius;
1651 SkScalar fOuterRadius;
1652 bool fStroke;
1653 SkRect fDevBounds;
1654 };
1655
1656 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexB uffer) {
1657 return SkNEW_ARGS(RRectCircleRendererBatch, (geometry, indexBuffer));
1658 }
1659
1660 const char* name() const SK_OVERRIDE { return "RRectCircleBatch"; }
1661
1662 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1663 // When this is called on a batch, there is only one geometry bundle
1664 out->setKnownFourComponents(fGeoData[0].fColor);
1665 }
1666 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
1667 out->setUnknownSingleComponent();
1668 }
1669
1670 void initBatchOpt(const GrBatchOpt& batchOpt) {
1671 fBatchOpt = batchOpt;
1672 }
1673
1674 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1675 // Handle any color overrides
1676 if (init.fColorIgnored) {
1677 fGeoData[0].fColor = GrColor_ILLEGAL;
1678 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1679 fGeoData[0].fColor = init.fOverrideColor;
1680 }
1681
1682 // setup batch properties
1683 fBatch.fColorIgnored = init.fColorIgnored;
1684 fBatch.fColor = fGeoData[0].fColor;
1685 fBatch.fStroke = fGeoData[0].fStroke;
1686 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1687 fBatch.fCoverageIgnored = init.fCoverageIgnored;
1688 }
1689
1690 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
1691 // reset to device coordinates
1692 SkMatrix invert;
1693 if (!this->viewMatrix().invert(&invert)) {
1694 SkDebugf("Failed to invert\n");
1695 return;
1696 }
1697
1698 // Setup geometry processor
1699 SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->colo r(),
1700 this->stro ke(),
1701 invert));
1702
1703 batchTarget->initDraw(gp, pipeline);
1704
1705 // TODO this is hacky, but the only way we have to initialize the GP is to use the
1706 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
1707 // everywhere we can remove this nastiness
1708 GrPipelineInfo init;
1709 init.fColorIgnored = fBatch.fColorIgnored;
1710 init.fOverrideColor = GrColor_ILLEGAL;
1711 init.fCoverageIgnored = fBatch.fCoverageIgnored;
1712 init.fUsesLocalCoords = this->usesLocalCoords();
1713 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1714
1715 int instanceCount = fGeoData.count();
1716 int vertexCount = kVertsPerRRect * instanceCount;
1717 size_t vertexStride = gp->getVertexStride();
1718 SkASSERT(vertexStride == sizeof(CircleVertex));
1719
1720 const GrVertexBuffer* vertexBuffer;
1721 int firstVertex;
1722
1723 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1724 vertexCount,
1725 &vertexBuffer,
1726 &firstVertex);
1727
1728 CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
1729
1730 for (int i = 0; i < instanceCount; i++) {
1731 Geometry& args = fGeoData[i];
1732
1733 SkScalar outerRadius = args.fOuterRadius;
1734
1735 const SkRect& bounds = args.fDevBounds;
1736
1737 SkScalar yCoords[4] = {
1738 bounds.fTop,
1739 bounds.fTop + outerRadius,
1740 bounds.fBottom - outerRadius,
1741 bounds.fBottom
1742 };
1743
1744 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1745 // The inner radius in the vertex data must be specified in normaliz ed space.
1746 SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
1747 for (int i = 0; i < 4; ++i) {
1748 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1749 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1750 verts->fOuterRadius = outerRadius;
1751 verts->fInnerRadius = innerRadius;
1752 verts++;
1753
1754 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[ i]);
1755 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1756 verts->fOuterRadius = outerRadius;
1757 verts->fInnerRadius = innerRadius;
1758 verts++;
1759
1760 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords [i]);
1761 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1762 verts->fOuterRadius = outerRadius;
1763 verts->fInnerRadius = innerRadius;
1764 verts++;
1765
1766 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1767 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1768 verts->fOuterRadius = outerRadius;
1769 verts->fInnerRadius = innerRadius;
1770 verts++;
1771 }
1772 }
1773
1774 // drop out the middle quad if we're stroked
1775 int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1776 SK_ARRAY_COUNT(gRRectIndices);
1777
1778
1779 GrDrawTarget::DrawInfo drawInfo;
1780 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1781 drawInfo.setStartVertex(0);
1782 drawInfo.setStartIndex(0);
1783 drawInfo.setVerticesPerInstance(kVertsPerRRect);
1784 drawInfo.setIndicesPerInstance(indexCnt);
1785 drawInfo.adjustStartVertex(firstVertex);
1786 drawInfo.setVertexBuffer(vertexBuffer);
1787 drawInfo.setIndexBuffer(fIndexBuffer);
1788
1789 int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
1790
1791 while (instanceCount) {
1792 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw) );
1793 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
1794 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
1795
1796 batchTarget->draw(drawInfo);
1797
1798 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
1799 instanceCount -= drawInfo.instanceCount();
1800 }
1801 }
1802
1803 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1804
1805 private:
1806 RRectCircleRendererBatch(const Geometry& geometry, const GrIndexBuffer* inde xBuffer)
1807 : fIndexBuffer(indexBuffer) {
1808 this->initClassID<RRectCircleRendererBatch>();
1809 fGeoData.push_back(geometry);
1810 }
1811
1812 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1813 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1814
1815 // TODO vertex color
1816 if (this->color() != that->color()) {
1817 return false;
1818 }
1819
1820 if (this->stroke() != that->stroke()) {
1821 return false;
1822 }
1823
1824 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1825 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
1826 return false;
1827 }
1828
1829 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
1830 return true;
1831 }
1832
1833 GrColor color() const { return fBatch.fColor; }
1834 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1835 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1836 bool stroke() const { return fBatch.fStroke; }
1837
1838 struct BatchTracker {
1839 GrColor fColor;
1840 bool fStroke;
1841 bool fUsesLocalCoords;
1842 bool fColorIgnored;
1843 bool fCoverageIgnored;
1844 };
1845
1846 GrBatchOpt fBatchOpt;
1847 BatchTracker fBatch;
1848 SkSTArray<1, Geometry, true> fGeoData;
1849 const GrIndexBuffer* fIndexBuffer;
1850 };
1851
1852 class RRectEllipseRendererBatch : public GrBatch {
1853 public:
1854 struct Geometry {
1855 GrColor fColor;
1856 SkMatrix fViewMatrix;
1857 SkScalar fXRadius;
1858 SkScalar fYRadius;
1859 SkScalar fInnerXRadius;
1860 SkScalar fInnerYRadius;
1861 bool fStroke;
1862 SkRect fDevBounds;
1863 };
1864
1865 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexB uffer) {
1866 return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry, indexBuffer));
1867 }
1868
1869 const char* name() const SK_OVERRIDE { return "RRectEllipseRendererBatch"; }
1870
1871 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1872 // When this is called on a batch, there is only one geometry bundle
1873 out->setKnownFourComponents(fGeoData[0].fColor);
1874 }
1875 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
1876 out->setUnknownSingleComponent();
1877 }
1878
1879 void initBatchOpt(const GrBatchOpt& batchOpt) {
1880 fBatchOpt = batchOpt;
1881 }
1882
1883 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1884 // Handle any color overrides
1885 if (init.fColorIgnored) {
1886 fGeoData[0].fColor = GrColor_ILLEGAL;
1887 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1888 fGeoData[0].fColor = init.fOverrideColor;
1889 }
1890
1891 // setup batch properties
1892 fBatch.fColorIgnored = init.fColorIgnored;
1893 fBatch.fColor = fGeoData[0].fColor;
1894 fBatch.fStroke = fGeoData[0].fStroke;
1895 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1896 fBatch.fCoverageIgnored = init.fCoverageIgnored;
1897 }
1898
1899 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
1900 // reset to device coordinates
1901 SkMatrix invert;
1902 if (!this->viewMatrix().invert(&invert)) {
1903 SkDebugf("Failed to invert\n");
1904 return;
1905 }
1906
1907 // Setup geometry processor
1908 SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->col or(),
1909 this->str oke(),
1910 invert));
1911
1912 batchTarget->initDraw(gp, pipeline);
1913
1914 // TODO this is hacky, but the only way we have to initialize the GP is to use the
1915 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
1916 // everywhere we can remove this nastiness
1917 GrPipelineInfo init;
1918 init.fColorIgnored = fBatch.fColorIgnored;
1919 init.fOverrideColor = GrColor_ILLEGAL;
1920 init.fCoverageIgnored = fBatch.fCoverageIgnored;
1921 init.fUsesLocalCoords = this->usesLocalCoords();
1922 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1923
1924 int instanceCount = fGeoData.count();
1925 int vertexCount = kVertsPerRRect * instanceCount;
1926 size_t vertexStride = gp->getVertexStride();
1927 SkASSERT(vertexStride == sizeof(EllipseVertex));
1928
1929 const GrVertexBuffer* vertexBuffer;
1930 int firstVertex;
1931
1932 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1933 vertexCount,
1934 &vertexBuffer,
1935 &firstVertex);
1936
1937 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
1938
1939 for (int i = 0; i < instanceCount; i++) {
1940 Geometry& args = fGeoData[i];
1941
1942 // Compute the reciprocals of the radii here to save time in the sha der
1943 SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
1944 SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
1945 SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1946 SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1947
1948 // Extend the radii out half a pixel to antialias.
1949 SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
1950 SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
1951
1952 const SkRect& bounds = args.fDevBounds;
1953
1954 SkScalar yCoords[4] = {
1955 bounds.fTop,
1956 bounds.fTop + yOuterRadius,
1957 bounds.fBottom - yOuterRadius,
1958 bounds.fBottom
1959 };
1960 SkScalar yOuterOffsets[4] = {
1961 yOuterRadius,
1962 SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
1963 SK_ScalarNearlyZero,
1964 yOuterRadius
1965 };
1966
1967 for (int i = 0; i < 4; ++i) {
1968 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1969 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1970 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1971 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadReci p);
1972 verts++;
1973
1974 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords [i]);
1975 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffset s[i]);
1976 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1977 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadReci p);
1978 verts++;
1979
1980 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoord s[i]);
1981 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffset s[i]);
1982 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1983 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadReci p);
1984 verts++;
1985
1986 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1987 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1988 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1989 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadReci p);
1990 verts++;
1991 }
1992 }
1993
1994 // drop out the middle quad if we're stroked
1995 int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1996 SK_ARRAY_COUNT(gRRectIndices);
1997
1998 GrDrawTarget::DrawInfo drawInfo;
1999 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
2000 drawInfo.setStartVertex(0);
2001 drawInfo.setStartIndex(0);
2002 drawInfo.setVerticesPerInstance(kVertsPerRRect);
2003 drawInfo.setIndicesPerInstance(indexCnt);
2004 drawInfo.adjustStartVertex(firstVertex);
2005 drawInfo.setVertexBuffer(vertexBuffer);
2006 drawInfo.setIndexBuffer(fIndexBuffer);
2007
2008 int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
2009
2010 while (instanceCount) {
2011 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw) );
2012 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
2013 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
2014
2015 batchTarget->draw(drawInfo);
2016
2017 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
2018 instanceCount -= drawInfo.instanceCount();
2019 }
2020 }
2021
2022 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
2023
2024 private:
2025 RRectEllipseRendererBatch(const Geometry& geometry, const GrIndexBuffer* ind exBuffer)
2026 : fIndexBuffer(indexBuffer) {
2027 this->initClassID<RRectEllipseRendererBatch>();
2028 fGeoData.push_back(geometry);
2029 }
2030
2031 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
2032 RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
2033
2034 // TODO vertex color
2035 if (this->color() != that->color()) {
2036 return false;
2037 }
2038
2039 if (this->stroke() != that->stroke()) {
2040 return false;
2041 }
2042
2043 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
2044 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
2045 return false;
2046 }
2047
2048 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
2049 return true;
2050 }
2051
2052 GrColor color() const { return fBatch.fColor; }
2053 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
2054 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
2055 bool stroke() const { return fBatch.fStroke; }
2056
2057 struct BatchTracker {
2058 GrColor fColor;
2059 bool fStroke;
2060 bool fUsesLocalCoords;
2061 bool fColorIgnored;
2062 bool fCoverageIgnored;
2063 };
2064
2065 GrBatchOpt fBatchOpt;
2066 BatchTracker fBatch;
2067 SkSTArray<1, Geometry, true> fGeoData;
2068 const GrIndexBuffer* fIndexBuffer;
2069 };
2070
1141 bool GrOvalRenderer::drawRRect(GrDrawTarget* target, 2071 bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
1142 GrPipelineBuilder* pipelineBuilder, 2072 GrPipelineBuilder* pipelineBuilder,
1143 GrColor color, 2073 GrColor color,
1144 const SkMatrix& viewMatrix, 2074 const SkMatrix& viewMatrix,
1145 bool useAA, 2075 bool useAA,
1146 const SkRRect& rrect, 2076 const SkRRect& rrect,
1147 const SkStrokeRec& stroke) { 2077 const SkStrokeRec& stroke) {
1148 if (rrect.isOval()) { 2078 if (rrect.isOval()) {
1149 return this->drawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(), 2079 return this->drawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
1150 stroke); 2080 stroke);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 2132
1203 // The way the effect interpolates the offset-to-ellipse/circle-center attri bute only works on 2133 // The way the effect interpolates the offset-to-ellipse/circle-center attri bute only works on
1204 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine- 2134 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine-
1205 // patch will have fractional coverage. This only matters when the interior is actually filled. 2135 // patch will have fractional coverage. This only matters when the interior is actually filled.
1206 // We could consider falling back to rect rendering here, since a tiny radiu s is 2136 // We could consider falling back to rect rendering here, since a tiny radiu s is
1207 // indistinguishable from a square corner. 2137 // indistinguishable from a square corner.
1208 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { 2138 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
1209 return false; 2139 return false;
1210 } 2140 }
1211 2141
1212 // reset to device coordinates
1213 SkMatrix invert;
1214 if (!viewMatrix.invert(&invert)) {
1215 SkDebugf("Failed to invert\n");
1216 return false;
1217 }
1218
1219 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(isStrokeOnly); 2142 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(isStrokeOnly);
1220 if (NULL == indexBuffer) { 2143 if (NULL == indexBuffer) {
1221 SkDebugf("Failed to create index buffer!\n"); 2144 SkDebugf("Failed to create index buffer!\n");
1222 return false; 2145 return false;
1223 } 2146 }
1224 2147
1225 // if the corners are circles, use the circle renderer 2148 // if the corners are circles, use the circle renderer
1226 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { 2149 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) {
1227 SkScalar innerRadius = 0.0f; 2150 SkScalar innerRadius = 0.0f;
1228 SkScalar outerRadius = xRadius; 2151 SkScalar outerRadius = xRadius;
1229 SkScalar halfWidth = 0; 2152 SkScalar halfWidth = 0;
1230 if (hasStroke) { 2153 if (hasStroke) {
1231 if (SkScalarNearlyZero(scaledStroke.fX)) { 2154 if (SkScalarNearlyZero(scaledStroke.fX)) {
1232 halfWidth = SK_ScalarHalf; 2155 halfWidth = SK_ScalarHalf;
1233 } else { 2156 } else {
1234 halfWidth = SkScalarHalf(scaledStroke.fX); 2157 halfWidth = SkScalarHalf(scaledStroke.fX);
1235 } 2158 }
1236 2159
1237 if (isStrokeOnly) { 2160 if (isStrokeOnly) {
1238 innerRadius = xRadius - halfWidth; 2161 innerRadius = xRadius - halfWidth;
1239 } 2162 }
1240 outerRadius += halfWidth; 2163 outerRadius += halfWidth;
1241 bounds.outset(halfWidth, halfWidth); 2164 bounds.outset(halfWidth, halfWidth);
1242 } 2165 }
1243 2166
1244 isStrokeOnly = (isStrokeOnly && innerRadius >= 0); 2167 isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
1245 2168
1246 SkAutoTUnref<GrGeometryProcessor> effect(CircleEdgeEffect::Create(color,
1247 isStro keOnly,
1248 invert ));
1249
1250 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid e(), 0);
1251 SkASSERT(effect->getVertexStride() == sizeof(CircleVertex));
1252 if (!geo.succeeded()) {
1253 SkDebugf("Failed to get space for vertices!\n");
1254 return false;
1255 }
1256 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1257
1258 // The radii are outset for two reasons. First, it allows the shader to simply perform 2169 // The radii are outset for two reasons. First, it allows the shader to simply perform
1259 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius. 2170 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1260 // Second, the outer radius is used to compute the verts of the bounding box that is 2171 // Second, the outer radius is used to compute the verts of the bounding box that is
1261 // rendered and the outset ensures the box will cover all partially cove red by the rrect 2172 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1262 // corners. 2173 // corners.
1263 outerRadius += SK_ScalarHalf; 2174 outerRadius += SK_ScalarHalf;
1264 innerRadius -= SK_ScalarHalf; 2175 innerRadius -= SK_ScalarHalf;
1265 2176
1266 // Expand the rect so all the pixels will be captured. 2177 // Expand the rect so all the pixels will be captured.
1267 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 2178 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1268 2179
1269 SkScalar yCoords[4] = { 2180 RRectCircleRendererBatch::Geometry geometry;
1270 bounds.fTop, 2181 geometry.fViewMatrix = viewMatrix;
1271 bounds.fTop + outerRadius, 2182 geometry.fColor = color;
1272 bounds.fBottom - outerRadius, 2183 geometry.fInnerRadius = innerRadius;
1273 bounds.fBottom 2184 geometry.fOuterRadius = outerRadius;
1274 }; 2185 geometry.fStroke = isStrokeOnly;
1275 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 }; 2186 geometry.fDevBounds = bounds;
1276 // The inner radius in the vertex data must be specified in normalized s pace.
1277 innerRadius = innerRadius / outerRadius;
1278 for (int i = 0; i < 4; ++i) {
1279 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1280 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1281 verts->fOuterRadius = outerRadius;
1282 verts->fInnerRadius = innerRadius;
1283 verts++;
1284 2187
1285 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); 2188 SkAutoTUnref<GrBatch> batch(RRectCircleRendererBatch::Create(geometry, i ndexBuffer));
1286 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); 2189 target->drawBatch(pipelineBuilder, batch, &bounds);
1287 verts->fOuterRadius = outerRadius;
1288 verts->fInnerRadius = innerRadius;
1289 verts++;
1290
1291 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]) ;
1292 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1293 verts->fOuterRadius = outerRadius;
1294 verts->fInnerRadius = innerRadius;
1295 verts++;
1296
1297 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1298 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1299 verts->fOuterRadius = outerRadius;
1300 verts->fInnerRadius = innerRadius;
1301 verts++;
1302 }
1303
1304 // drop out the middle quad if we're stroked
1305 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1306 SK_ARRAY_COUNT(gRRectIndices);
1307 target->setIndexSourceToBuffer(indexBuffer);
1308 target->drawIndexedInstances(pipelineBuilder, effect, kTriangles_GrPrimi tiveType, 1, 16,
1309 indexCnt, &bounds);
1310 2190
1311 // otherwise we use the ellipse renderer 2191 // otherwise we use the ellipse renderer
1312 } else { 2192 } else {
1313 SkScalar innerXRadius = 0.0f; 2193 SkScalar innerXRadius = 0.0f;
1314 SkScalar innerYRadius = 0.0f; 2194 SkScalar innerYRadius = 0.0f;
1315 if (hasStroke) { 2195 if (hasStroke) {
1316 if (SkScalarNearlyZero(scaledStroke.length())) { 2196 if (SkScalarNearlyZero(scaledStroke.length())) {
1317 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); 2197 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1318 } else { 2198 } else {
1319 scaledStroke.scale(SK_ScalarHalf); 2199 scaledStroke.scale(SK_ScalarHalf);
(...skipping 17 matching lines...) Expand all
1337 innerYRadius = yRadius - scaledStroke.fY; 2217 innerYRadius = yRadius - scaledStroke.fY;
1338 } 2218 }
1339 2219
1340 xRadius += scaledStroke.fX; 2220 xRadius += scaledStroke.fX;
1341 yRadius += scaledStroke.fY; 2221 yRadius += scaledStroke.fY;
1342 bounds.outset(scaledStroke.fX, scaledStroke.fY); 2222 bounds.outset(scaledStroke.fX, scaledStroke.fY);
1343 } 2223 }
1344 2224
1345 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0); 2225 isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
1346 2226
1347 SkAutoTUnref<GrGeometryProcessor> effect(EllipseEdgeEffect::Create(color ,
1348 isStr okeOnly,
1349 inver t));
1350
1351 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid e(), 0);
1352 SkASSERT(effect->getVertexStride() == sizeof(EllipseVertex));
1353 if (!geo.succeeded()) {
1354 SkDebugf("Failed to get space for vertices!\n");
1355 return false;
1356 }
1357
1358 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
1359
1360 // Compute the reciprocals of the radii here to save time in the shader
1361 SkScalar xRadRecip = SkScalarInvert(xRadius);
1362 SkScalar yRadRecip = SkScalarInvert(yRadius);
1363 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
1364 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
1365
1366 // Extend the radii out half a pixel to antialias.
1367 SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
1368 SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
1369
1370 // Expand the rect so all the pixels will be captured. 2227 // Expand the rect so all the pixels will be captured.
1371 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 2228 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1372 2229
1373 SkScalar yCoords[4] = { 2230 RRectEllipseRendererBatch::Geometry geometry;
1374 bounds.fTop, 2231 geometry.fViewMatrix = viewMatrix;
1375 bounds.fTop + yOuterRadius, 2232 geometry.fColor = color;
1376 bounds.fBottom - yOuterRadius, 2233 geometry.fXRadius = xRadius;
1377 bounds.fBottom 2234 geometry.fYRadius = yRadius;
1378 }; 2235 geometry.fInnerXRadius = innerXRadius;
1379 SkScalar yOuterOffsets[4] = { 2236 geometry.fInnerYRadius = innerYRadius;
1380 yOuterRadius, 2237 geometry.fStroke = isStrokeOnly;
1381 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 2238 geometry.fDevBounds = bounds;
1382 SK_ScalarNearlyZero,
1383 yOuterRadius
1384 };
1385 2239
1386 for (int i = 0; i < 4; ++i) { 2240 SkAutoTUnref<GrBatch> batch(RRectEllipseRendererBatch::Create(geometry, indexBuffer));
1387 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); 2241 target->drawBatch(pipelineBuilder, batch, &bounds);
1388 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1389 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1390 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1391 verts++;
1392
1393 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ;
1394 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
1395 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1396 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1397 verts++;
1398
1399 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] );
1400 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
1401 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1402 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1403 verts++;
1404
1405 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1406 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1407 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1408 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1409 verts++;
1410 }
1411
1412 // drop out the middle quad if we're stroked
1413 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1414 SK_ARRAY_COUNT(gRRectIndices);
1415 target->setIndexSourceToBuffer(indexBuffer);
1416 target->drawIndexedInstances(pipelineBuilder, effect, kTriangles_GrPrimi tiveType, 1, 16,
1417 indexCnt, &bounds);
1418 } 2242 }
1419
1420 target->resetIndexSource();
1421 return true; 2243 return true;
1422 } 2244 }
OLDNEW
« no previous file with comments | « src/gpu/GrBatchTarget.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698