OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 "GrPLSPathRenderer.h" | 8 #include "GrPLSPathRenderer.h" |
9 | 9 |
10 #include "SkChunkAlloc.h" | 10 #include "SkChunkAlloc.h" |
(...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 SkPath path; | 780 SkPath path; |
781 args.fShape->asPath(&path); | 781 args.fShape->asPath(&path); |
782 return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && | 782 return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && |
783 args.fShape->style().isSimpleFill() && !path.isInverseFillType() && | 783 args.fShape->style().isSimpleFill() && !path.isInverseFillType() && |
784 path.getFillType() == SkPath::FillType::kWinding_FillType; | 784 path.getFillType() == SkPath::FillType::kWinding_FillType; |
785 } | 785 } |
786 | 786 |
787 class PLSPathBatch : public GrVertexBatch { | 787 class PLSPathBatch : public GrVertexBatch { |
788 public: | 788 public: |
789 DEFINE_BATCH_CLASS_ID | 789 DEFINE_BATCH_CLASS_ID |
790 struct Geometry { | 790 PLSPathBatch(GrColor color, const SkPath& path, const SkMatrix& viewMatrix) |
791 GrColor fColor; | 791 : INHERITED(ClassID()) |
792 SkMatrix fViewMatrix; | 792 , fColor(color) |
793 SkPath fPath; | 793 , fPath(path) |
794 }; | 794 , fViewMatrix(viewMatrix) { |
795 | 795 // compute bounds |
796 static GrDrawBatch* Create(const Geometry& geometry) { | 796 fBounds = path.getBounds(); |
797 return new PLSPathBatch(geometry); | 797 fViewMatrix.mapRect(&fBounds); |
798 } | 798 } |
799 | 799 |
800 const char* name() const override { return "PLSBatch"; } | 800 const char* name() const override { return "PLSBatch"; } |
801 | 801 |
802 void computePipelineOptimizations(GrInitInvariantOutput* color, | 802 void computePipelineOptimizations(GrInitInvariantOutput* color, |
803 GrInitInvariantOutput* coverage, | 803 GrInitInvariantOutput* coverage, |
804 GrBatchToXPOverrides* overrides) const ove
rride { | 804 GrBatchToXPOverrides* overrides) const ove
rride { |
805 // When this is called on a batch, there is only one geometry bundle | 805 // When this is called on a batch, there is only one geometry bundle |
806 color->setKnownFourComponents(fGeoData[0].fColor); | 806 color->setKnownFourComponents(fColor); |
807 coverage->setUnknownSingleComponent(); | 807 coverage->setUnknownSingleComponent(); |
808 overrides->fUsePLSDstRead = true; | 808 overrides->fUsePLSDstRead = true; |
809 } | 809 } |
810 | 810 |
811 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 811 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
812 // Handle any color overrides | 812 // Handle any color overrides |
813 if (!overrides.readsColor()) { | 813 if (!overrides.readsColor()) { |
814 fGeoData[0].fColor = GrColor_ILLEGAL; | 814 fColor = GrColor_ILLEGAL; |
815 } | 815 } |
816 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | 816 overrides.getOverrideColorIfSet(&fColor); |
817 | 817 |
818 // setup batch properties | 818 // setup batch properties |
819 fBatch.fColorIgnored = !overrides.readsColor(); | 819 fUsesLocalCoords = overrides.readsLocalCoords(); |
820 fBatch.fColor = fGeoData[0].fColor; | |
821 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); | |
822 fBatch.fCoverageIgnored = !overrides.readsCoverage(); | |
823 fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); | |
824 } | 820 } |
825 | 821 |
826 void onPrepareDraws(Target* target) const override { | 822 void onPrepareDraws(Target* target) const override { |
827 int instanceCount = fGeoData.count(); | |
828 | 823 |
829 SkMatrix invert; | 824 SkMatrix invert; |
830 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { | 825 if (fUsesLocalCoords && !fViewMatrix.invert(&invert)) { |
831 SkDebugf("Could not invert viewmatrix\n"); | 826 SkDebugf("Could not invert viewmatrix\n"); |
832 return; | 827 return; |
833 } | 828 } |
834 | 829 |
835 // Setup GrGeometryProcessors | 830 // Setup GrGeometryProcessors |
836 SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor( | 831 SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor( |
837 PLSAATriangleEffect::Create(invert, this->usesLocalCoords())); | 832 PLSAATriangleEffect::Create(invert, fUsesLocalCoords)); |
838 SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor( | 833 SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor( |
839 PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords())); | 834 PLSQuadEdgeEffect::Create(invert, fUsesLocalCoords)); |
840 | 835 |
841 GrResourceProvider* rp = target->resourceProvider(); | 836 GrResourceProvider* rp = target->resourceProvider(); |
842 for (int i = 0; i < instanceCount; ++i) { | 837 SkRect bounds; |
843 const Geometry& args = fGeoData[i]; | 838 this->bounds().roundOut(&bounds); |
844 SkRect bounds = args.fPath.getBounds(); | 839 triangleProcessor->setBounds(bounds); |
845 args.fViewMatrix.mapRect(&bounds); | 840 quadProcessor->setBounds(bounds); |
846 bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft); | |
847 bounds.fTop = SkScalarFloorToScalar(bounds.fTop); | |
848 bounds.fRight = SkScalarCeilToScalar(bounds.fRight); | |
849 bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom); | |
850 triangleProcessor->setBounds(bounds); | |
851 quadProcessor->setBounds(bounds); | |
852 | 841 |
853 // We use the fact that SkPath::transform path does subdivision base
d on | 842 // We use the fact that SkPath::transform path does subdivision based on |
854 // perspective. Otherwise, we apply the view matrix when copying to
the | 843 // perspective. Otherwise, we apply the view matrix when copying to the |
855 // segment representation. | 844 // segment representation. |
856 const SkMatrix* viewMatrix = &args.fViewMatrix; | 845 const SkMatrix* viewMatrix = &fViewMatrix; |
857 | 846 |
858 // We avoid initializing the path unless we have to | 847 // We avoid initializing the path unless we have to |
859 const SkPath* pathPtr = &args.fPath; | 848 const SkPath* pathPtr = &fPath; |
860 SkTLazy<SkPath> tmpPath; | 849 SkTLazy<SkPath> tmpPath; |
861 if (viewMatrix->hasPerspective()) { | 850 if (viewMatrix->hasPerspective()) { |
862 SkPath* tmpPathPtr = tmpPath.init(*pathPtr); | 851 SkPath* tmpPathPtr = tmpPath.init(*pathPtr); |
863 tmpPathPtr->setIsVolatile(true); | 852 tmpPathPtr->setIsVolatile(true); |
864 tmpPathPtr->transform(*viewMatrix); | 853 tmpPathPtr->transform(*viewMatrix); |
865 viewMatrix = &SkMatrix::I(); | 854 viewMatrix = &SkMatrix::I(); |
866 pathPtr = tmpPathPtr; | 855 pathPtr = tmpPathPtr; |
867 } | 856 } |
868 | 857 |
869 GrMesh mesh; | 858 GrMesh mesh; |
870 | 859 |
871 PLSVertices triVertices; | 860 PLSVertices triVertices; |
872 PLSVertices quadVertices; | 861 PLSVertices quadVertices; |
873 if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices,
rp, bounds)) { | 862 if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp,
bounds)) { |
874 continue; | 863 return; |
875 } | 864 } |
876 | 865 |
877 if (triVertices.count()) { | 866 if (triVertices.count()) { |
878 const GrBuffer* triVertexBuffer; | 867 const GrBuffer* triVertexBuffer; |
879 int firstTriVertex; | 868 int firstTriVertex; |
880 size_t triStride = triangleProcessor->getVertexStride(); | 869 size_t triStride = triangleProcessor->getVertexStride(); |
881 PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeV
ertexSpace( | 870 PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVerte
xSpace( |
882 triStride, triVertices.count(), &triVertexBuffer, &first
TriVertex)); | 871 triStride, triVertices.count(), &triVertexBuffer, &firstTriV
ertex)); |
883 if (!triVerts) { | 872 if (!triVerts) { |
884 SkDebugf("Could not allocate vertices\n"); | |
885 return; | |
886 } | |
887 for (int i = 0; i < triVertices.count(); ++i) { | |
888 triVerts[i] = triVertices[i]; | |
889 } | |
890 mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriV
ertex, | |
891 triVertices.count()); | |
892 target->draw(triangleProcessor, mesh); | |
893 } | |
894 | |
895 if (quadVertices.count()) { | |
896 const GrBuffer* quadVertexBuffer; | |
897 int firstQuadVertex; | |
898 size_t quadStride = quadProcessor->getVertexStride(); | |
899 PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->make
VertexSpace( | |
900 quadStride, quadVertices.count(), &quadVertexBuffer, &fi
rstQuadVertex)); | |
901 if (!quadVerts) { | |
902 SkDebugf("Could not allocate vertices\n"); | |
903 return; | |
904 } | |
905 for (int i = 0; i < quadVertices.count(); ++i) { | |
906 quadVerts[i] = quadVertices[i]; | |
907 } | |
908 mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQua
dVertex, | |
909 quadVertices.count()); | |
910 target->draw(quadProcessor, mesh); | |
911 } | |
912 | |
913 SkAutoTUnref<GrGeometryProcessor> finishProcessor( | |
914 PLSFinishEffect::Create(this->color(), | |
915 pathPtr->getFillType() == | |
916 SkPath::FillType
::kEvenOdd_FillType, | |
917 invert, | |
918 this->usesLocalCoords())); | |
919 const GrBuffer* rectVertexBuffer; | |
920 size_t finishStride = finishProcessor->getVertexStride(); | |
921 int firstRectVertex; | |
922 static const int kRectVertexCount = 6; | |
923 SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSp
ace( | |
924 finishStride, kRectVertexCount, &rectVertexBuffer, &firstRec
tVertex)); | |
925 if (!rectVerts) { | |
926 SkDebugf("Could not allocate vertices\n"); | 873 SkDebugf("Could not allocate vertices\n"); |
927 return; | 874 return; |
928 } | 875 } |
929 rectVerts[0] = { bounds.fLeft, bounds.fTop }; | 876 for (int i = 0; i < triVertices.count(); ++i) { |
930 rectVerts[1] = { bounds.fLeft, bounds.fBottom }; | 877 triVerts[i] = triVertices[i]; |
931 rectVerts[2] = { bounds.fRight, bounds.fBottom }; | 878 } |
932 rectVerts[3] = { bounds.fLeft, bounds.fTop }; | 879 mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVerte
x, |
933 rectVerts[4] = { bounds.fRight, bounds.fTop }; | 880 triVertices.count()); |
934 rectVerts[5] = { bounds.fRight, bounds.fBottom }; | 881 target->draw(triangleProcessor, mesh); |
| 882 } |
935 | 883 |
936 mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVer
tex, | 884 if (quadVertices.count()) { |
937 kRectVertexCount); | 885 const GrBuffer* quadVertexBuffer; |
938 target->draw(finishProcessor, mesh); | 886 int firstQuadVertex; |
| 887 size_t quadStride = quadProcessor->getVertexStride(); |
| 888 PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVert
exSpace( |
| 889 quadStride, quadVertices.count(), &quadVertexBuffer, &firstQ
uadVertex)); |
| 890 if (!quadVerts) { |
| 891 SkDebugf("Could not allocate vertices\n"); |
| 892 return; |
| 893 } |
| 894 for (int i = 0; i < quadVertices.count(); ++i) { |
| 895 quadVerts[i] = quadVertices[i]; |
| 896 } |
| 897 mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVer
tex, |
| 898 quadVertices.count()); |
| 899 target->draw(quadProcessor, mesh); |
939 } | 900 } |
| 901 |
| 902 SkAutoTUnref<GrGeometryProcessor> finishProcessor( |
| 903 PLSFinishEffect::Create(fColor, |
| 904 pathPtr->getFillType() == |
| 905 SkPath::FillType::kE
venOdd_FillType, |
| 906 invert, |
| 907 fUsesLocalCoords)); |
| 908 const GrBuffer* rectVertexBuffer; |
| 909 size_t finishStride = finishProcessor->getVertexStride(); |
| 910 int firstRectVertex; |
| 911 static const int kRectVertexCount = 6; |
| 912 SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace( |
| 913 finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVer
tex)); |
| 914 if (!rectVerts) { |
| 915 SkDebugf("Could not allocate vertices\n"); |
| 916 return; |
| 917 } |
| 918 rectVerts[0] = { bounds.fLeft, bounds.fTop }; |
| 919 rectVerts[1] = { bounds.fLeft, bounds.fBottom }; |
| 920 rectVerts[2] = { bounds.fRight, bounds.fBottom }; |
| 921 rectVerts[3] = { bounds.fLeft, bounds.fTop }; |
| 922 rectVerts[4] = { bounds.fRight, bounds.fTop }; |
| 923 rectVerts[5] = { bounds.fRight, bounds.fBottom }; |
| 924 |
| 925 mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, |
| 926 kRectVertexCount); |
| 927 target->draw(finishProcessor, mesh); |
940 } | 928 } |
941 | 929 |
942 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
943 | |
944 private: | 930 private: |
945 PLSPathBatch(const Geometry& geometry) : INHERITED(ClassID()) { | |
946 fGeoData.push_back(geometry); | |
947 | |
948 // compute bounds | |
949 fBounds = geometry.fPath.getBounds(); | |
950 geometry.fViewMatrix.mapRect(&fBounds); | |
951 } | |
952 | |
953 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | 931 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
954 return false; | 932 return false; |
955 } | 933 } |
956 | 934 |
957 GrColor color() const { return fBatch.fColor; } | 935 bool fUsesLocalCoords; |
958 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
959 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } | |
960 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
961 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
962 | 936 |
963 struct BatchTracker { | 937 GrColor fColor; |
964 GrColor fColor; | 938 SkPath fPath; |
965 bool fUsesLocalCoords; | 939 SkMatrix fViewMatrix; |
966 bool fColorIgnored; | |
967 bool fCoverageIgnored; | |
968 bool fCanTweakAlphaForCoverage; | |
969 }; | |
970 | |
971 BatchTracker fBatch; | |
972 SkSTArray<1, Geometry, true> fGeoData; | |
973 | |
974 typedef GrVertexBatch INHERITED; | 940 typedef GrVertexBatch INHERITED; |
975 }; | 941 }; |
976 | 942 |
977 SkDEBUGCODE(bool inPLSDraw = false;) | 943 SkDEBUGCODE(bool inPLSDraw = false;) |
978 bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { | 944 bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { |
979 SkASSERT(!args.fShape->isEmpty()) | 945 SkASSERT(!args.fShape->isEmpty()) |
980 SkASSERT(!inPLSDraw); | 946 SkASSERT(!inPLSDraw); |
981 SkDEBUGCODE(inPLSDraw = true;) | 947 SkDEBUGCODE(inPLSDraw = true;) |
982 PLSPathBatch::Geometry geometry; | 948 SkPath path; |
983 geometry.fColor = args.fColor; | 949 args.fShape->asPath(&path); |
984 geometry.fViewMatrix = *args.fViewMatrix; | |
985 args.fShape->asPath(&geometry.fPath); | |
986 | 950 |
987 SkAutoTUnref<GrDrawBatch> batch(PLSPathBatch::Create(geometry)); | 951 SkAutoTUnref<GrDrawBatch> batch(new PLSPathBatch(args.fColor, path, *args.fV
iewMatrix)); |
988 | 952 |
989 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); | 953 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); |
990 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 954 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
991 | 955 |
992 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 956 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
993 | 957 |
994 SkDEBUGCODE(inPLSDraw = false;) | 958 SkDEBUGCODE(inPLSDraw = false;) |
995 return true; | 959 return true; |
996 | 960 |
997 } | 961 } |
998 | 962 |
999 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 963 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
1000 | 964 |
1001 #ifdef GR_TEST_UTILS | 965 #ifdef GR_TEST_UTILS |
1002 | 966 |
1003 DRAW_BATCH_TEST_DEFINE(PLSPathBatch) { | 967 DRAW_BATCH_TEST_DEFINE(PLSPathBatch) { |
1004 PLSPathBatch::Geometry geometry; | 968 GrColor color = GrRandomColor(random); |
1005 geometry.fColor = GrRandomColor(random); | 969 SkMatrix vm = GrTest::TestMatrixInvertible(random); |
1006 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); | 970 SkPath path = GrTest::TestPathConvex(random); |
1007 geometry.fPath = GrTest::TestPathConvex(random); | |
1008 | 971 |
1009 return PLSPathBatch::Create(geometry); | 972 return new PLSPathBatch(color, path, vm); |
1010 } | 973 } |
1011 | 974 |
1012 #endif | 975 #endif |
OLD | NEW |