Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Precompile.cpp
Go to the documentation of this file.
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
22
23namespace skgpu::graphite {
24
25//--------------------------------------------------------------------------------------------------
27 if (this->priv().isALocalMatrixShader()) {
28 // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
29 // follow suit here
30 return sk_ref_sp(this);
31 }
32
34}
35
37 if (!cf) {
38 return sk_ref_sp(this);
39 }
40
41 return PrecompileShaders::ColorFilter({ sk_ref_sp(this) }, { std::move(cf) });
42}
43
45 if (!cs) {
46 return sk_ref_sp(this);
47 }
48
49 return PrecompileShaders::WorkingColorSpace({ sk_ref_sp(this) }, { std::move(cs) });
50}
51
55
57 sk_sp<PrecompileColorFilter> inner) const {
58 if (!inner) {
59 return sk_ref_sp(this);
60 }
61
62 return PrecompileColorFilters::Compose({ sk_ref_sp(this) }, { std::move(inner) });
63}
64
65//--------------------------------------------------------------------------------------------------
67 // In the normal API this modification happens in SkDevice::clipShader()
68 fClipShaderOptions.reserve(2 * clipShaders.size());
69 for (const sk_sp<PrecompileShader>& cs : clipShaders) {
70 // All clipShaders get wrapped in a CTMShader ...
71 sk_sp<PrecompileShader> withCTM = cs ? cs->makeWithCTM() : nullptr;
72 // and, if it is a SkClipOp::kDifference clip, an additional ColorFilterShader
74 withCTM ? withCTM->makeWithColorFilter(PrecompileColorFilters::Blend())
75 : nullptr;
76
77 fClipShaderOptions.emplace_back(std::move(withCTM));
78 fClipShaderOptions.emplace_back(std::move(inverted));
79 }
80}
81
82int PaintOptions::numShaderCombinations() const {
83 int numShaderCombinations = 0;
84 for (const sk_sp<PrecompileShader>& s : fShaderOptions) {
85 numShaderCombinations += s->numCombinations();
86 }
87
88 // If no shader option is specified we will add a solid color shader option
89 return numShaderCombinations ? numShaderCombinations : 1;
90}
91
92int PaintOptions::numMaskFilterCombinations() const {
93 int numMaskFilterCombinations = 0;
94 for (const sk_sp<PrecompileMaskFilter>& mf : fMaskFilterOptions) {
95 numMaskFilterCombinations += mf->numCombinations();
96 }
97
98 // If no mask filter options are specified we will use the geometry's coverage
99 return numMaskFilterCombinations ? numMaskFilterCombinations : 1;
100}
101
102int PaintOptions::numColorFilterCombinations() const {
103 int numColorFilterCombinations = 0;
104 for (const sk_sp<PrecompileColorFilter>& cf : fColorFilterOptions) {
105 numColorFilterCombinations += cf->numCombinations();
106 }
107
108 // If no color filter options are specified we will use the unmodified result color
109 return numColorFilterCombinations ? numColorFilterCombinations : 1;
110}
111
112int PaintOptions::numBlendModeCombinations() const {
113 int numBlendCombos = fBlendModeOptions.size();
114 for (const sk_sp<PrecompileBlender>& b: fBlenderOptions) {
115 SkASSERT(!b->asBlendMode().has_value());
116 numBlendCombos += b->numChildCombinations();
117 }
118
119 if (!numBlendCombos) {
120 // If the user didn't specify a blender we will fall back to kSrcOver blending
121 numBlendCombos = 1;
122 }
123
124 return numBlendCombos;
125}
126
127int PaintOptions::numClipShaderCombinations() const {
128 int numClipShaderCombos = 0;
129 for (const sk_sp<PrecompileShader>& cs: fClipShaderOptions) {
130 if (cs) {
131 numClipShaderCombos += cs->numChildCombinations();
132 } else {
133 ++numClipShaderCombos;
134 }
135 }
136
137 // If no clipShader options are specified we will just have the unclipped options
138 return numClipShaderCombos ? numClipShaderCombos : 1;
139}
140
141
142int PaintOptions::numCombinations() const {
143 // TODO: we need to handle ImageFilters separately
144 return this->numShaderCombinations() *
145 this->numMaskFilterCombinations() *
146 this->numColorFilterCombinations() *
147 this->numBlendModeCombinations() *
148 this->numClipShaderCombinations();
149}
150
152 Coverage coverage,
153 PrecompileBlender* blender) {
154 if (blender) {
155 return GetDstReadRequirement(caps, blender->asBlendMode(), coverage);
156 }
157 return GetDstReadRequirement(caps, SkBlendMode::kSrcOver, coverage);
158}
159
161public:
162 PaintOption(bool opaquePaintColor,
163 const std::pair<sk_sp<PrecompileBlender>, int>& finalBlender,
164 const std::pair<sk_sp<PrecompileShader>, int>& shader,
165 const std::pair<sk_sp<PrecompileColorFilter>, int>& colorFilter,
166 bool hasPrimitiveBlender,
167 const std::pair<sk_sp<PrecompileShader>, int>& clipShader,
168 DstReadRequirement dstReadReq,
169 bool dither)
170 : fOpaquePaintColor(opaquePaintColor)
171 , fFinalBlender(finalBlender)
172 , fShader(shader)
173 , fColorFilter(colorFilter)
174 , fHasPrimitiveBlender(hasPrimitiveBlender)
175 , fClipShader(clipShader)
176 , fDstReadReq(dstReadReq)
177 , fDither(dither) {
178 }
179
180 const PrecompileBlender* finalBlender() const { return fFinalBlender.first.get(); }
181
183
184private:
185 void addPaintColorToKey(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
186 void handlePrimitiveColor(const KeyContext&,
188 PipelineDataGatherer*) const;
189 void handlePaintAlpha(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
190 void handleColorFilter(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
191 void handleDithering(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
192 void handleDstRead(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*) const;
193
194 bool shouldDither(SkColorType dstCT) const;
195
196 bool fOpaquePaintColor;
197 std::pair<sk_sp<PrecompileBlender>, int> fFinalBlender;
198 std::pair<sk_sp<PrecompileShader>, int> fShader;
199 std::pair<sk_sp<PrecompileColorFilter>, int> fColorFilter;
200 bool fHasPrimitiveBlender;
201 std::pair<sk_sp<PrecompileShader>, int> fClipShader;
202 DstReadRequirement fDstReadReq;
203 bool fDither;
204};
205
206
207void PaintOption::addPaintColorToKey(const KeyContext& keyContext,
208 PaintParamsKeyBuilder* builder,
209 PipelineDataGatherer* gatherer) const {
210 if (fShader.first) {
211 fShader.first->priv().addToKey(keyContext, builder, gatherer, fShader.second);
212 } else {
213 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
214 }
215}
216
217void PaintOption::handlePrimitiveColor(const KeyContext& keyContext,
218 PaintParamsKeyBuilder* keyBuilder,
219 PipelineDataGatherer* gatherer) const {
220 if (fHasPrimitiveBlender) {
221 Blend(keyContext, keyBuilder, gatherer,
222 /* addBlendToKey= */ [&] () -> void {
223 // TODO: Support runtime blenders for primitive blending in the precompile API.
224 // In the meantime, assume for now that we're using kSrcOver here.
225 AddToKey(keyContext, keyBuilder, gatherer,
227 },
228 /* addSrcToKey= */ [&]() -> void {
229 this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
230 },
231 /* addDstToKey= */ [&]() -> void {
232 keyBuilder->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
233 });
234 } else {
235 this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
236 }
237}
238
239void PaintOption::handlePaintAlpha(const KeyContext& keyContext,
240 PaintParamsKeyBuilder* keyBuilder,
241 PipelineDataGatherer* gatherer) const {
242
243 if (!fShader.first && !fHasPrimitiveBlender) {
244 // If there is no shader and no primitive blending the input to the colorFilter stage
245 // is just the premultiplied paint color.
246 SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, SK_PMColor4fWHITE);
247 return;
248 }
249
250 if (!fOpaquePaintColor) {
251 Blend(keyContext, keyBuilder, gatherer,
252 /* addBlendToKey= */ [&] () -> void {
253 AddKnownModeBlend(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
254 },
255 /* addSrcToKey= */ [&]() -> void {
256 this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
257 },
258 /* addDstToKey= */ [&]() -> void {
259 AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
260 });
261 } else {
262 this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
263 }
264}
265
266void PaintOption::handleColorFilter(const KeyContext& keyContext,
267 PaintParamsKeyBuilder* builder,
268 PipelineDataGatherer* gatherer) const {
269 if (fColorFilter.first) {
270 Compose(keyContext, builder, gatherer,
271 /* addInnerToKey= */ [&]() -> void {
272 this->handlePaintAlpha(keyContext, builder, gatherer);
273 },
274 /* addOuterToKey= */ [&]() -> void {
275 fColorFilter.first->priv().addToKey(keyContext, builder, gatherer,
276 fColorFilter.second);
277 });
278 } else {
279 this->handlePaintAlpha(keyContext, builder, gatherer);
280 }
281}
282
283// This should be kept in sync w/ SkPaintPriv::ShouldDither and PaintParams::should_dither
284bool PaintOption::shouldDither(SkColorType dstCT) const {
285 // The paint dither flag can veto.
286 if (!fDither) {
287 return false;
288 }
289
290 if (dstCT == kUnknown_SkColorType) {
291 return false;
292 }
293
294 // We always dither 565 or 4444 when requested.
295 if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
296 return true;
297 }
298
299 // Otherwise, dither is only needed for non-const paints.
300 return fShader.first && !fShader.first->isConstant(fShader.second);
301}
302
303void PaintOption::handleDithering(const KeyContext& keyContext,
304 PaintParamsKeyBuilder* builder,
305 PipelineDataGatherer* gatherer) const {
306
307#ifndef SK_IGNORE_GPU_DITHER
308 SkColorType ct = keyContext.dstColorInfo().colorType();
309 if (this->shouldDither(ct)) {
310 Compose(keyContext, builder, gatherer,
311 /* addInnerToKey= */ [&]() -> void {
312 this->handleColorFilter(keyContext, builder, gatherer);
313 },
314 /* addOuterToKey= */ [&]() -> void {
315 AddDitherBlock(keyContext, builder, gatherer, ct);
316 });
317 } else
318#endif
319 {
320 this->handleColorFilter(keyContext, builder, gatherer);
321 }
322}
323
324void PaintOption::handleDstRead(const KeyContext& keyContext,
325 PaintParamsKeyBuilder* builder,
326 PipelineDataGatherer* gatherer) const {
327 if (fDstReadReq != DstReadRequirement::kNone) {
328 Blend(keyContext, builder, gatherer,
329 /* addBlendToKey= */ [&] () -> void {
330 if (fFinalBlender.first) {
331 fFinalBlender.first->priv().addToKey(keyContext, builder, gatherer,
332 fFinalBlender.second);
333 } else {
334 AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kSrcOver);
335 }
336 },
337 /* addSrcToKey= */ [&]() -> void {
338 this->handleDithering(keyContext, builder, gatherer);
339 },
340 /* addDstToKey= */ [&]() -> void {
341 AddDstReadBlock(keyContext, builder, gatherer, fDstReadReq);
342 });
343 } else {
344 this->handleDithering(keyContext, builder, gatherer);
345 }
346}
347
348void PaintOption::toKey(const KeyContext& keyContext,
349 PaintParamsKeyBuilder* keyBuilder,
350 PipelineDataGatherer* gatherer) const {
351 this->handleDstRead(keyContext, keyBuilder, gatherer);
352
353 std::optional<SkBlendMode> finalBlendMode = this->finalBlender()
354 ? this->finalBlender()->asBlendMode()
356 if (fDstReadReq != DstReadRequirement::kNone) {
357 // In this case the blend will have been handled by shader-based blending with the dstRead.
358 finalBlendMode = SkBlendMode::kSrc;
359 }
360
361 if (fClipShader.first) {
362 ClipShaderBlock::BeginBlock(keyContext, keyBuilder, gatherer);
363 fClipShader.first->priv().addToKey(keyContext, keyBuilder, gatherer,
364 fClipShader.second);
365 keyBuilder->endBlock();
366 }
367
368 // Set the hardware blend mode.
369 SkASSERT(finalBlendMode);
370 BuiltInCodeSnippetID fixedFuncBlendModeID = static_cast<BuiltInCodeSnippetID>(
371 kFixedFunctionBlendModeIDOffset + static_cast<int>(*finalBlendMode));
372
373 keyBuilder->addBlock(fixedFuncBlendModeID);
374}
375
376void PaintOptions::createKey(const KeyContext& keyContext,
377 PaintParamsKeyBuilder* keyBuilder,
378 PipelineDataGatherer* gatherer,
379 int desiredCombination,
380 bool addPrimitiveBlender,
381 Coverage coverage) const {
382 SkDEBUGCODE(keyBuilder->checkReset();)
383 SkASSERT(desiredCombination < this->numCombinations());
384
385 const int numClipShaderCombos = this->numClipShaderCombinations();
386 const int numBlendModeCombos = this->numBlendModeCombinations();
387 const int numColorFilterCombinations = this->numColorFilterCombinations();
388 const int numMaskFilterCombinations = this->numMaskFilterCombinations();
389
390 const int desiredClipShaderCombination = desiredCombination % numClipShaderCombos;
391 int remainingCombinations = desiredCombination / numClipShaderCombos;
392
393 const int desiredBlendCombination = remainingCombinations % numBlendModeCombos;
394 remainingCombinations /= numBlendModeCombos;
395
396 const int desiredColorFilterCombination = remainingCombinations % numColorFilterCombinations;
397 remainingCombinations /= numColorFilterCombinations;
398
399 [[maybe_unused]] const int desiredMaskFilterCombination =
400 remainingCombinations % numMaskFilterCombinations;
401 remainingCombinations /= numMaskFilterCombinations;
402
403 const int desiredShaderCombination = remainingCombinations;
404 SkASSERT(desiredShaderCombination < this->numShaderCombinations());
405
406 // TODO: this probably needs to be passed in just like addPrimitiveBlender
407 const bool kOpaquePaintColor = true;
408
409 auto clipShader = PrecompileBase::SelectOption(SkSpan(fClipShaderOptions),
410 desiredClipShaderCombination);
411
412 std::pair<sk_sp<PrecompileBlender>, int> finalBlender;
413 if (desiredBlendCombination < fBlendModeOptions.size()) {
414 finalBlender = { PrecompileBlender::Mode(fBlendModeOptions[desiredBlendCombination]), 0 };
415 } else {
416 finalBlender = PrecompileBase::SelectOption(
417 SkSpan(fBlenderOptions),
418 desiredBlendCombination - fBlendModeOptions.size());
419 }
420 if (!finalBlender.first) {
421 finalBlender = { PrecompileBlender::Mode(SkBlendMode::kSrcOver), 0 };
422 }
423 DstReadRequirement dstReadReq = get_dst_read_req(keyContext.caps(), coverage,
424 finalBlender.first.get());
425
426 PaintOption option(kOpaquePaintColor,
427 finalBlender,
428 PrecompileBase::SelectOption(SkSpan(fShaderOptions),
429 desiredShaderCombination),
430 PrecompileBase::SelectOption(SkSpan(fColorFilterOptions),
431 desiredColorFilterCombination),
432 addPrimitiveBlender,
433 clipShader,
434 dstReadReq,
435 fDither);
436
437 option.toKey(keyContext, keyBuilder, gatherer);
438}
439
440namespace {
441
442void create_blur_pipelines(const KeyContext& keyContext,
443 PipelineDataGatherer* gatherer,
444 const PaintOptions::ProcessCombination& processCombination) {
445 PaintOptions blurPaintOptions, imagePaintOptions;
446
447 // For blurs we know we don't have alpha-only textures and don't need cubic filtering.
450
451 SkBlendMode blurBlendModes[] = { SkBlendMode::kSrc };
452 blurPaintOptions.setShaders({ PrecompileShadersPriv::Blur(imageShader) });
453 blurPaintOptions.setBlendModes(blurBlendModes);
454
455 SkBlendMode imageBlendModes[] = { SkBlendMode::kSrc, SkBlendMode::kDstOut };
456 imagePaintOptions.setShaders({ imageShader });
457 imagePaintOptions.setBlendModes(imageBlendModes);
458
459 blurPaintOptions.priv().buildCombinations(keyContext,
460 gatherer,
462 /* withPrimitiveBlender= */ false,
464 processCombination);
465 imagePaintOptions.priv().buildCombinations(keyContext,
466 gatherer,
468 /* withPrimitiveBlender= */ false,
470 processCombination);
471}
472
473} // anonymous namespace
474
475void PaintOptions::buildCombinations(
476 const KeyContext& keyContext,
477 PipelineDataGatherer* gatherer,
478 DrawTypeFlags drawTypes,
479 bool withPrimitiveBlender,
480 Coverage coverage,
481 const ProcessCombination& processCombination) const {
482
483 PaintParamsKeyBuilder builder(keyContext.dict());
484
485 if (fImageFilterOptions != PrecompileImageFilters::kNone) {
486 PaintOptions tmp = *this;
487
488 // When image filtering the original blend mode is taken over by the restore paint
489 tmp.setImageFilters(PrecompileImageFilters::kNone);
490 SkBlendMode newDrawBlendMode[] = { SkBlendMode::kSrcOver };
491 tmp.setBlendModes(newDrawBlendMode);
492
493 tmp.buildCombinations(keyContext, gatherer, drawTypes, withPrimitiveBlender, coverage,
494 processCombination);
495
496 if (fImageFilterOptions & PrecompileImageFilters::kBlur) {
497 create_blur_pipelines(keyContext, gatherer, processCombination);
498 }
499 } else {
500 int numCombinations = this->numCombinations();
501 for (int i = 0; i < numCombinations; ++i) {
502 // Since the precompilation path's uniforms aren't used and don't change the key,
503 // the exact layout doesn't matter
504 gatherer->resetWithNewLayout(Layout::kMetal);
505
506 this->createKey(keyContext, &builder, gatherer, i, withPrimitiveBlender, coverage);
507
508 // The 'findOrCreate' calls lockAsKey on builder and then destroys the returned
509 // PaintParamsKey. This serves to reset the builder.
510 UniquePaintParamsID paintID = keyContext.dict()->findOrCreate(&builder);
511
512 processCombination(paintID, drawTypes, withPrimitiveBlender, coverage);
513 }
514 }
515}
516
517} // namespace skgpu::graphite
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kSrcOver
r = s + (1-sa)*d
@ kDstOut
r = d * (1-sa)
@ kSrcIn
r = s * da
constexpr SkPMColor4f SK_PMColor4fWHITE
SkColorType
Definition SkColorType.h:19
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition SkColorType.h:23
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
static sk_sp< SkBlender > Mode(SkBlendMode mode)
int size() const
Definition SkTDArray.h:138
const Caps * caps() const
Definition KeyContext.h:57
PaintOption(bool opaquePaintColor, const std::pair< sk_sp< PrecompileBlender >, int > &finalBlender, const std::pair< sk_sp< PrecompileShader >, int > &shader, const std::pair< sk_sp< PrecompileColorFilter >, int > &colorFilter, bool hasPrimitiveBlender, const std::pair< sk_sp< PrecompileShader >, int > &clipShader, DstReadRequirement dstReadReq, bool dither)
const PrecompileBlender * finalBlender() const
void toKey(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *) const
std::function< void(UniquePaintParamsID id, DrawTypeFlags, bool withPrimitiveBlender, Coverage)> ProcessCombination
Definition Precompile.h:208
void setClipShaders(SkSpan< const sk_sp< PrecompileShader > > clipShaders)
void addBlock(BuiltInCodeSnippetID id)
virtual bool isALocalMatrixShader() const
Definition Precompile.h:86
static std::pair< sk_sp< T >, int > SelectOption(SkSpan< const sk_sp< T > > options, int desiredOption)
Definition Precompile.h:99
virtual std::optional< SkBlendMode > asBlendMode() const
Definition Precompile.h:156
static sk_sp< PrecompileBlender > Mode(SkBlendMode)
sk_sp< PrecompileColorFilter > makeComposed(sk_sp< PrecompileColorFilter > inner) const
sk_sp< PrecompileShader > makeWithColorFilter(sk_sp< PrecompileColorFilter >)
sk_sp< PrecompileShader > makeWithWorkingColorSpace(sk_sp< SkColorSpace >)
sk_sp< PrecompileShader > makeWithCTM()
sk_sp< PrecompileShader > makeWithLocalMatrix()
static bool b
struct MyStruct s
const myers::Point & get(const myers::Segment &)
sk_sp< PrecompileShader > Image(SkEnumBitMask< PrecompileImageShaderFlags >)
sk_sp< PrecompileShader > CTM(SkSpan< const sk_sp< PrecompileShader > > wrapped)
sk_sp< PrecompileShader > Blur(sk_sp< PrecompileShader > child)
SK_API sk_sp< PrecompileShader > ColorFilter(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
SK_API sk_sp< PrecompileShader > LocalMatrix(SkSpan< const sk_sp< PrecompileShader > > wrapped)
SK_API sk_sp< PrecompileShader > WorkingColorSpace(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< SkColorSpace > > colorSpaces)
static constexpr int kFixedFunctionBlendModeIDOffset
void AddToKey(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlender *blender)
void AddKnownModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
DstReadRequirement GetDstReadRequirement(const Caps *caps, std::optional< SkBlendMode > blendMode, Coverage coverage)
void Compose(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addInnerToKey, AddToKeyFn addOuterToKey)
void AddDitherBlock(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkColorType ct)
void AddDstReadBlock(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, DstReadRequirement dstReadReq)
DstReadRequirement get_dst_read_req(const Caps *caps, Coverage coverage, PrecompileBlender *blender)
void Blend(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addBlendToKey, AddToKeyFn addSrcToKey, AddToKeyFn addDstToKey)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const SkPMColor4f &)