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