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