/src/skia/src/shaders/SkShaderBase.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
11 | | #include "include/core/SkMatrix.h" |
12 | | #include "include/core/SkPaint.h" |
13 | | #include "include/core/SkSamplingOptions.h" |
14 | | #include "include/core/SkShader.h" |
15 | | #include "include/private/SkNoncopyable.h" |
16 | | #include "src/core/SkEffectPriv.h" |
17 | | #include "src/core/SkMask.h" |
18 | | #include "src/core/SkTLazy.h" |
19 | | #include "src/core/SkVM_fwd.h" |
20 | | |
21 | | #if SK_SUPPORT_GPU |
22 | | #include "src/gpu/GrFPArgs.h" |
23 | | #endif |
24 | | |
25 | | class GrFragmentProcessor; |
26 | | class SkArenaAlloc; |
27 | | class SkColorSpace; |
28 | | class SkImage; |
29 | | struct SkImageInfo; |
30 | | class SkPaint; |
31 | | class SkRasterPipeline; |
32 | | class SkRuntimeEffect; |
33 | | |
34 | | /** |
35 | | * Shaders can optionally return a subclass of this when appending their stages. |
36 | | * Doing so tells the caller that the stages can be reused with different CTMs (but nothing |
37 | | * else can change), by calling the updater's udpate() method before each use. |
38 | | * |
39 | | * This can be a perf-win bulk draws like drawAtlas and drawVertices, where most of the setup |
40 | | * (i.e. uniforms) are constant, and only something small is changing (i.e. matrices). This |
41 | | * reuse skips the cost of computing the stages (and/or avoids having to allocate a separate |
42 | | * shader for each small draw. |
43 | | */ |
44 | | class SkStageUpdater { |
45 | | public: |
46 | 0 | virtual ~SkStageUpdater() {} |
47 | | |
48 | | virtual bool SK_WARN_UNUSED_RESULT update(const SkMatrix& ctm) = 0; |
49 | | }; |
50 | | |
51 | | class SkUpdatableShader; |
52 | | |
53 | | class SkShaderBase : public SkShader { |
54 | | public: |
55 | | ~SkShaderBase() override; |
56 | | |
57 | | sk_sp<SkShader> makeInvertAlpha() const; |
58 | | sk_sp<SkShader> makeWithCTM(const SkMatrix&) const; // owns its own ctm |
59 | | |
60 | | /** |
61 | | * Returns true if the shader is guaranteed to produce only a single color. |
62 | | * Subclasses can override this to allow loop-hoisting optimization. |
63 | | */ |
64 | 575k | virtual bool isConstant() const { return false; } |
65 | | |
66 | 822k | const SkMatrix& getLocalMatrix() const { return fLocalMatrix; } |
67 | | |
68 | | enum Flags { |
69 | | //!< set if all of the colors will be opaque |
70 | | kOpaqueAlpha_Flag = 1 << 0, |
71 | | |
72 | | /** set if the spans only vary in X (const in Y). |
73 | | e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient |
74 | | that varies from left-to-right. This flag specifies this for |
75 | | shadeSpan(). |
76 | | */ |
77 | | kConstInY32_Flag = 1 << 1, |
78 | | |
79 | | /** hint for the blitter that 4f is the preferred shading mode. |
80 | | */ |
81 | | kPrefers4f_Flag = 1 << 2, |
82 | | }; |
83 | | |
84 | | /** |
85 | | * ContextRec acts as a parameter bundle for creating Contexts. |
86 | | */ |
87 | | struct ContextRec { |
88 | | ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM, |
89 | | SkColorType dstColorType, SkColorSpace* dstColorSpace) |
90 | | : fMatrix(&matrix) |
91 | | , fLocalMatrix(localM) |
92 | | , fDstColorType(dstColorType) |
93 | 551k | , fDstColorSpace(dstColorSpace) { |
94 | 551k | fPaintAlpha = paint.getAlpha(); |
95 | 551k | fPaintDither = paint.isDither(); |
96 | 551k | } |
97 | | |
98 | | const SkMatrix* fMatrix; // the current matrix in the canvas |
99 | | const SkMatrix* fLocalMatrix; // optional local matrix |
100 | | SkColorType fDstColorType; // the color type of the dest surface |
101 | | SkColorSpace* fDstColorSpace; // the color space of the dest surface (if any) |
102 | | SkAlpha fPaintAlpha; |
103 | | bool fPaintDither; |
104 | | |
105 | | bool isLegacyCompatible(SkColorSpace* shadersColorSpace) const; |
106 | | }; |
107 | | |
108 | | class Context : public ::SkNoncopyable { |
109 | | public: |
110 | | Context(const SkShaderBase& shader, const ContextRec&); |
111 | | |
112 | | virtual ~Context(); |
113 | | |
114 | | /** |
115 | | * Called sometimes before drawing with this shader. Return the type of |
116 | | * alpha your shader will return. The default implementation returns 0. |
117 | | * Your subclass should override if it can (even sometimes) report a |
118 | | * non-zero value, since that will enable various blitters to perform |
119 | | * faster. |
120 | | */ |
121 | 30.1k | virtual uint32_t getFlags() const { return 0; } |
122 | | |
123 | | /** |
124 | | * Called for each span of the object being drawn. Your subclass should |
125 | | * set the appropriate colors (with premultiplied alpha) that correspond |
126 | | * to the specified device coordinates. |
127 | | */ |
128 | | virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; |
129 | | |
130 | | protected: |
131 | | // Reference to shader, so we don't have to dupe information. |
132 | | const SkShaderBase& fShader; |
133 | | |
134 | 48.9M | uint8_t getPaintAlpha() const { return fPaintAlpha; } |
135 | 864 | const SkMatrix& getTotalInverse() const { return fTotalInverse; } |
136 | 0 | const SkMatrix& getCTM() const { return fCTM; } |
137 | | |
138 | | private: |
139 | | SkMatrix fCTM; |
140 | | SkMatrix fTotalInverse; |
141 | | uint8_t fPaintAlpha; |
142 | | |
143 | | using INHERITED = SkNoncopyable; |
144 | | }; |
145 | | |
146 | | /** |
147 | | * Make a context using the memory provided by the arena. |
148 | | * |
149 | | * @return pointer to context or nullptr if can't be created |
150 | | */ |
151 | | Context* makeContext(const ContextRec&, SkArenaAlloc*) const; |
152 | | |
153 | | #if SK_SUPPORT_GPU |
154 | | /** |
155 | | * Returns a GrFragmentProcessor that implements the shader for the GPU backend. nullptr is |
156 | | * returned if there is no GPU implementation. |
157 | | * |
158 | | * The GPU device does not call SkShader::createContext(), instead we pass the view matrix, |
159 | | * local matrix, and filter quality directly. |
160 | | * |
161 | | * The GrRecordingContext may be used by the to create textures that are required by the |
162 | | * returned processor. |
163 | | * |
164 | | * The returned GrFragmentProcessor should expect an unpremultiplied input color and |
165 | | * produce a premultiplied output. |
166 | | */ |
167 | | virtual std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const; |
168 | | #endif |
169 | | |
170 | | /** |
171 | | * If the shader can represent its "average" luminance in a single color, return true and |
172 | | * if color is not NULL, return that color. If it cannot, return false and ignore the color |
173 | | * parameter. |
174 | | * |
175 | | * Note: if this returns true, the returned color will always be opaque, as only the RGB |
176 | | * components are used to compute luminance. |
177 | | */ |
178 | | bool asLuminanceColor(SkColor*) const; |
179 | | |
180 | | // If this returns false, then we draw nothing (do not fall back to shader context) |
181 | | SK_WARN_UNUSED_RESULT |
182 | | bool appendStages(const SkStageRec&) const; |
183 | | |
184 | | bool SK_WARN_UNUSED_RESULT computeTotalInverse(const SkMatrix& ctm, |
185 | | const SkMatrix* outerLocalMatrix, |
186 | | SkMatrix* totalInverse) const; |
187 | | |
188 | | // Returns the total local matrix for this shader: |
189 | | // |
190 | | // M = postLocalMatrix x shaderLocalMatrix x preLocalMatrix |
191 | | // |
192 | | SkTCopyOnFirstWrite<SkMatrix> totalLocalMatrix(const SkMatrix* preLocalMatrix) const; |
193 | | |
194 | 1.65k | virtual SkImage* onIsAImage(SkMatrix*, SkTileMode[2]) const { |
195 | 1.65k | return nullptr; |
196 | 1.65k | } |
197 | | |
198 | 562 | virtual SkRuntimeEffect* asRuntimeEffect() const { return nullptr; } |
199 | | |
200 | 7.89k | static Type GetFlattenableType() { return kSkShader_Type; } |
201 | 6.54k | Type getFlattenableType() const override { return GetFlattenableType(); } |
202 | | |
203 | | static sk_sp<SkShaderBase> Deserialize(const void* data, size_t size, |
204 | 0 | const SkDeserialProcs* procs = nullptr) { |
205 | 0 | return sk_sp<SkShaderBase>(static_cast<SkShaderBase*>( |
206 | 0 | SkFlattenable::Deserialize(GetFlattenableType(), data, size, procs).release())); |
207 | 0 | } |
208 | | static void RegisterFlattenables(); |
209 | | |
210 | | /** DEPRECATED. skbug.com/8941 |
211 | | * If this shader can be represented by another shader + a localMatrix, return that shader and |
212 | | * the localMatrix. If not, return nullptr and ignore the localMatrix parameter. |
213 | | */ |
214 | | virtual sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const; |
215 | | |
216 | | SkUpdatableShader* updatableShader(SkArenaAlloc* alloc) const; |
217 | | virtual SkUpdatableShader* onUpdatableShader(SkArenaAlloc* alloc) const; |
218 | | |
219 | 658 | SkStageUpdater* appendUpdatableStages(const SkStageRec& rec) const { |
220 | 658 | return this->onAppendUpdatableStages(rec); |
221 | 658 | } |
222 | | |
223 | | SK_WARN_UNUSED_RESULT |
224 | | skvm::Color program(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, |
225 | | const SkMatrixProvider&, const SkMatrix* localM, const SkColorInfo& dst, |
226 | | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const; |
227 | | |
228 | | protected: |
229 | | SkShaderBase(const SkMatrix* localMatrix = nullptr); |
230 | | |
231 | | void flatten(SkWriteBuffer&) const override; |
232 | | |
233 | | #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT |
234 | | /** |
235 | | * Specialize creating a SkShader context using the supplied allocator. |
236 | | * @return pointer to context owned by the arena allocator. |
237 | | */ |
238 | 10.3k | virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const { |
239 | 10.3k | return nullptr; |
240 | 10.3k | } |
241 | | #endif |
242 | | |
243 | 16.4k | virtual bool onAsLuminanceColor(SkColor*) const { |
244 | 16.4k | return false; |
245 | 16.4k | } |
246 | | |
247 | | // Default impl creates shadercontext and calls that (not very efficient) |
248 | | virtual bool onAppendStages(const SkStageRec&) const; |
249 | | |
250 | 658 | virtual SkStageUpdater* onAppendUpdatableStages(const SkStageRec&) const { return nullptr; } |
251 | | |
252 | | protected: |
253 | | static skvm::Coord ApplyMatrix(skvm::Builder*, const SkMatrix&, skvm::Coord, skvm::Uniforms*); |
254 | | |
255 | | private: |
256 | | // This is essentially const, but not officially so it can be modified in constructors. |
257 | | SkMatrix fLocalMatrix; |
258 | | |
259 | | virtual skvm::Color onProgram(skvm::Builder*, |
260 | | skvm::Coord device, skvm::Coord local, skvm::Color paint, |
261 | | const SkMatrixProvider&, const SkMatrix* localM, |
262 | | const SkColorInfo& dst, skvm::Uniforms*, SkArenaAlloc*) const = 0; |
263 | | |
264 | | using INHERITED = SkShader; |
265 | | }; |
266 | | |
267 | | class SkUpdatableShader : public SkShaderBase { |
268 | | public: |
269 | | virtual bool update(const SkMatrix& ctm) const = 0; |
270 | | |
271 | | private: |
272 | | // For serialization. This will never be called. |
273 | 0 | Factory getFactory() const override { return nullptr; } |
274 | 0 | const char* getTypeName() const override { return nullptr; } |
275 | | }; |
276 | | |
277 | 11.6M | inline SkShaderBase* as_SB(SkShader* shader) { |
278 | 11.6M | return static_cast<SkShaderBase*>(shader); |
279 | 11.6M | } |
280 | | |
281 | 471k | inline const SkShaderBase* as_SB(const SkShader* shader) { |
282 | 471k | return static_cast<const SkShaderBase*>(shader); |
283 | 471k | } |
284 | | |
285 | 139k | inline const SkShaderBase* as_SB(const sk_sp<SkShader>& shader) { |
286 | 139k | return static_cast<SkShaderBase*>(shader.get()); |
287 | 139k | } |
288 | | |
289 | | #endif // SkShaderBase_DEFINED |