OLD | NEW |
---|---|
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 Loading... | |
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(¢er, 1); | 898 viewMatrix.mapPoints(¢er, 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |