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//////////////////////////////////////////////////////////////////////////////
16class AARectEffect : public GrFragmentProcessor {
17public:
18    const SkRect& getRect() const { return fRect; }
19
20    static GrFragmentProcessor* Create(GrPrimitiveEdgeType edgeType, const SkRect& rect) {
21        return SkNEW_ARGS(AARectEffect, (edgeType, rect));
22    }
23
24    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
25
26    const char* name() const override { return "AARect"; }
27
28    void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
29
30    GrGLFragmentProcessor* createGLInstance() const override;
31
32private:
33    AARectEffect(GrPrimitiveEdgeType edgeType, const SkRect& rect)
34        : fRect(rect), fEdgeType(edgeType) {
35        this->initClassID<AARectEffect>();
36        this->setWillReadFragmentPosition();
37    }
38
39    bool onIsEqual(const GrFragmentProcessor& other) const override {
40        const AARectEffect& aare = other.cast<AARectEffect>();
41        return fRect == aare.fRect;
42    }
43
44    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
62GR_DEFINE_FRAGMENT_PROCESSOR_TEST(AARectEffect);
63
64GrFragmentProcessor* 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
84class GLAARectEffect : public GrGLFragmentProcessor {
85public:
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
99private:
100    GrGLProgramDataManager::UniformHandle fRectUniform;
101    SkRect                                fPrevRect;
102    typedef GrGLFragmentProcessor INHERITED;
103};
104
105GLAARectEffect::GLAARectEffect(const GrProcessor& effect) {
106    fPrevRect.fLeft = SK_ScalarNaN;
107}
108
109void 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
153void 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
163void GLAARectEffect::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
164                            GrProcessorKeyBuilder* b) {
165    const AARectEffect& aare = processor.cast<AARectEffect>();
166    b->add32(aare.getEdgeType());
167}
168
169void AARectEffect::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
170    GLAARectEffect::GenKey(*this, caps, b);
171}
172
173GrGLFragmentProcessor* AARectEffect::createGLInstance() const  {
174    return SkNEW_ARGS(GLAARectEffect, (*this));
175}
176
177//////////////////////////////////////////////////////////////////////////////
178
179class GrGLConvexPolyEffect : public GrGLFragmentProcessor {
180public:
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
194private:
195    GrGLProgramDataManager::UniformHandle fEdgeUniform;
196    SkScalar                              fPrevEdges[3 * GrConvexPolyEffect::kMaxEdges];
197    typedef GrGLFragmentProcessor INHERITED;
198};
199
200GrGLConvexPolyEffect::GrGLConvexPolyEffect(const GrProcessor&) {
201    fPrevEdges[0] = SK_ScalarNaN;
202}
203
204void 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
246void 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
255void 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
265GrFragmentProcessor* 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
316GrFragmentProcessor* GrConvexPolyEffect::Create(GrPrimitiveEdgeType edgeType, const SkRect& rect) {
317    if (kHairlineAA_GrProcessorEdgeType == edgeType){
318        return NULL;
319    }
320    return AARectEffect::Create(edgeType, rect);
321}
322
323GrConvexPolyEffect::~GrConvexPolyEffect() {}
324
325void GrConvexPolyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
326    inout->mulByUnknownSingleComponent();
327}
328
329void GrConvexPolyEffect::getGLProcessorKey(const GrGLSLCaps& caps,
330                                           GrProcessorKeyBuilder* b) const {
331    GrGLConvexPolyEffect::GenKey(*this, caps, b);
332}
333
334GrGLFragmentProcessor* GrConvexPolyEffect::createGLInstance() const  {
335    return SkNEW_ARGS(GrGLConvexPolyEffect, (*this));
336}
337
338GrConvexPolyEffect::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
353bool 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
362GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect);
363
364GrFragmentProcessor* 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