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