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