Flutter Engine
The Flutter Engine
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,
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();
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
106void GrConvexPolyEffect::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
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 {
116 const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>();
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("float alpha = 1.0;\n"
127 "float edge;\n");
128 for (int i = 0; i < cpe.fEdgeCount; ++i) {
129 fragBuilder->codeAppendf("edge = dot(float3(%s[%d]), 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 * half(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
197bool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const {
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
Definition: FontMgrTest.cpp:50
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
Definition: GrTypesPriv.h:369
@ kFragment_GrShaderFlag
Definition: GrTypesPriv.h:287
static constexpr bool GrClipEdgeTypeIsInverseFill(const GrClipEdgeType edgeType)
Definition: GrTypesPriv.h:375
GrClipEdgeType
Definition: GrTypesPriv.h:361
static GrClipEdgeType GrInvertClipEdgeType(const GrClipEdgeType edgeType)
Definition: GrTypesPriv.h:385
static constexpr bool GrClipEdgeTypeIsAA(const GrClipEdgeType edgeType)
Definition: GrTypesPriv.h:380
static bool equal(const SkBitmap &a, const SkBitmap &b)
Definition: ImageTest.cpp:1395
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
Definition: SkColorData.h:378
constexpr float SK_FloatNaN
SkPathFirstDirection
Definition: SkPathEnums.h:19
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
#define SK_ScalarHalf
Definition: SkScalar.h:19
GLenum type
static constexpr int kMaxEdges
std::unique_ptr< GrFragmentProcessor > clone() const override
static GrFPResult Make(std::unique_ptr< GrFragmentProcessor > inputFP, GrClipEdgeType edgeType, int n, const float edges[])
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
Definition: GrProcessor.h:127
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
Definition: SkPath.cpp:2627
Verb next(SkPoint pts[4])
Definition: SkPath.cpp:1901
Definition: SkPath.h:59
@ kLine_SegmentMask
Definition: SkPath.h:1445
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kDone_Verb
Definition: SkPath.h:1472
@ kLine_Verb
Definition: SkPath.h:1467
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
const myers::Point & get(const myers::Segment &)
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
bool normalize()
Definition: SkPoint.cpp:22