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