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