Chromium Code Reviews| 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 |