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