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