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