• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/core/SkPathPriv.h"
9 #include "src/gpu/effects/GrConvexPolyEffect.h"
10 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
12 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
13 #include "src/sksl/dsl/priv/DSLFPs.h"
14 
15 //////////////////////////////////////////////////////////////////////////////
16 
Make(std::unique_ptr<GrFragmentProcessor> inputFP,GrClipEdgeType type,const SkPath & path)17 GrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP,
18                                     GrClipEdgeType type, const SkPath& path) {
19     if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || !path.isConvex()) {
20         return GrFPFailure(std::move(inputFP));
21     }
22 
23     SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(path);
24     // The only way this should fail is if the clip is effectively a infinitely thin line. In that
25     // case nothing is inside the clip. It'd be nice to detect this at a higher level and either
26     // skip the draw or omit the clip element.
27     if (dir == SkPathFirstDirection::kUnknown) {
28         if (GrClipEdgeTypeIsInverseFill(type)) {
29             return GrFPSuccess(
30                     GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fWHITE));
31         }
32         // This could use ConstColor instead of ModulateRGBA but it would trigger a debug print
33         // about a coverage processor not being compatible with the alpha-as-coverage optimization.
34         // We don't really care about this unlikely case so we just use ModulateRGBA to suppress
35         // the print.
36         return GrFPSuccess(
37                 GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fTRANSPARENT));
38     }
39 
40     SkScalar        edges[3 * kMaxEdges];
41     SkPoint         pts[4];
42     SkPath::Verb    verb;
43     SkPath::Iter    iter(path, true);
44 
45     // SkPath considers itself convex so long as there is a convex contour within it,
46     // regardless of any degenerate contours such as a string of moveTos before it.
47     // Iterate here to consume any degenerate contours and only process the points
48     // on the actual convex contour.
49     int n = 0;
50     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
51         switch (verb) {
52             case SkPath::kMove_Verb:
53             case SkPath::kClose_Verb:
54                 break;
55             case SkPath::kLine_Verb: {
56                 if (n >= kMaxEdges) {
57                     return GrFPFailure(std::move(inputFP));
58                 }
59                 if (pts[0] != pts[1]) {
60                     SkVector v = pts[1] - pts[0];
61                     v.normalize();
62                     if (SkPathFirstDirection::kCCW == dir) {
63                         edges[3 * n] = v.fY;
64                         edges[3 * n + 1] = -v.fX;
65                     } else {
66                         edges[3 * n] = -v.fY;
67                         edges[3 * n + 1] = v.fX;
68                     }
69                     edges[3 * n + 2] = -(edges[3 * n] * pts[1].fX + edges[3 * n + 1] * pts[1].fY);
70                     ++n;
71                 }
72                 break;
73             }
74             default:
75                 // Non-linear segment so not a polygon.
76                 return GrFPFailure(std::move(inputFP));
77         }
78     }
79 
80     if (path.isInverseFillType()) {
81         type = GrInvertClipEdgeType(type);
82     }
83     return GrConvexPolyEffect::Make(std::move(inputFP), type, n, edges);
84 }
85 
~GrConvexPolyEffect()86 GrConvexPolyEffect::~GrConvexPolyEffect() {}
87 
onAddToKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const88 void GrConvexPolyEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
89     static_assert(kGrClipEdgeTypeCnt <= 8);
90     uint32_t key = (fEdgeCount << 3) | static_cast<int>(fEdgeType);
91     b->add32(key);
92 }
93 
onMakeProgramImpl() const94 std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrConvexPolyEffect::onMakeProgramImpl() const {
95     class Impl : public ProgramImpl {
96     public:
97         void emitCode(EmitArgs& args) override {
98             const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>();
99 
100             using namespace SkSL::dsl;
101             StartFragmentProcessor(this, &args);
102             GlobalVar edgeArray(kUniform_Modifier, Array(kHalf3_Type, cpe.fEdgeCount), "edgeArray");
103             Declare(edgeArray);
104             fEdgeUniform = VarUniformHandle(edgeArray);
105             Var alpha(kHalf_Type, "alpha", 1);
106             Declare(alpha);
107             Var edge(kHalf_Type, "edge");
108             Declare(edge);
109             for (int i = 0; i < cpe.fEdgeCount; ++i) {
110                 edge = Dot(edgeArray[i], Half3(Swizzle(sk_FragCoord(), X, Y, ONE)));
111                 if (GrClipEdgeTypeIsAA(cpe.fEdgeType)) {
112                     edge = Saturate(edge);
113                 } else {
114                     edge = Select(edge >= 0.5, 1.0, 0.0);
115                 }
116                 alpha *= edge;
117             }
118 
119             if (GrClipEdgeTypeIsInverseFill(cpe.fEdgeType)) {
120                 alpha = 1.0 - alpha;
121             }
122 
123             Return(SampleChild(0) * alpha);
124             EndFragmentProcessor();
125         }
126 
127     private:
128         void onSetData(const GrGLSLProgramDataManager& pdman,
129                        const GrFragmentProcessor& fp) override {
130             const GrConvexPolyEffect& cpe = fp.cast<GrConvexPolyEffect>();
131             size_t n = 3*cpe.fEdgeCount;
132             if (!std::equal(fPrevEdges.begin(), fPrevEdges.begin() + n, cpe.fEdges.begin())) {
133                 pdman.set3fv(fEdgeUniform, cpe.fEdgeCount, cpe.fEdges.data());
134                 std::copy_n(cpe.fEdges.begin(), n, fPrevEdges.begin());
135             }
136         }
137 
138         GrGLSLProgramDataManager::UniformHandle              fEdgeUniform;
139         std::array<float, 3 * GrConvexPolyEffect::kMaxEdges> fPrevEdges = {SK_FloatNaN};
140     };
141 
142     return std::make_unique<Impl>();
143 }
144 
GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP,GrClipEdgeType edgeType,int n,const float edges[])145 GrConvexPolyEffect::GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
146                                        GrClipEdgeType edgeType,
147                                        int n,
148                                        const float edges[])
149         : INHERITED(kGrConvexPolyEffect_ClassID,
150                     ProcessorOptimizationFlags(inputFP.get()) &
151                             kCompatibleWithCoverageAsAlpha_OptimizationFlag)
152         , fEdgeType(edgeType)
153         , fEdgeCount(n) {
154     // Factory function should have already ensured this.
155     SkASSERT(n <= kMaxEdges);
156     std::copy_n(edges, 3*n, fEdges.begin());
157     // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case
158     // and 100% covered in the non-AA case.
159     for (int i = 0; i < n; ++i) {
160         fEdges[3 * i + 2] += SK_ScalarHalf;
161     }
162 
163     this->registerChild(std::move(inputFP));
164 }
165 
GrConvexPolyEffect(const GrConvexPolyEffect & that)166 GrConvexPolyEffect::GrConvexPolyEffect(const GrConvexPolyEffect& that)
167         : INHERITED(that)
168         , fEdgeType(that.fEdgeType)
169         , fEdgeCount(that.fEdgeCount) {
170     std::copy_n(that.fEdges.begin(), 3*that.fEdgeCount, fEdges.begin());
171 }
172 
clone() const173 std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::clone() const {
174     return std::unique_ptr<GrFragmentProcessor>(new GrConvexPolyEffect(*this));
175 }
176 
onIsEqual(const GrFragmentProcessor & other) const177 bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
178     const GrConvexPolyEffect& cpe = other.cast<GrConvexPolyEffect>();
179     int n = 3*cpe.fEdgeCount;
180     return cpe.fEdgeType == fEdgeType   &&
181            cpe.fEdgeCount == fEdgeCount &&
182            std::equal(cpe.fEdges.begin(), cpe.fEdges.begin() + n, fEdges.begin());
183 }
184 
185 //////////////////////////////////////////////////////////////////////////////
186 
187 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect);
188 
189 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)190 std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::TestCreate(GrProcessorTestData* d) {
191     int count = d->fRandom->nextULessThan(kMaxEdges) + 1;
192     SkScalar edges[kMaxEdges * 3];
193     for (int i = 0; i < 3 * count; ++i) {
194         edges[i] = d->fRandom->nextSScalar1();
195     }
196 
197     bool success;
198     std::unique_ptr<GrFragmentProcessor> fp = d->inputFP();
199     do {
200         GrClipEdgeType edgeType =
201                 static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
202         std::tie(success, fp) = GrConvexPolyEffect::Make(std::move(fp), edgeType, count, edges);
203     } while (!success);
204     return fp;
205 }
206 #endif
207