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

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

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