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 "GrConvexPolyEffect.h"
9 #include "GrInvariantOutput.h"
10 #include "SkPathPriv.h"
11 #include "effects/GrConstColorProcessor.h"
12 #include "glsl/GrGLSLFragmentProcessor.h"
13 #include "glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "glsl/GrGLSLProgramDataManager.h"
15 #include "glsl/GrGLSLUniformHandler.h"
16
17 //////////////////////////////////////////////////////////////////////////////
18 class AARectEffect : public GrFragmentProcessor {
19 public:
getRect() const20 const SkRect& getRect() const { return fRect; }
21
Make(GrPrimitiveEdgeType edgeType,const SkRect & rect)22 static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType edgeType, const SkRect& rect) {
23 return sk_sp<GrFragmentProcessor>(new AARectEffect(edgeType, rect));
24 }
25
getEdgeType() const26 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
27
name() const28 const char* name() const override { return "AARect"; }
29
30 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
31
32 private:
AARectEffect(GrPrimitiveEdgeType edgeType,const SkRect & rect)33 AARectEffect(GrPrimitiveEdgeType edgeType, const SkRect& rect)
34 : fRect(rect), fEdgeType(edgeType) {
35 this->initClassID<AARectEffect>();
36 this->setWillReadFragmentPosition();
37 }
38
39 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
40
onIsEqual(const GrFragmentProcessor & other) const41 bool onIsEqual(const GrFragmentProcessor& other) const override {
42 const AARectEffect& aare = other.cast<AARectEffect>();
43 return fRect == aare.fRect;
44 }
45
onComputeInvariantOutput(GrInvariantOutput * inout) const46 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
47 if (fRect.isEmpty()) {
48 // An empty rect will have no coverage anywhere.
49 inout->mulByKnownSingleComponent(0);
50 } else {
51 inout->mulByUnknownSingleComponent();
52 }
53 }
54
55 SkRect fRect;
56 GrPrimitiveEdgeType fEdgeType;
57
58 typedef GrFragmentProcessor INHERITED;
59
60 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
61
62 };
63
64 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(AARectEffect);
65
TestCreate(GrProcessorTestData * d)66 sk_sp<GrFragmentProcessor> AARectEffect::TestCreate(GrProcessorTestData* d) {
67 SkRect rect = SkRect::MakeLTRB(d->fRandom->nextSScalar1(),
68 d->fRandom->nextSScalar1(),
69 d->fRandom->nextSScalar1(),
70 d->fRandom->nextSScalar1());
71 sk_sp<GrFragmentProcessor> fp;
72 do {
73 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
74 d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt));
75
76 fp = AARectEffect::Make(edgeType, rect);
77 } while (nullptr == fp);
78 return fp;
79 }
80
81 //////////////////////////////////////////////////////////////////////////////
82
83 class GLAARectEffect : public GrGLSLFragmentProcessor {
84 public:
GLAARectEffect()85 GLAARectEffect() {
86 fPrevRect.fLeft = SK_ScalarNaN;
87 }
88
89 void emitCode(EmitArgs&) override;
90
91 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
92
93 protected:
94 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
95
96 private:
97 GrGLSLProgramDataManager::UniformHandle fRectUniform;
98 SkRect fPrevRect;
99
100 typedef GrGLSLFragmentProcessor INHERITED;
101 };
102
emitCode(EmitArgs & args)103 void GLAARectEffect::emitCode(EmitArgs& args) {
104 const AARectEffect& aare = args.fFp.cast<AARectEffect>();
105 const char *rectName;
106 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
107 // respectively.
108 fRectUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
109 kVec4f_GrSLType,
110 kDefault_GrSLPrecision,
111 "rect",
112 &rectName);
113
114 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
115 const char* fragmentPos = fragBuilder->fragmentPosition();
116 if (GrProcessorEdgeTypeIsAA(aare.getEdgeType())) {
117 // The amount of coverage removed in x and y by the edges is computed as a pair of negative
118 // numbers, xSub and ySub.
119 fragBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
120 fragBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
121 fragBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
122 fragBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
123 fragBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
124 // Now compute coverage in x and y and multiply them to get the fraction of the pixel
125 // covered.
126 fragBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
127 } else {
128 fragBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
129 fragBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
130 fragBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
131 fragBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
132 fragBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
133 }
134
135 if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) {
136 fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n");
137 }
138 fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor,
139 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
140 }
141
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)142 void GLAARectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
143 const GrProcessor& processor) {
144 const AARectEffect& aare = processor.cast<AARectEffect>();
145 const SkRect& rect = aare.getRect();
146 if (rect != fPrevRect) {
147 pdman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f,
148 rect.fRight - 0.5f, rect.fBottom - 0.5f);
149 fPrevRect = rect;
150 }
151 }
152
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)153 void GLAARectEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
154 GrProcessorKeyBuilder* b) {
155 const AARectEffect& aare = processor.cast<AARectEffect>();
156 b->add32(aare.getEdgeType());
157 }
158
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const159 void AARectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
160 GLAARectEffect::GenKey(*this, caps, b);
161 }
162
onCreateGLSLInstance() const163 GrGLSLFragmentProcessor* AARectEffect::onCreateGLSLInstance() const {
164 return new GLAARectEffect;
165 }
166
167 //////////////////////////////////////////////////////////////////////////////
168
169 class GrGLConvexPolyEffect : public GrGLSLFragmentProcessor {
170 public:
GrGLConvexPolyEffect()171 GrGLConvexPolyEffect() {
172 fPrevEdges[0] = SK_ScalarNaN;
173 }
174
175 void emitCode(EmitArgs&) override;
176
177 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
178
179 protected:
180 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
181
182 private:
183 GrGLSLProgramDataManager::UniformHandle fEdgeUniform;
184 SkScalar fPrevEdges[3 * GrConvexPolyEffect::kMaxEdges];
185 typedef GrGLSLFragmentProcessor INHERITED;
186 };
187
emitCode(EmitArgs & args)188 void GrGLConvexPolyEffect::emitCode(EmitArgs& args) {
189 const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>();
190
191 const char *edgeArrayName;
192 fEdgeUniform = args.fUniformHandler->addUniformArray(kFragment_GrShaderFlag,
193 kVec3f_GrSLType,
194 kDefault_GrSLPrecision,
195 "edges",
196 cpe.getEdgeCount(),
197 &edgeArrayName);
198 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
199 fragBuilder->codeAppend("\t\tfloat alpha = 1.0;\n");
200 fragBuilder->codeAppend("\t\tfloat edge;\n");
201 const char* fragmentPos = fragBuilder->fragmentPosition();
202 for (int i = 0; i < cpe.getEdgeCount(); ++i) {
203 fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
204 edgeArrayName, i, fragmentPos, fragmentPos);
205 if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) {
206 fragBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
207 } else {
208 fragBuilder->codeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n");
209 }
210 fragBuilder->codeAppend("\t\talpha *= edge;\n");
211 }
212
213 if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) {
214 fragBuilder->codeAppend("\talpha = 1.0 - alpha;\n");
215 }
216 fragBuilder->codeAppendf("\t%s = %s;\n", args.fOutputColor,
217 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
218 }
219
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & effect)220 void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman,
221 const GrProcessor& effect) {
222 const GrConvexPolyEffect& cpe = effect.cast<GrConvexPolyEffect>();
223 size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar);
224 if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) {
225 pdman.set3fv(fEdgeUniform, cpe.getEdgeCount(), cpe.getEdges());
226 memcpy(fPrevEdges, cpe.getEdges(), byteSize);
227 }
228 }
229
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)230 void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
231 GrProcessorKeyBuilder* b) {
232 const GrConvexPolyEffect& cpe = processor.cast<GrConvexPolyEffect>();
233 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8);
234 uint32_t key = (cpe.getEdgeCount() << 3) | cpe.getEdgeType();
235 b->add32(key);
236 }
237
238 //////////////////////////////////////////////////////////////////////////////
239
Make(GrPrimitiveEdgeType type,const SkPath & path,const SkVector * offset)240 sk_sp<GrFragmentProcessor> GrConvexPolyEffect::Make(GrPrimitiveEdgeType type, const SkPath& path,
241 const SkVector* offset) {
242 if (kHairlineAA_GrProcessorEdgeType == type) {
243 return nullptr;
244 }
245 if (path.getSegmentMasks() != SkPath::kLine_SegmentMask ||
246 !path.isConvex()) {
247 return nullptr;
248 }
249
250 SkPathPriv::FirstDirection dir;
251 // The only way this should fail is if the clip is effectively a infinitely thin line. In that
252 // case nothing is inside the clip. It'd be nice to detect this at a higher level and either
253 // skip the draw or omit the clip element.
254 if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) {
255 if (GrProcessorEdgeTypeIsInverseFill(type)) {
256 return GrConstColorProcessor::Make(0xFFFFFFFF,
257 GrConstColorProcessor::kModulateRGBA_InputMode);
258 }
259 return GrConstColorProcessor::Make(0, GrConstColorProcessor::kIgnore_InputMode);
260 }
261
262 SkVector t;
263 if (nullptr == offset) {
264 t.set(0, 0);
265 } else {
266 t = *offset;
267 }
268
269 SkScalar edges[3 * kMaxEdges];
270 SkPoint pts[4];
271 SkPath::Verb verb;
272 SkPath::Iter iter(path, true);
273
274 // SkPath considers itself convex so long as there is a convex contour within it,
275 // regardless of any degenerate contours such as a string of moveTos before it.
276 // Iterate here to consume any degenerate contours and only process the points
277 // on the actual convex contour.
278 int n = 0;
279 while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) {
280 switch (verb) {
281 case SkPath::kMove_Verb:
282 SkASSERT(n == 0);
283 case SkPath::kClose_Verb:
284 break;
285 case SkPath::kLine_Verb: {
286 if (n >= kMaxEdges) {
287 return nullptr;
288 }
289 SkVector v = pts[1] - pts[0];
290 v.normalize();
291 if (SkPathPriv::kCCW_FirstDirection == dir) {
292 edges[3 * n] = v.fY;
293 edges[3 * n + 1] = -v.fX;
294 } else {
295 edges[3 * n] = -v.fY;
296 edges[3 * n + 1] = v.fX;
297 }
298 SkPoint p = pts[1] + t;
299 edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY);
300 ++n;
301 break;
302 }
303 default:
304 return nullptr;
305 }
306 }
307
308 if (path.isInverseFillType()) {
309 type = GrInvertProcessorEdgeType(type);
310 }
311 return Make(type, n, edges);
312 }
313
Make(GrPrimitiveEdgeType edgeType,const SkRect & rect)314 sk_sp<GrFragmentProcessor> GrConvexPolyEffect::Make(GrPrimitiveEdgeType edgeType,
315 const SkRect& rect) {
316 if (kHairlineAA_GrProcessorEdgeType == edgeType){
317 return nullptr;
318 }
319 return AARectEffect::Make(edgeType, rect);
320 }
321
~GrConvexPolyEffect()322 GrConvexPolyEffect::~GrConvexPolyEffect() {}
323
onComputeInvariantOutput(GrInvariantOutput * inout) const324 void GrConvexPolyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
325 inout->mulByUnknownSingleComponent();
326 }
327
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const328 void GrConvexPolyEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
329 GrProcessorKeyBuilder* b) const {
330 GrGLConvexPolyEffect::GenKey(*this, caps, b);
331 }
332
onCreateGLSLInstance() const333 GrGLSLFragmentProcessor* GrConvexPolyEffect::onCreateGLSLInstance() const {
334 return new GrGLConvexPolyEffect;
335 }
336
GrConvexPolyEffect(GrPrimitiveEdgeType edgeType,int n,const SkScalar edges[])337 GrConvexPolyEffect::GrConvexPolyEffect(GrPrimitiveEdgeType edgeType, int n, const SkScalar edges[])
338 : fEdgeType(edgeType)
339 , fEdgeCount(n) {
340 this->initClassID<GrConvexPolyEffect>();
341 // Factory function should have already ensured this.
342 SkASSERT(n <= kMaxEdges);
343 memcpy(fEdges, edges, 3 * n * sizeof(SkScalar));
344 // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case
345 // and 100% covered in the non-AA case.
346 for (int i = 0; i < n; ++i) {
347 fEdges[3 * i + 2] += SK_ScalarHalf;
348 }
349 this->setWillReadFragmentPosition();
350 }
351
onIsEqual(const GrFragmentProcessor & other) const352 bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
353 const GrConvexPolyEffect& cpe = other.cast<GrConvexPolyEffect>();
354 // ignore the fact that 0 == -0 and just use memcmp.
355 return (cpe.fEdgeType == fEdgeType && cpe.fEdgeCount == fEdgeCount &&
356 0 == memcmp(cpe.fEdges, fEdges, 3 * fEdgeCount * sizeof(SkScalar)));
357 }
358
359 //////////////////////////////////////////////////////////////////////////////
360
361 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect);
362
TestCreate(GrProcessorTestData * d)363 sk_sp<GrFragmentProcessor> GrConvexPolyEffect::TestCreate(GrProcessorTestData* d) {
364 int count = d->fRandom->nextULessThan(kMaxEdges) + 1;
365 SkScalar edges[kMaxEdges * 3];
366 for (int i = 0; i < 3 * count; ++i) {
367 edges[i] = d->fRandom->nextSScalar1();
368 }
369
370 sk_sp<GrFragmentProcessor> fp;
371 do {
372 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
373 d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt));
374 fp = GrConvexPolyEffect::Make(edgeType, count, edges);
375 } while (nullptr == fp);
376 return fp;
377 }
378