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