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