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 "SkPath.h"
11 #include "gl/GrGLProcessor.h"
12 #include "gl/GrGLSL.h"
13 #include "gl/builders/GrGLProgramBuilder.h"
14
15 //////////////////////////////////////////////////////////////////////////////
16 class AARectEffect : public GrFragmentProcessor {
17 public:
getRect() const18 const SkRect& getRect() const { return fRect; }
19
Create(GrPrimitiveEdgeType edgeType,const SkRect & rect)20 static GrFragmentProcessor* Create(GrPrimitiveEdgeType edgeType, const SkRect& rect) {
21 return SkNEW_ARGS(AARectEffect, (edgeType, rect));
22 }
23
getEdgeType() const24 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
25
name() const26 const char* name() const override { return "AARect"; }
27
28 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
29
30 GrGLFragmentProcessor* createGLInstance() 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
onIsEqual(const GrFragmentProcessor & other) const39 bool onIsEqual(const GrFragmentProcessor& other) const override {
40 const AARectEffect& aare = other.cast<AARectEffect>();
41 return fRect == aare.fRect;
42 }
43
onComputeInvariantOutput(GrInvariantOutput * inout) const44 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
45 if (fRect.isEmpty()) {
46 // An empty rect will have no coverage anywhere.
47 inout->mulByKnownSingleComponent(0);
48 } else {
49 inout->mulByUnknownSingleComponent();
50 }
51 }
52
53 SkRect fRect;
54 GrPrimitiveEdgeType fEdgeType;
55
56 typedef GrFragmentProcessor INHERITED;
57
58 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
59
60 };
61
62 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(AARectEffect);
63
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])64 GrFragmentProcessor* AARectEffect::TestCreate(SkRandom* random,
65 GrContext*,
66 const GrDrawTargetCaps& caps,
67 GrTexture*[]) {
68 SkRect rect = SkRect::MakeLTRB(random->nextSScalar1(),
69 random->nextSScalar1(),
70 random->nextSScalar1(),
71 random->nextSScalar1());
72 GrFragmentProcessor* fp;
73 do {
74 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan(
75 kGrProcessorEdgeTypeCnt));
76
77 fp = AARectEffect::Create(edgeType, rect);
78 } while (NULL == fp);
79 return fp;
80 }
81
82 //////////////////////////////////////////////////////////////////////////////
83
84 class GLAARectEffect : public GrGLFragmentProcessor {
85 public:
86 GLAARectEffect(const GrProcessor&);
87
88 virtual void emitCode(GrGLFPBuilder* builder,
89 const GrFragmentProcessor& fp,
90 const char* outputColor,
91 const char* inputColor,
92 const TransformedCoordsArray&,
93 const TextureSamplerArray&) override;
94
95 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
96
97 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
98
99 private:
100 GrGLProgramDataManager::UniformHandle fRectUniform;
101 SkRect fPrevRect;
102 typedef GrGLFragmentProcessor INHERITED;
103 };
104
GLAARectEffect(const GrProcessor & effect)105 GLAARectEffect::GLAARectEffect(const GrProcessor& effect) {
106 fPrevRect.fLeft = SK_ScalarNaN;
107 }
108
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor & fp,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)109 void GLAARectEffect::emitCode(GrGLFPBuilder* builder,
110 const GrFragmentProcessor& fp,
111 const char* outputColor,
112 const char* inputColor,
113 const TransformedCoordsArray&,
114 const TextureSamplerArray& samplers) {
115 const AARectEffect& aare = fp.cast<AARectEffect>();
116 const char *rectName;
117 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
118 // respectively.
119 fRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
120 kVec4f_GrSLType,
121 kDefault_GrSLPrecision,
122 "rect",
123 &rectName);
124
125 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
126 const char* fragmentPos = fsBuilder->fragmentPosition();
127 if (GrProcessorEdgeTypeIsAA(aare.getEdgeType())) {
128 // The amount of coverage removed in x and y by the edges is computed as a pair of negative
129 // numbers, xSub and ySub.
130 fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
131 fsBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
132 fsBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
133 fsBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
134 fsBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
135 // Now compute coverage in x and y and multiply them to get the fraction of the pixel
136 // covered.
137 fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
138 } else {
139 fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
140 fsBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
141 fsBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
142 fsBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
143 fsBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
144 }
145
146 if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) {
147 fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n");
148 }
149 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
150 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
151 }
152
setData(const GrGLProgramDataManager & pdman,const GrProcessor & processor)153 void GLAARectEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) {
154 const AARectEffect& aare = processor.cast<AARectEffect>();
155 const SkRect& rect = aare.getRect();
156 if (rect != fPrevRect) {
157 pdman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f,
158 rect.fRight - 0.5f, rect.fBottom - 0.5f);
159 fPrevRect = rect;
160 }
161 }
162
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)163 void GLAARectEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
164 GrProcessorKeyBuilder* b) {
165 const AARectEffect& aare = processor.cast<AARectEffect>();
166 b->add32(aare.getEdgeType());
167 }
168
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const169 void AARectEffect::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
170 GLAARectEffect::GenKey(*this, caps, b);
171 }
172
createGLInstance() const173 GrGLFragmentProcessor* AARectEffect::createGLInstance() const {
174 return SkNEW_ARGS(GLAARectEffect, (*this));
175 }
176
177 //////////////////////////////////////////////////////////////////////////////
178
179 class GrGLConvexPolyEffect : public GrGLFragmentProcessor {
180 public:
181 GrGLConvexPolyEffect(const GrProcessor&);
182
183 virtual void emitCode(GrGLFPBuilder* builder,
184 const GrFragmentProcessor& fp,
185 const char* outputColor,
186 const char* inputColor,
187 const TransformedCoordsArray&,
188 const TextureSamplerArray&) override;
189
190 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
191
192 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
193
194 private:
195 GrGLProgramDataManager::UniformHandle fEdgeUniform;
196 SkScalar fPrevEdges[3 * GrConvexPolyEffect::kMaxEdges];
197 typedef GrGLFragmentProcessor INHERITED;
198 };
199
GrGLConvexPolyEffect(const GrProcessor &)200 GrGLConvexPolyEffect::GrGLConvexPolyEffect(const GrProcessor&) {
201 fPrevEdges[0] = SK_ScalarNaN;
202 }
203
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor & fp,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)204 void GrGLConvexPolyEffect::emitCode(GrGLFPBuilder* builder,
205 const GrFragmentProcessor& fp,
206 const char* outputColor,
207 const char* inputColor,
208 const TransformedCoordsArray&,
209 const TextureSamplerArray& samplers) {
210 const GrConvexPolyEffect& cpe = fp.cast<GrConvexPolyEffect>();
211
212 const char *edgeArrayName;
213 fEdgeUniform = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
214 kVec3f_GrSLType,
215 kDefault_GrSLPrecision,
216 "edges",
217 cpe.getEdgeCount(),
218 &edgeArrayName);
219 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
220 fsBuilder->codeAppend("\t\tfloat alpha = 1.0;\n");
221 fsBuilder->codeAppend("\t\tfloat edge;\n");
222 const char* fragmentPos = fsBuilder->fragmentPosition();
223 for (int i = 0; i < cpe.getEdgeCount(); ++i) {
224 fsBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
225 edgeArrayName, i, fragmentPos, fragmentPos);
226 if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) {
227 fsBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
228 } else {
229 fsBuilder->codeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n");
230 }
231 fsBuilder->codeAppend("\t\talpha *= edge;\n");
232 }
233
234 // Woe is me. See skbug.com/2149.
235 if (kTegra2_GrGLRenderer == builder->ctxInfo().renderer()) {
236 fsBuilder->codeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n");
237 }
238
239 if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) {
240 fsBuilder->codeAppend("\talpha = 1.0 - alpha;\n");
241 }
242 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
243 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
244 }
245
setData(const GrGLProgramDataManager & pdman,const GrProcessor & effect)246 void GrGLConvexPolyEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& effect) {
247 const GrConvexPolyEffect& cpe = effect.cast<GrConvexPolyEffect>();
248 size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar);
249 if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) {
250 pdman.set3fv(fEdgeUniform, cpe.getEdgeCount(), cpe.getEdges());
251 memcpy(fPrevEdges, cpe.getEdges(), byteSize);
252 }
253 }
254
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)255 void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
256 GrProcessorKeyBuilder* b) {
257 const GrConvexPolyEffect& cpe = processor.cast<GrConvexPolyEffect>();
258 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8);
259 uint32_t key = (cpe.getEdgeCount() << 3) | cpe.getEdgeType();
260 b->add32(key);
261 }
262
263 //////////////////////////////////////////////////////////////////////////////
264
Create(GrPrimitiveEdgeType type,const SkPath & path,const SkVector * offset)265 GrFragmentProcessor* GrConvexPolyEffect::Create(GrPrimitiveEdgeType type, const SkPath& path,
266 const SkVector* offset) {
267 if (kHairlineAA_GrProcessorEdgeType == type) {
268 return NULL;
269 }
270 if (path.getSegmentMasks() != SkPath::kLine_SegmentMask ||
271 !path.isConvex()) {
272 return NULL;
273 }
274
275 if (path.countPoints() > kMaxEdges) {
276 return NULL;
277 }
278
279 SkPoint pts[kMaxEdges];
280 SkScalar edges[3 * kMaxEdges];
281
282 SkPath::Direction dir;
283 SkAssertResult(path.cheapComputeDirection(&dir));
284
285 SkVector t;
286 if (NULL == offset) {
287 t.set(0, 0);
288 } else {
289 t = *offset;
290 }
291
292 int count = path.getPoints(pts, kMaxEdges);
293 int n = 0;
294 for (int lastPt = count - 1, i = 0; i < count; lastPt = i++) {
295 if (pts[lastPt] != pts[i]) {
296 SkVector v = pts[i] - pts[lastPt];
297 v.normalize();
298 if (SkPath::kCCW_Direction == dir) {
299 edges[3 * n] = v.fY;
300 edges[3 * n + 1] = -v.fX;
301 } else {
302 edges[3 * n] = -v.fY;
303 edges[3 * n + 1] = v.fX;
304 }
305 SkPoint p = pts[i] + t;
306 edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY);
307 ++n;
308 }
309 }
310 if (path.isInverseFillType()) {
311 type = GrInvertProcessorEdgeType(type);
312 }
313 return Create(type, n, edges);
314 }
315
Create(GrPrimitiveEdgeType edgeType,const SkRect & rect)316 GrFragmentProcessor* GrConvexPolyEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& rect) {
317 if (kHairlineAA_GrProcessorEdgeType == edgeType){
318 return NULL;
319 }
320 return AARectEffect::Create(edgeType, rect);
321 }
322
~GrConvexPolyEffect()323 GrConvexPolyEffect::~GrConvexPolyEffect() {}
324
onComputeInvariantOutput(GrInvariantOutput * inout) const325 void GrConvexPolyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
326 inout->mulByUnknownSingleComponent();
327 }
328
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const329 void GrConvexPolyEffect::getGLProcessorKey(const GrGLSLCaps& caps,
330 GrProcessorKeyBuilder* b) const {
331 GrGLConvexPolyEffect::GenKey(*this, caps, b);
332 }
333
createGLInstance() const334 GrGLFragmentProcessor* GrConvexPolyEffect::createGLInstance() const {
335 return SkNEW_ARGS(GrGLConvexPolyEffect, (*this));
336 }
337
GrConvexPolyEffect(GrPrimitiveEdgeType edgeType,int n,const SkScalar edges[])338 GrConvexPolyEffect::GrConvexPolyEffect(GrPrimitiveEdgeType edgeType, int n, const SkScalar edges[])
339 : fEdgeType(edgeType)
340 , fEdgeCount(n) {
341 this->initClassID<GrConvexPolyEffect>();
342 // Factory function should have already ensured this.
343 SkASSERT(n <= kMaxEdges);
344 memcpy(fEdges, edges, 3 * n * sizeof(SkScalar));
345 // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case
346 // and 100% covered in the non-AA case.
347 for (int i = 0; i < n; ++i) {
348 fEdges[3 * i + 2] += SK_ScalarHalf;
349 }
350 this->setWillReadFragmentPosition();
351 }
352
onIsEqual(const GrFragmentProcessor & other) const353 bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
354 const GrConvexPolyEffect& cpe = other.cast<GrConvexPolyEffect>();
355 // ignore the fact that 0 == -0 and just use memcmp.
356 return (cpe.fEdgeType == fEdgeType && cpe.fEdgeCount == fEdgeCount &&
357 0 == memcmp(cpe.fEdges, fEdges, 3 * fEdgeCount * sizeof(SkScalar)));
358 }
359
360 //////////////////////////////////////////////////////////////////////////////
361
362 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect);
363
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps & caps,GrTexture * [])364 GrFragmentProcessor* GrConvexPolyEffect::TestCreate(SkRandom* random,
365 GrContext*,
366 const GrDrawTargetCaps& caps,
367 GrTexture*[]) {
368 int count = random->nextULessThan(kMaxEdges) + 1;
369 SkScalar edges[kMaxEdges * 3];
370 for (int i = 0; i < 3 * count; ++i) {
371 edges[i] = random->nextSScalar1();
372 }
373
374 GrFragmentProcessor* fp;
375 do {
376 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
377 random->nextULessThan(kGrProcessorEdgeTypeCnt));
378 fp = GrConvexPolyEffect::Create(edgeType, count, edges);
379 } while (NULL == fp);
380 return fp;
381 }
382