• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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 skgpu_graphite_KeyHelpers_DEFINED
9 #define skgpu_graphite_KeyHelpers_DEFINED
10 
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkBlendMode.h"
13 #include "include/core/SkM44.h"
14 #include "include/core/SkPoint3.h"
15 #include "include/core/SkSamplingOptions.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkSpan.h"
18 #include "include/core/SkTileMode.h"
19 #include "include/effects/SkGradientShader.h"
20 #include "include/gpu/graphite/Context.h"
21 #include "include/private/SkColorData.h"
22 #include "include/private/base/SkTArray.h"
23 #include "src/core/SkColorSpaceXformSteps.h"
24 #include "src/gpu/graphite/TextureProxy.h"
25 #include "src/shaders/SkShaderBase.h"
26 
27 class SkColorFilter;
28 class SkData;
29 class SkRuntimeEffect;
30 
31 namespace skgpu::graphite {
32 
33 class DrawContext;
34 class KeyContext;
35 class PaintParamsKeyBuilder;
36 class PipelineDataGatherer;
37 class UniquePaintParamsID;
38 enum class ReadSwizzle;
39 
40 // Types of logical "destinations" that a blender might blend with.
41 enum class DstColorType {
42     // A color read from the framebuffer.
43     kSurface,
44     // A color provided by geometry.
45     kPrimitive,
46     // A color evaluated by a child shader.
47     kChildOutput,
48 };
49 
50 /**
51  * The KeyHelpers can be used to manually construct an SkPaintParamsKey.
52  *
53  * TODO: If we restructure how the keys are made, we can utilize a single block type for the
54  * different blend blocks outlined below. The different Src/Dst pairings could instead be encoded
55  * as parent-child relationships.
56  */
57 
58 struct DstReadSampleBlock {
59     static void AddBlock(const KeyContext&,
60                          PaintParamsKeyBuilder*,
61                          PipelineDataGatherer*,
62                          sk_sp<TextureProxy> dst,
63                          SkIPoint dstOffset);
64 };
65 
66 struct SolidColorShaderBlock {
67     static void AddBlock(const KeyContext&,
68                          PaintParamsKeyBuilder*,
69                          PipelineDataGatherer*,
70                          const SkPMColor4f&);
71 };
72 
73 struct RGBPaintColorBlock {
74     static void AddBlock(const KeyContext&,
75                          PaintParamsKeyBuilder*,
76                          PipelineDataGatherer*);
77 };
78 
79 struct AlphaOnlyPaintColorBlock {
80     static void AddBlock(const KeyContext&,
81                          PaintParamsKeyBuilder*,
82                          PipelineDataGatherer*);
83 };
84 
85 struct GradientShaderBlocks {
86     struct GradientData {
87         // The number of stops stored internal to this data structure before falling back to
88         // bitmap storage.
89         static constexpr int kNumInternalStorageStops = 8;
90 
91         // This ctor is used during pre-compilation when we don't have enough information to
92         // extract uniform data. However, we must be able to provide enough data to make all the
93         // relevant decisions about which code snippets to use.
94         GradientData(SkShaderBase::GradientType, int numStops);
95 
96         // This ctor is used when extracting information from PaintParams. It must provide
97         // enough data to generate the uniform data the selected code snippet will require.
98         GradientData(SkShaderBase::GradientType,
99                      SkPoint point0, SkPoint point1,
100                      float radius0, float radius1,
101                      float bias, float scale,
102                      SkTileMode,
103                      int numStops,
104                      const SkPMColor4f* colors,
105                      const float* offsets,
106                      sk_sp<TextureProxy> colorsAndOffsetsProxy,
107                      bool useStorageBuffer,
108                      const SkGradientShader::Interpolation&);
109 
110         bool operator==(const GradientData& rhs) const = delete;
111         bool operator!=(const GradientData& rhs) const = delete;
112 
113         // Layout options.
114         SkShaderBase::GradientType fType;
115         SkPoint                    fPoints[2];
116         float                      fRadii[2];
117 
118         // Layout options for sweep gradient.
119         float                  fBias;
120         float                  fScale;
121 
122         SkTileMode             fTM;
123         int                    fNumStops;
124         bool                   fUseStorageBuffer;
125 
126         // For gradients w/ <= kNumInternalStorageStops stops we use fColors and fOffsets.
127         // The offsets are packed into a single float4 to save space when the layout is std140.
128         //
129         // Otherwise when storage buffers are preferred, we save the colors and offsets pointers
130         // to fSrcColors and fSrcOffsets so we can directly copy to the gatherer gradient buffer,
131         // else we pack the data into the fColorsAndOffsetsProxy texture.
132         SkPMColor4f                   fColors[kNumInternalStorageStops];
133         SkV4                          fOffsets[kNumInternalStorageStops / 4];
134         sk_sp<TextureProxy>           fColorsAndOffsetsProxy;
135         const SkPMColor4f*            fSrcColors;
136         const float*                  fSrcOffsets;
137 
138         SkGradientShader::Interpolation fInterpolation;
139     };
140 
141     static void AddBlock(const KeyContext&,
142                          PaintParamsKeyBuilder*,
143                          PipelineDataGatherer*,
144                          const GradientData&);
145 };
146 
147 struct LocalMatrixShaderBlock {
148     struct LMShaderData {
LMShaderDataLocalMatrixShaderBlock::LMShaderData149         LMShaderData(const SkMatrix& localMatrix)
150                 : fLocalMatrix(localMatrix) {
151         }
152 
153         const SkM44 fLocalMatrix;
154     };
155 
156     static void BeginBlock(const KeyContext&,
157                            PaintParamsKeyBuilder*,
158                            PipelineDataGatherer*,
159                            const LMShaderData&);
160 };
161 
162 struct ImageShaderBlock {
163     struct ImageData {
164         ImageData(const SkSamplingOptions& sampling,
165                   SkTileMode tileModeX,
166                   SkTileMode tileModeY,
167                   SkISize imgSize,
168                   SkRect subset,
169                   ReadSwizzle readSwizzle);
170 
171         SkSamplingOptions fSampling;
172         SkTileMode fTileModes[2];
173         SkISize fImgSize;
174         SkRect fSubset;
175         ReadSwizzle fReadSwizzle;
176 
177         SkColorSpaceXformSteps fSteps;
178 
179         // TODO: Currently this is only filled in when we're generating the key from an actual
180         // SkImageShader. In the pre-compile case we will need to create a Graphite promise
181         // image which holds the appropriate data.
182         sk_sp<TextureProxy> fTextureProxy;
183     };
184 
185     static void AddBlock(const KeyContext&,
186                          PaintParamsKeyBuilder*,
187                          PipelineDataGatherer*,
188                          const ImageData&);
189 };
190 
191 struct YUVImageShaderBlock {
192     struct ImageData {
193         ImageData(const SkSamplingOptions& sampling,
194                   SkTileMode tileModeX,
195                   SkTileMode tileModeY,
196                   SkISize imgSize,
197                   SkRect subset);
198 
199         SkSamplingOptions fSampling;
200         SkSamplingOptions fSamplingUV;
201         SkTileMode fTileModes[2];
202         SkISize fImgSize;
203         SkISize fImgSizeUV;  // Size of UV planes relative to Y's texel space
204         SkRect fSubset;
205         SkPoint fLinearFilterUVInset = { 0.50001f, 0.50001f };
206         SkV4 fChannelSelect[4];
207         SkMatrix fYUVtoRGBMatrix;
208         SkPoint3 fYUVtoRGBTranslate;
209 
210         // TODO: Currently these are only filled in when we're generating the key from an actual
211         // SkImageShader. In the pre-compile case we will need to create Graphite promise
212         // images which hold the appropriate data.
213         sk_sp<TextureProxy> fTextureProxies[4];
214     };
215 
216     static void AddBlock(const KeyContext&,
217                          PaintParamsKeyBuilder*,
218                          PipelineDataGatherer*,
219                          const ImageData&);
220 };
221 
222 struct CoordClampShaderBlock {
223     struct CoordClampData {
CoordClampDataCoordClampShaderBlock::CoordClampData224         CoordClampData(SkRect subset) : fSubset(subset) {}
225 
226         SkRect fSubset;
227     };
228 
229     // The gatherer and data should be null or non-null together
230     static void BeginBlock(const KeyContext&,
231                            PaintParamsKeyBuilder*,
232                            PipelineDataGatherer*,
233                            const CoordClampData&);
234 };
235 
236 struct DitherShaderBlock {
237     struct DitherData {
DitherDataDitherShaderBlock::DitherData238         DitherData(float range, sk_sp<TextureProxy> proxy)
239             : fRange(range)
240             , fLUTProxy(std::move(proxy)) {}
241 
242         float fRange;
243         sk_sp<TextureProxy> fLUTProxy;
244     };
245 
246     static void AddBlock(const KeyContext&,
247                          PaintParamsKeyBuilder*,
248                          PipelineDataGatherer*,
249                          const DitherData&);
250 };
251 
252 struct PerlinNoiseShaderBlock {
253     enum class Type {
254         kFractalNoise,
255         kTurbulence,
256     };
257 
258     struct PerlinNoiseData {
PerlinNoiseDataPerlinNoiseShaderBlock::PerlinNoiseData259         PerlinNoiseData(Type type,
260                         SkVector baseFrequency,
261                         int numOctaves,
262                         SkISize stitchData)
263             : fType(type)
264             , fBaseFrequency(baseFrequency)
265             , fNumOctaves(numOctaves)
266             , fStitchData{ SkIntToFloat(stitchData.fWidth), SkIntToFloat(stitchData.fHeight) } {
267         }
268 
stitchingPerlinNoiseShaderBlock::PerlinNoiseData269         bool stitching() const { return !fStitchData.isZero(); }
270 
271         Type fType;
272         SkVector fBaseFrequency;
273         int fNumOctaves;
274         SkVector fStitchData;
275 
276         sk_sp<TextureProxy> fPermutationsProxy;
277         sk_sp<TextureProxy> fNoiseProxy;
278     };
279 
280     // The gatherer and data should be null or non-null together
281     static void AddBlock(const KeyContext&,
282                          PaintParamsKeyBuilder*,
283                          PipelineDataGatherer*,
284                          const PerlinNoiseData&);
285 };
286 
287 struct BlendShaderBlock {
288     static void BeginBlock(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*);
289 };
290 
291 struct BlendModeBlenderBlock {
292     static void AddBlock(const KeyContext&,
293                          PaintParamsKeyBuilder*,
294                          PipelineDataGatherer*,
295                          SkBlendMode);
296 };
297 
298 struct CoeffBlenderBlock {
299     static void AddBlock(const KeyContext&,
300                          PaintParamsKeyBuilder*,
301                          PipelineDataGatherer*,
302                          SkSpan<const float> coeffs);
303 };
304 
305 struct ClipShaderBlock {
306     static void BeginBlock(const KeyContext&,
307                            PaintParamsKeyBuilder*,
308                            PipelineDataGatherer*);
309 };
310 
311 struct ComposeBlock {
312     static void BeginBlock(const KeyContext&,
313                            PaintParamsKeyBuilder*,
314                            PipelineDataGatherer*);
315 };
316 
317 struct MatrixColorFilterBlock {
318     struct MatrixColorFilterData {
MatrixColorFilterDataMatrixColorFilterBlock::MatrixColorFilterData319         MatrixColorFilterData(const float matrix[20],
320                               bool inHSLA)
321                 : fMatrix(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
322                           matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
323                           matrix[10], matrix[11], matrix[12], matrix[13],
324                           matrix[15], matrix[16], matrix[17], matrix[18])
325                 , fTranslate{matrix[4], matrix[9], matrix[14], matrix[19]}
326                 , fInHSLA(inHSLA) {
327         }
328 
329         SkM44 fMatrix;
330         SkV4  fTranslate;
331         bool  fInHSLA;
332     };
333 
334     // The gatherer and matrixCFData should be null or non-null together
335     static void AddBlock(const KeyContext&,
336                          PaintParamsKeyBuilder*,
337                          PipelineDataGatherer*,
338                          const MatrixColorFilterData&);
339 };
340 
341 struct TableColorFilterBlock {
342     struct TableColorFilterData {
TableColorFilterDataTableColorFilterBlock::TableColorFilterData343         TableColorFilterData(sk_sp<TextureProxy> proxy) : fTextureProxy(std::move(proxy)) {}
344 
345         sk_sp<TextureProxy> fTextureProxy;
346     };
347 
348     static void AddBlock(const KeyContext&,
349                          PaintParamsKeyBuilder*,
350                          PipelineDataGatherer*,
351                          const TableColorFilterData&);
352 };
353 
354 struct ColorSpaceTransformBlock {
355     struct ColorSpaceTransformData {
356         ColorSpaceTransformData(const SkColorSpace* src,
357                                 SkAlphaType srcAT,
358                                 const SkColorSpace* dst,
359                                 SkAlphaType dstAT);
ColorSpaceTransformDataColorSpaceTransformBlock::ColorSpaceTransformData360         ColorSpaceTransformData(const SkColorSpaceXformSteps& steps) { fSteps = steps; }
361         SkColorSpaceXformSteps fSteps;
362     };
363 
364     static void AddBlock(const KeyContext&,
365                          PaintParamsKeyBuilder*,
366                          PipelineDataGatherer*,
367                          const ColorSpaceTransformData&);
368 };
369 
370 /**
371  * Blend mode color filters blend their input (as the dst color) with some given color (supplied
372  * via a uniform) as the src color.
373  */
374 void AddBlendModeColorFilter(const KeyContext&,
375                              PaintParamsKeyBuilder*,
376                              PipelineDataGatherer*,
377                              SkBlendMode,
378                              const SkPMColor4f& srcColor);
379 
380 struct RuntimeEffectBlock {
381     struct ShaderData {
382         // This ctor is used during pre-compilation when we don't have enough information to
383         // extract uniform data.
384         ShaderData(sk_sp<const SkRuntimeEffect> effect);
385 
386         // This ctor is used when extracting information from PaintParams.
387         ShaderData(sk_sp<const SkRuntimeEffect> effect,
388                    sk_sp<const SkData> uniforms);
389 
390         bool operator==(const ShaderData& rhs) const;
391         bool operator!=(const ShaderData& rhs) const { return !(*this == rhs); }
392 
393         // Runtime shader data.
394         sk_sp<const SkRuntimeEffect> fEffect;
395         sk_sp<const SkData>          fUniforms;
396     };
397 
398     static void BeginBlock(const KeyContext&,
399                            PaintParamsKeyBuilder*,
400                            PipelineDataGatherer*,
401                            const ShaderData&);
402 };
403 
404 void AddToKey(const KeyContext&,
405               PaintParamsKeyBuilder*,
406               PipelineDataGatherer*,
407               const SkBlender*);
408 
409 /**
410  *  Add implementation details, for the specified backend, of this SkColorFilter to the
411  *  provided key.
412  *
413  *  @param keyContext backend context for key creation
414  *  @param builder    builder for creating the key for this SkShader
415  *  @param gatherer   if non-null, storage for this colorFilter's data
416  *  @param filter     This function is a no-op if filter is null.
417  */
418 void AddToKey(const KeyContext& keyContext,
419               PaintParamsKeyBuilder* builder,
420               PipelineDataGatherer* gatherer,
421               const SkColorFilter* filter);
422 
423 /**
424  *  Add implementation details, for the specified backend, of this SkShader to the
425  *  provided key.
426  *
427  *  @param keyContext backend context for key creation
428  *  @param builder    builder for creating the key for this SkShader
429  *  @param gatherer   if non-null, storage for this colorFilter's data
430  *  @param shader     This function is a no-op if shader is null.
431  */
432 void AddToKey(const KeyContext& keyContext,
433               PaintParamsKeyBuilder* builder,
434               PipelineDataGatherer* gatherer,
435               const SkShader* shader);
436 
437 // TODO(b/330864257) These visitation functions are redundant with AddToKey, except that they are
438 // executed in the Device::drawGeometry() stack frame, whereas the keys are currently deferred until
439 // DrawPass::Make. Image use needs to be detected in the draw frame to split tasks to match client
440 // actions. Once paint keys are extracted in the draw frame, this can go away entirely.
441 void NotifyImagesInUse(Recorder*, DrawContext*, const SkBlender*);
442 void NotifyImagesInUse(Recorder*, DrawContext*, const SkColorFilter*);
443 void NotifyImagesInUse(Recorder*, DrawContext*, const SkShader*);
444 
445 } // namespace skgpu::graphite
446 
447 #endif // skgpu_graphite_KeyHelpers_DEFINED
448