Flutter Engine
The Flutter Engine
SkShaderBase.h
Go to the documentation of this file.
1/*
2 * Copyright 2017 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#ifndef SkShaderBase_DEFINED
9#define SkShaderBase_DEFINED
10
21
22#include <cstddef>
23#include <cstdint>
24#include <optional>
25#include <tuple>
26
27class SkArenaAlloc;
28class SkColorSpace;
29class SkImage;
30class SkRuntimeEffect;
31class SkWriteBuffer;
32enum SkColorType : int;
33enum class SkTileMode;
34struct SkDeserialProcs;
35struct SkStageRec;
36
37namespace SkShaders {
38/**
39 * This is used to accumulate matrices, starting with the CTM, when building up
40 * SkRasterPipeline or GrFragmentProcessor by walking the SkShader tree. It avoids
41 * adding a matrix multiply for each individual matrix. It also handles the reverse matrix
42 * concatenation order required by Android Framework, see b/256873449.
43 *
44 * This also tracks the dubious concept of a "total matrix", in the legacy Context/shadeSpan system.
45 * That includes all the matrices encountered during traversal to the current shader, including ones
46 * that have already been applied. The total matrix represents the transformation from the current
47 * shader's coordinate space to device space. It is dubious because it doesn't account for SkShaders
48 * that manipulate the coordinates passed to their children, which may not even be representable by
49 * a matrix.
50 *
51 * The total matrix is used for mipmap level selection and a filter downgrade optimizations in
52 * SkImageShader and sizing of the SkImage created by SkPictureShader. If we can remove usages
53 * of the "total matrix" and if Android Framework could be updated to not use backwards local
54 * matrix concatenation this could just be replaced by a simple SkMatrix or SkM44 passed down
55 * during traversal.
56 */
57class MatrixRec {
58public:
59 MatrixRec() = default;
60
61 explicit MatrixRec(const SkMatrix& ctm);
62
63 /**
64 * Returns a new MatrixRec that represents the existing total and pending matrix
65 * pre-concat'ed with m.
66 */
67 [[nodiscard]] MatrixRec concat(const SkMatrix& m) const;
68
69 /**
70 * Appends a mul by the inverse of the pending local matrix to the pipeline. 'postInv' is an
71 * additional matrix to post-apply to the inverted pending matrix. If the pending matrix is
72 * not invertible the std::optional result won't have a value and the pipeline will be
73 * unmodified.
74 */
75 [[nodiscard]] std::optional<MatrixRec> apply(const SkStageRec& rec,
76 const SkMatrix& postInv = {}) const;
77
78 /**
79 * FP matrices work differently than SkRasterPipeline. The starting coordinates provided to the
80 * root SkShader's FP are already in local space. So we never apply the inverse CTM. This
81 * returns the inverted pending local matrix with the provided postInv matrix applied after it.
82 * If the pending local matrix cannot be inverted, the boolean is false.
83 */
84 std::tuple<SkMatrix, bool> applyForFragmentProcessor(const SkMatrix& postInv) const;
85
86 /**
87 * A parent FP may need to create a FP for its child by calling
88 * SkShaderBase::asFragmentProcessor() and then pass the result to the apply() above.
89 * This comes up when the parent needs to ensure pending matrices are applied before the
90 * child because the parent is going to manipulate the coordinates *after* any pending
91 * matrix and pass the resulting coords to the child. This function gets a MatrixRec that
92 * reflects the state after this MatrixRec has bee applied but it does not apply it!
93 * Example:
94 * auto childFP = fChild->asFragmentProcessor(args, mrec.applied());
95 * childFP = MakeAWrappingFPThatModifiesChildsCoords(std::move(childFP));
96 * auto [success, parentFP] = mrec.apply(std::move(childFP));
97 */
98 MatrixRec applied() const;
99
100 /** Call to indicate that the mapping from shader to device space is not known. */
101 void markTotalMatrixInvalid() { fTotalMatrixIsValid = false; }
102
103 /** Marks the CTM as already applied; can avoid re-seeding the shader unnecessarily. */
104 void markCTMApplied() { fCTMApplied = true; }
105
106 /**
107 * Indicates whether the total matrix of a MatrixRec passed to a SkShader actually
108 * represents the full transform between that shader's coordinate space and device space.
109 */
110 bool totalMatrixIsValid() const { return fTotalMatrixIsValid; }
111
112 /**
113 * Gets the total transform from the current shader's space to device space. This may or
114 * may not be valid. Shaders should avoid making decisions based on this matrix if
115 * totalMatrixIsValid() is false.
116 */
117 SkMatrix totalMatrix() const { return SkMatrix::Concat(fCTM, fTotalLocalMatrix); }
118
119 /** Gets the inverse of totalMatrix(), if invertible. */
120 [[nodiscard]] bool totalInverse(SkMatrix* out) const {
121 return this->totalMatrix().invert(out);
122 }
123
124 /** Is there a transform that has not yet been applied by a parent shader? */
125 bool hasPendingMatrix() const {
126 return (!fCTMApplied && !fCTM.isIdentity()) || !fPendingLocalMatrix.isIdentity();
127 }
128
129 /** When generating raster pipeline, have the device coordinates been seeded? */
130 bool rasterPipelineCoordsAreSeeded() const { return fCTMApplied; }
131
132private:
133 MatrixRec(const SkMatrix& ctm,
134 const SkMatrix& totalLocalMatrix,
135 const SkMatrix& pendingLocalMatrix,
136 bool totalIsValid,
137 bool ctmApplied)
138 : fCTM(ctm)
139 , fTotalLocalMatrix(totalLocalMatrix)
140 , fPendingLocalMatrix(pendingLocalMatrix)
141 , fTotalMatrixIsValid(totalIsValid)
142 , fCTMApplied(ctmApplied) {}
143
144 const SkMatrix fCTM;
145
146 // Concatenation of all local matrices, including those already applied.
147 const SkMatrix fTotalLocalMatrix;
148
149 // The accumulated local matrices from walking down the shader hierarchy that have NOT yet
150 // been incorporated into the SkRasterPipeline.
151 const SkMatrix fPendingLocalMatrix;
152
153 bool fTotalMatrixIsValid = true;
154
155 // Tracks whether the CTM has already been applied (and in raster pipeline whether the
156 // device coords have been seeded.)
157 bool fCTMApplied = false;
158};
159
160} // namespace SkShaders
161
162#define SK_ALL_SHADERS(M) \
163 M(Blend) \
164 M(CTM) \
165 M(Color) \
166 M(Color4) \
167 M(ColorFilter) \
168 M(CoordClamp) \
169 M(Empty) \
170 M(GradientBase) \
171 M(Image) \
172 M(LocalMatrix) \
173 M(PerlinNoise) \
174 M(Picture) \
175 M(Runtime) \
176 M(Transform) \
177 M(TriColor) \
178 M(WorkingColorSpace)
179
180#define SK_ALL_GRADIENTS(M) \
181 M(Conical) \
182 M(Linear) \
183 M(Radial) \
184 M(Sweep)
185
186class SkShaderBase : public SkShader {
187public:
188 ~SkShaderBase() override;
189
191 sk_sp<SkShader> makeWithCTM(const SkMatrix&) const; // owns its own ctm
192
193 /**
194 * Returns true if the shader is guaranteed to produce only a single color.
195 * Subclasses can override this to allow loop-hoisting optimization.
196 */
197 virtual bool isConstant() const { return false; }
198
199 enum class ShaderType {
200#define M(type) k##type,
202#undef M
203 };
204
205 virtual ShaderType type() const = 0;
206
207 enum class GradientType {
208 kNone,
209#define M(type) k##type,
211#undef M
212 };
213
214 /**
215 * If the shader subclass can be represented as a gradient, asGradient
216 * returns the matching GradientType enum (or GradientType::kNone if it
217 * cannot). Also, if info is not null, asGradient populates info with
218 * the relevant (see below) parameters for the gradient. fColorCount
219 * is both an input and output parameter. On input, it indicates how
220 * many entries in fColors and fColorOffsets can be used, if they are
221 * non-NULL. After asGradient has run, fColorCount indicates how
222 * many color-offset pairs there are in the gradient. If there is
223 * insufficient space to store all of the color-offset pairs, fColors
224 * and fColorOffsets will not be altered. fColorOffsets specifies
225 * where on the range of 0 to 1 to transition to the given color.
226 * The meaning of fPoint and fRadius is dependent on the type of gradient.
227 *
228 * None:
229 * info is ignored.
230 * Color:
231 * fColorOffsets[0] is meaningless.
232 * Linear:
233 * fPoint[0] and fPoint[1] are the end-points of the gradient
234 * Radial:
235 * fPoint[0] and fRadius[0] are the center and radius
236 * Conical:
237 * fPoint[0] and fRadius[0] are the center and radius of the 1st circle
238 * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle
239 * Sweep:
240 * fPoint[0] is the center of the sweep.
241 */
243 int fColorCount = 0; //!< In-out parameter, specifies passed size
244 // of fColors/fColorOffsets on input, and
245 // actual number of colors/offsets on
246 // output.
247 SkColor* fColors = nullptr; //!< The colors in the gradient.
248 SkScalar* fColorOffsets = nullptr; //!< The unit offset for color transitions.
249 SkPoint fPoint[2]; //!< Type specific, see above.
250 SkScalar fRadius[2]; //!< Type specific, see above.
252 uint32_t fGradientFlags = 0; //!< see SkGradientShader::Flags
253 };
254
256 SkMatrix* localMatrix = nullptr) const {
257 return GradientType::kNone;
258 }
259
260 enum Flags {
261 //!< set if all of the colors will be opaque
263 };
264
265 /**
266 * ContextRec acts as a parameter bundle for creating Contexts.
267 */
268 struct ContextRec {
269 ContextRec(SkAlpha paintAlpha,
270 const SkShaders::MatrixRec& matrixRec,
271 SkColorType dstColorType,
272 SkColorSpace* dstColorSpace,
273 const SkSurfaceProps& props)
274 : fMatrixRec(matrixRec)
275 , fDstColorType(dstColorType)
276 , fDstColorSpace(dstColorSpace)
277 , fProps(props)
278 , fPaintAlpha(paintAlpha) {}
279
280 static ContextRec Concat(const ContextRec& parentRec, const SkMatrix& localM) {
281 return {parentRec.fPaintAlpha,
282 parentRec.fMatrixRec.concat(localM),
283 parentRec.fDstColorType,
284 parentRec.fDstColorSpace,
285 parentRec.fProps};
286 }
287
289 SkColorType fDstColorType; // the color type of the dest surface
290 SkColorSpace* fDstColorSpace; // the color space of the dest surface (if any)
291 SkSurfaceProps fProps; // props of the dest surface
293
294 bool isLegacyCompatible(SkColorSpace* shadersColorSpace) const;
295 };
296
297 class Context : public ::SkNoncopyable {
298 public:
299 Context(const SkShaderBase& shader, const ContextRec&);
300
301 virtual ~Context();
302
303 /**
304 * Called sometimes before drawing with this shader. Return the type of
305 * alpha your shader will return. The default implementation returns 0.
306 * Your subclass should override if it can (even sometimes) report a
307 * non-zero value, since that will enable various blitters to perform
308 * faster.
309 */
310 virtual uint32_t getFlags() const { return 0; }
311
312 /**
313 * Called for each span of the object being drawn. Your subclass should
314 * set the appropriate colors (with premultiplied alpha) that correspond
315 * to the specified device coordinates.
316 */
317 virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
318
319 protected:
320 // Reference to shader, so we don't have to dupe information.
322
323 uint8_t getPaintAlpha() const { return fPaintAlpha; }
324 const SkMatrix& getTotalInverse() const { return fTotalInverse; }
325
326 private:
327 SkMatrix fTotalInverse;
328 uint8_t fPaintAlpha;
329 };
330
331 /**
332 * Make a context using the memory provided by the arena.
333 *
334 * @return pointer to context or nullptr if can't be created
335 */
336 Context* makeContext(const ContextRec&, SkArenaAlloc*) const;
337
338 /**
339 * If the shader can represent its "average" luminance in a single color, return true and
340 * if color is not NULL, return that color. If it cannot, return false and ignore the color
341 * parameter.
342 *
343 * Note: if this returns true, the returned color will always be opaque, as only the RGB
344 * components are used to compute luminance.
345 */
346 bool asLuminanceColor(SkColor4f*) const;
347
348 /**
349 * If this returns false, then we draw nothing (do not fall back to shader context). This should
350 * only be called on a root-level effect. It assumes that the initial device coordinates have
351 * not yet been seeded.
352 */
353 [[nodiscard]] bool appendRootStages(const SkStageRec& rec, const SkMatrix& ctm) const;
354
355 /**
356 * Adds stages to implement this shader. To ensure that the correct input coords are present
357 * in r,g MatrixRec::apply() must be called (unless the shader doesn't require it's input
358 * coords). The default impl creates shadercontext and calls that (not very efficient).
359 */
360 virtual bool appendStages(const SkStageRec&, const SkShaders::MatrixRec&) const = 0;
361
362 virtual SkImage* onIsAImage(SkMatrix*, SkTileMode[2]) const {
363 return nullptr;
364 }
365
366 virtual SkRuntimeEffect* asRuntimeEffect() const { return nullptr; }
367
369 Type getFlattenableType() const override { return GetFlattenableType(); }
370
371 static sk_sp<SkShaderBase> Deserialize(const void* data, size_t size,
372 const SkDeserialProcs* procs = nullptr) {
373 return sk_sp<SkShaderBase>(static_cast<SkShaderBase*>(
375 }
376 static void RegisterFlattenables();
377
378 /** DEPRECATED. skbug.com/8941
379 * If this shader can be represented by another shader + a localMatrix, return that shader and
380 * the localMatrix. If not, return nullptr and ignore the localMatrix parameter.
381 */
382 virtual sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const;
383
384 static SkMatrix ConcatLocalMatrices(const SkMatrix& parentLM, const SkMatrix& childLM) {
385#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) // b/256873449
386 return SkMatrix::Concat(childLM, parentLM);
387#endif
388 return SkMatrix::Concat(parentLM, childLM);
389 }
390
391protected:
393
394 void flatten(SkWriteBuffer&) const override;
395
396#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
397 /**
398 * Specialize creating a SkShader context using the supplied allocator.
399 * @return pointer to context owned by the arena allocator.
400 */
401 virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const {
402 return nullptr;
403 }
404#endif
405
406 virtual bool onAsLuminanceColor(SkColor4f*) const {
407 return false;
408 }
409
411};
412inline SkShaderBase* as_SB(SkShader* shader) {
413 return static_cast<SkShaderBase*>(shader);
414}
415
416inline const SkShaderBase* as_SB(const SkShader* shader) {
417 return static_cast<const SkShaderBase*>(shader);
418}
419
420inline const SkShaderBase* as_SB(const sk_sp<SkShader>& shader) {
421 return static_cast<SkShaderBase*>(shader.get());
422}
423
431
432#endif // SkShaderBase_DEFINED
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
SkColorType
Definition: SkColorType.h:19
uint32_t SkColor
Definition: SkColor.h:37
uint8_t SkAlpha
Definition: SkColor.h:26
uint32_t SkPMColor
Definition: SkColor.h:205
SkShaderBase * as_SB(SkShader *shader)
Definition: SkShaderBase.h:412
void SkRegisterEmptyShaderFlattenable()
void SkRegisterWorkingColorSpaceShaderFlattenable()
void SkRegisterColor4ShaderFlattenable()
#define SK_ALL_GRADIENTS(M)
Definition: SkShaderBase.h:180
void SkRegisterColorShaderFlattenable()
void SkRegisterPerlinNoiseShaderFlattenable()
void SkRegisterBlendShaderFlattenable()
void SkRegisterCoordClampShaderFlattenable()
#define SK_ALL_SHADERS(M)
Definition: SkShaderBase.h:162
SkTileMode
Definition: SkTileMode.h:13
static sk_sp< SkFlattenable > Deserialize(Type, const void *data, size_t length, const SkDeserialProcs *procs=nullptr)
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
bool isIdentity() const
Definition: SkMatrix.h:223
uint8_t getPaintAlpha() const
Definition: SkShaderBase.h:323
virtual void shadeSpan(int x, int y, SkPMColor[], int count)=0
Context(const SkShaderBase &shader, const ContextRec &)
virtual uint32_t getFlags() const
Definition: SkShaderBase.h:310
const SkMatrix & getTotalInverse() const
Definition: SkShaderBase.h:324
const SkShaderBase & fShader
Definition: SkShaderBase.h:321
virtual bool onAsLuminanceColor(SkColor4f *) const
Definition: SkShaderBase.h:406
sk_sp< SkShader > makeInvertAlpha() const
@ kOpaqueAlpha_Flag
set if all of the colors will be opaque
Definition: SkShaderBase.h:262
virtual GradientType asGradient(GradientInfo *info=nullptr, SkMatrix *localMatrix=nullptr) const
Definition: SkShaderBase.h:255
virtual bool isConstant() const
Definition: SkShaderBase.h:197
bool appendRootStages(const SkStageRec &rec, const SkMatrix &ctm) const
void flatten(SkWriteBuffer &) const override
bool asLuminanceColor(SkColor4f *) const
sk_sp< SkShader > makeWithCTM(const SkMatrix &) const
static Type GetFlattenableType()
Definition: SkShaderBase.h:368
~SkShaderBase() override
static SkMatrix ConcatLocalMatrices(const SkMatrix &parentLM, const SkMatrix &childLM)
Definition: SkShaderBase.h:384
virtual ShaderType type() const =0
Type getFlattenableType() const override
Definition: SkShaderBase.h:369
virtual SkImage * onIsAImage(SkMatrix *, SkTileMode[2]) const
Definition: SkShaderBase.h:362
Context * makeContext(const ContextRec &, SkArenaAlloc *) const
virtual bool appendStages(const SkStageRec &, const SkShaders::MatrixRec &) const =0
virtual sk_sp< SkShader > makeAsALocalMatrixShader(SkMatrix *localMatrix) const
static void RegisterFlattenables()
virtual SkRuntimeEffect * asRuntimeEffect() const
Definition: SkShaderBase.h:366
static sk_sp< SkShaderBase > Deserialize(const void *data, size_t size, const SkDeserialProcs *procs=nullptr)
Definition: SkShaderBase.h:371
std::optional< MatrixRec > apply(const SkStageRec &rec, const SkMatrix &postInv={}) const
bool totalInverse(SkMatrix *out) const
Definition: SkShaderBase.h:120
MatrixRec applied() const
bool totalMatrixIsValid() const
Definition: SkShaderBase.h:110
std::tuple< SkMatrix, bool > applyForFragmentProcessor(const SkMatrix &postInv) const
MatrixRec concat(const SkMatrix &m) const
bool hasPendingMatrix() const
Definition: SkShaderBase.h:125
SkMatrix totalMatrix() const
Definition: SkShaderBase.h:117
bool rasterPipelineCoordsAreSeeded() const
Definition: SkShaderBase.h:130
T * get() const
Definition: SkRefCnt.h:303
float SkScalar
Definition: extension.cpp:12
double y
double x
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define M(PROC, DITHER)
const SkShaders::MatrixRec fMatrixRec
Definition: SkShaderBase.h:288
ContextRec(SkAlpha paintAlpha, const SkShaders::MatrixRec &matrixRec, SkColorType dstColorType, SkColorSpace *dstColorSpace, const SkSurfaceProps &props)
Definition: SkShaderBase.h:269
static ContextRec Concat(const ContextRec &parentRec, const SkMatrix &localM)
Definition: SkShaderBase.h:280
bool isLegacyCompatible(SkColorSpace *shadersColorSpace) const
SkColorSpace * fDstColorSpace
Definition: SkShaderBase.h:290
uint32_t fGradientFlags
see SkGradientShader::Flags
Definition: SkShaderBase.h:252
SkPoint fPoint[2]
Type specific, see above.
Definition: SkShaderBase.h:249
SkColor * fColors
The colors in the gradient.
Definition: SkShaderBase.h:247
int fColorCount
In-out parameter, specifies passed size.
Definition: SkShaderBase.h:243
SkScalar fRadius[2]
Type specific, see above.
Definition: SkShaderBase.h:250
SkScalar * fColorOffsets
The unit offset for color transitions.
Definition: SkShaderBase.h:248
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63