1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
9cb93a386Sopenharmony_ci#include "src/gpu/effects/GrConvexPolyEffect.h"
10cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
12cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h"
13cb93a386Sopenharmony_ci#include "src/sksl/dsl/priv/DSLFPs.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciGrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP,
18cb93a386Sopenharmony_ci                                    GrClipEdgeType type, const SkPath& path) {
19cb93a386Sopenharmony_ci    if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || !path.isConvex()) {
20cb93a386Sopenharmony_ci        return GrFPFailure(std::move(inputFP));
21cb93a386Sopenharmony_ci    }
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci    SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(path);
24cb93a386Sopenharmony_ci    // The only way this should fail is if the clip is effectively a infinitely thin line. In that
25cb93a386Sopenharmony_ci    // case nothing is inside the clip. It'd be nice to detect this at a higher level and either
26cb93a386Sopenharmony_ci    // skip the draw or omit the clip element.
27cb93a386Sopenharmony_ci    if (dir == SkPathFirstDirection::kUnknown) {
28cb93a386Sopenharmony_ci        if (GrClipEdgeTypeIsInverseFill(type)) {
29cb93a386Sopenharmony_ci            return GrFPSuccess(
30cb93a386Sopenharmony_ci                    GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fWHITE));
31cb93a386Sopenharmony_ci        }
32cb93a386Sopenharmony_ci        // This could use ConstColor instead of ModulateRGBA but it would trigger a debug print
33cb93a386Sopenharmony_ci        // about a coverage processor not being compatible with the alpha-as-coverage optimization.
34cb93a386Sopenharmony_ci        // We don't really care about this unlikely case so we just use ModulateRGBA to suppress
35cb93a386Sopenharmony_ci        // the print.
36cb93a386Sopenharmony_ci        return GrFPSuccess(
37cb93a386Sopenharmony_ci                GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fTRANSPARENT));
38cb93a386Sopenharmony_ci    }
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    SkScalar        edges[3 * kMaxEdges];
41cb93a386Sopenharmony_ci    SkPoint         pts[4];
42cb93a386Sopenharmony_ci    SkPath::Verb    verb;
43cb93a386Sopenharmony_ci    SkPath::Iter    iter(path, true);
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    // SkPath considers itself convex so long as there is a convex contour within it,
46cb93a386Sopenharmony_ci    // regardless of any degenerate contours such as a string of moveTos before it.
47cb93a386Sopenharmony_ci    // Iterate here to consume any degenerate contours and only process the points
48cb93a386Sopenharmony_ci    // on the actual convex contour.
49cb93a386Sopenharmony_ci    int n = 0;
50cb93a386Sopenharmony_ci    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
51cb93a386Sopenharmony_ci        switch (verb) {
52cb93a386Sopenharmony_ci            case SkPath::kMove_Verb:
53cb93a386Sopenharmony_ci            case SkPath::kClose_Verb:
54cb93a386Sopenharmony_ci                break;
55cb93a386Sopenharmony_ci            case SkPath::kLine_Verb: {
56cb93a386Sopenharmony_ci                if (n >= kMaxEdges) {
57cb93a386Sopenharmony_ci                    return GrFPFailure(std::move(inputFP));
58cb93a386Sopenharmony_ci                }
59cb93a386Sopenharmony_ci                if (pts[0] != pts[1]) {
60cb93a386Sopenharmony_ci                    SkVector v = pts[1] - pts[0];
61cb93a386Sopenharmony_ci                    v.normalize();
62cb93a386Sopenharmony_ci                    if (SkPathFirstDirection::kCCW == dir) {
63cb93a386Sopenharmony_ci                        edges[3 * n] = v.fY;
64cb93a386Sopenharmony_ci                        edges[3 * n + 1] = -v.fX;
65cb93a386Sopenharmony_ci                    } else {
66cb93a386Sopenharmony_ci                        edges[3 * n] = -v.fY;
67cb93a386Sopenharmony_ci                        edges[3 * n + 1] = v.fX;
68cb93a386Sopenharmony_ci                    }
69cb93a386Sopenharmony_ci                    edges[3 * n + 2] = -(edges[3 * n] * pts[1].fX + edges[3 * n + 1] * pts[1].fY);
70cb93a386Sopenharmony_ci                    ++n;
71cb93a386Sopenharmony_ci                }
72cb93a386Sopenharmony_ci                break;
73cb93a386Sopenharmony_ci            }
74cb93a386Sopenharmony_ci            default:
75cb93a386Sopenharmony_ci                // Non-linear segment so not a polygon.
76cb93a386Sopenharmony_ci                return GrFPFailure(std::move(inputFP));
77cb93a386Sopenharmony_ci        }
78cb93a386Sopenharmony_ci    }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci    if (path.isInverseFillType()) {
81cb93a386Sopenharmony_ci        type = GrInvertClipEdgeType(type);
82cb93a386Sopenharmony_ci    }
83cb93a386Sopenharmony_ci    return GrConvexPolyEffect::Make(std::move(inputFP), type, n, edges);
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ciGrConvexPolyEffect::~GrConvexPolyEffect() {}
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ciSkString GrConvexPolyEffect::getShaderDfxInfo() const
89cb93a386Sopenharmony_ci{
90cb93a386Sopenharmony_ci    SkString format;
91cb93a386Sopenharmony_ci    format.printf("ShaderDfx_GrConvexPolyEffect_%d_%d", fEdgeCount, fEdgeType);
92cb93a386Sopenharmony_ci    return format;
93cb93a386Sopenharmony_ci}
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_civoid GrConvexPolyEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
96cb93a386Sopenharmony_ci    static_assert(kGrClipEdgeTypeCnt <= 8);
97cb93a386Sopenharmony_ci    uint32_t key = (fEdgeCount << 3) | static_cast<int>(fEdgeType);
98cb93a386Sopenharmony_ci    b->add32(key);
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> GrConvexPolyEffect::onMakeProgramImpl() const {
102cb93a386Sopenharmony_ci    class Impl : public ProgramImpl {
103cb93a386Sopenharmony_ci    public:
104cb93a386Sopenharmony_ci        void emitCode(EmitArgs& args) override {
105cb93a386Sopenharmony_ci            const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>();
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci            using namespace SkSL::dsl;
108cb93a386Sopenharmony_ci            StartFragmentProcessor(this, &args);
109cb93a386Sopenharmony_ci            GlobalVar edgeArray(kUniform_Modifier, Array(kHalf3_Type, cpe.fEdgeCount), "edgeArray");
110cb93a386Sopenharmony_ci            Declare(edgeArray);
111cb93a386Sopenharmony_ci            fEdgeUniform = VarUniformHandle(edgeArray);
112cb93a386Sopenharmony_ci            Var alpha(kHalf_Type, "alpha", 1);
113cb93a386Sopenharmony_ci            Declare(alpha);
114cb93a386Sopenharmony_ci            Var edge(kHalf_Type, "edge");
115cb93a386Sopenharmony_ci            Declare(edge);
116cb93a386Sopenharmony_ci            for (int i = 0; i < cpe.fEdgeCount; ++i) {
117cb93a386Sopenharmony_ci                edge = Dot(edgeArray[i], Half3(Swizzle(sk_FragCoord(), X, Y, ONE)));
118cb93a386Sopenharmony_ci                if (GrClipEdgeTypeIsAA(cpe.fEdgeType)) {
119cb93a386Sopenharmony_ci                    edge = Saturate(edge);
120cb93a386Sopenharmony_ci                } else {
121cb93a386Sopenharmony_ci                    edge = Select(edge >= 0.5, 1.0, 0.0);
122cb93a386Sopenharmony_ci                }
123cb93a386Sopenharmony_ci                alpha *= edge;
124cb93a386Sopenharmony_ci            }
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci            if (GrClipEdgeTypeIsInverseFill(cpe.fEdgeType)) {
127cb93a386Sopenharmony_ci                alpha = 1.0 - alpha;
128cb93a386Sopenharmony_ci            }
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci            Return(SampleChild(0) * alpha);
131cb93a386Sopenharmony_ci            EndFragmentProcessor();
132cb93a386Sopenharmony_ci        }
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    private:
135cb93a386Sopenharmony_ci        void onSetData(const GrGLSLProgramDataManager& pdman,
136cb93a386Sopenharmony_ci                       const GrFragmentProcessor& fp) override {
137cb93a386Sopenharmony_ci            const GrConvexPolyEffect& cpe = fp.cast<GrConvexPolyEffect>();
138cb93a386Sopenharmony_ci            size_t n = 3*cpe.fEdgeCount;
139cb93a386Sopenharmony_ci            if (!std::equal(fPrevEdges.begin(), fPrevEdges.begin() + n, cpe.fEdges.begin())) {
140cb93a386Sopenharmony_ci                pdman.set3fv(fEdgeUniform, cpe.fEdgeCount, cpe.fEdges.data());
141cb93a386Sopenharmony_ci                std::copy_n(cpe.fEdges.begin(), n, fPrevEdges.begin());
142cb93a386Sopenharmony_ci            }
143cb93a386Sopenharmony_ci        }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci        GrGLSLProgramDataManager::UniformHandle              fEdgeUniform;
146cb93a386Sopenharmony_ci        std::array<float, 3 * GrConvexPolyEffect::kMaxEdges> fPrevEdges = {SK_FloatNaN};
147cb93a386Sopenharmony_ci    };
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci    return std::make_unique<Impl>();
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ciGrConvexPolyEffect::GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
153cb93a386Sopenharmony_ci                                       GrClipEdgeType edgeType,
154cb93a386Sopenharmony_ci                                       int n,
155cb93a386Sopenharmony_ci                                       const float edges[])
156cb93a386Sopenharmony_ci        : INHERITED(kGrConvexPolyEffect_ClassID,
157cb93a386Sopenharmony_ci                    ProcessorOptimizationFlags(inputFP.get()) &
158cb93a386Sopenharmony_ci                            kCompatibleWithCoverageAsAlpha_OptimizationFlag)
159cb93a386Sopenharmony_ci        , fEdgeType(edgeType)
160cb93a386Sopenharmony_ci        , fEdgeCount(n) {
161cb93a386Sopenharmony_ci    // Factory function should have already ensured this.
162cb93a386Sopenharmony_ci    SkASSERT(n <= kMaxEdges);
163cb93a386Sopenharmony_ci    std::copy_n(edges, 3*n, fEdges.begin());
164cb93a386Sopenharmony_ci    // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case
165cb93a386Sopenharmony_ci    // and 100% covered in the non-AA case.
166cb93a386Sopenharmony_ci    for (int i = 0; i < n; ++i) {
167cb93a386Sopenharmony_ci        fEdges[3 * i + 2] += SK_ScalarHalf;
168cb93a386Sopenharmony_ci    }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    this->registerChild(std::move(inputFP));
171cb93a386Sopenharmony_ci}
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ciGrConvexPolyEffect::GrConvexPolyEffect(const GrConvexPolyEffect& that)
174cb93a386Sopenharmony_ci        : INHERITED(that)
175cb93a386Sopenharmony_ci        , fEdgeType(that.fEdgeType)
176cb93a386Sopenharmony_ci        , fEdgeCount(that.fEdgeCount) {
177cb93a386Sopenharmony_ci    std::copy_n(that.fEdges.begin(), 3*that.fEdgeCount, fEdges.begin());
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::clone() const {
181cb93a386Sopenharmony_ci    return std::unique_ptr<GrFragmentProcessor>(new GrConvexPolyEffect(*this));
182cb93a386Sopenharmony_ci}
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_cibool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
185cb93a386Sopenharmony_ci    const GrConvexPolyEffect& cpe = other.cast<GrConvexPolyEffect>();
186cb93a386Sopenharmony_ci    int n = 3*cpe.fEdgeCount;
187cb93a386Sopenharmony_ci    return cpe.fEdgeType == fEdgeType   &&
188cb93a386Sopenharmony_ci           cpe.fEdgeCount == fEdgeCount &&
189cb93a386Sopenharmony_ci           std::equal(cpe.fEdges.begin(), cpe.fEdges.begin() + n, fEdges.begin());
190cb93a386Sopenharmony_ci}
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ciGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect);
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci#if GR_TEST_UTILS
197cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::TestCreate(GrProcessorTestData* d) {
198cb93a386Sopenharmony_ci    int count = d->fRandom->nextULessThan(kMaxEdges) + 1;
199cb93a386Sopenharmony_ci    SkScalar edges[kMaxEdges * 3];
200cb93a386Sopenharmony_ci    for (int i = 0; i < 3 * count; ++i) {
201cb93a386Sopenharmony_ci        edges[i] = d->fRandom->nextSScalar1();
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    bool success;
205cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> fp = d->inputFP();
206cb93a386Sopenharmony_ci    do {
207cb93a386Sopenharmony_ci        GrClipEdgeType edgeType =
208cb93a386Sopenharmony_ci                static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
209cb93a386Sopenharmony_ci        std::tie(success, fp) = GrConvexPolyEffect::Make(std::move(fp), edgeType, count, edges);
210cb93a386Sopenharmony_ci    } while (!success);
211cb93a386Sopenharmony_ci    return fp;
212cb93a386Sopenharmony_ci}
213cb93a386Sopenharmony_ci#endif
214