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