2 * Copyright 2022 Google LLC
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/core/SkKeyHelpers.h"
10 #include "include/core/SkCombinationBuilder.h"
11 #include "src/core/SkDebugUtils.h"
12 #include "src/core/SkKeyContext.h"
13 #include "src/core/SkPaintParamsKey.h"
14 #include "src/core/SkPipelineData.h"
15 #include "src/core/SkShaderCodeDictionary.h"
16 #include "src/core/SkUniform.h"
17 #include "src/shaders/SkShaderBase.h"
19 #ifdef SK_GRAPHITE_ENABLED
20 #include "src/gpu/Blend.h"
21 #include "src/gpu/graphite/Texture.h"
22 #include "src/gpu/graphite/TextureProxy.h"
23 #include "src/gpu/graphite/UniformManager.h"
26 #define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID) \
27 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)
29 constexpr SkPMColor4f kErrorColor = { 1, 0, 0, 1 };
33 #ifdef SK_GRAPHITE_ENABLED
34 // This can be used to catch errors in blocks that have a fixed, known block data size
35 void validate_block_header(const SkPaintParamsKeyBuilder* builder,
36 SkBuiltInCodeSnippetID codeSnippetID,
38 SkDEBUGCODE(int fullBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes + blockDataSize;)
39 SkDEBUGCODE(int headerOffset = builder->sizeInBytes() - fullBlockSize;)
40 SkASSERT(builder->byte(headerOffset) == static_cast<int>(codeSnippetID));
41 SkASSERT(builder->byte(headerOffset+SkPaintParamsKey::kBlockSizeOffsetInBytes) ==
46 } // anonymous namespace
48 //--------------------------------------------------------------------------------------------------
49 namespace SolidColorShaderBlock {
53 #ifdef SK_GRAPHITE_ENABLED
54 static const int kBlockDataSize = 0;
56 void add_solid_uniform_data(const SkShaderCodeDictionary* dict,
57 const SkPMColor4f& premulColor,
58 SkPipelineDataGatherer* gatherer) {
59 VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kSolidColorShader)
60 gatherer->write(premulColor);
62 gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kSolidColorShader));
64 #endif // SK_GRAPHITE_ENABLED
66 } // anonymous namespace
68 void AddToKey(const SkKeyContext& keyContext,
69 SkPaintParamsKeyBuilder* builder,
70 SkPipelineDataGatherer* gatherer,
71 const SkPMColor4f& premulColor) {
73 #ifdef SK_GRAPHITE_ENABLED
74 if (builder->backend() == SkBackend::kGraphite) {
75 auto dict = keyContext.dict();
77 builder->beginBlock(SkBuiltInCodeSnippetID::kSolidColorShader);
80 validate_block_header(builder,
81 SkBuiltInCodeSnippetID::kSolidColorShader,
85 add_solid_uniform_data(dict, premulColor, gatherer);
89 #endif // SK_GRAPHITE_ENABLED
91 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
92 // TODO: add implementation of other backends
97 } // namespace SolidColorShaderBlock
99 //--------------------------------------------------------------------------------------------------
100 namespace GradientShaderBlocks {
104 #ifdef SK_GRAPHITE_ENABLED
105 static const int kBlockDataSize = 0;
107 void add_linear_gradient_uniform_data(const SkShaderCodeDictionary* dict,
108 SkBuiltInCodeSnippetID codeSnippetID,
109 const GradientData& gradData,
110 SkPipelineDataGatherer* gatherer) {
111 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
112 int stops = codeSnippetID == SkBuiltInCodeSnippetID::kLinearGradientShader4 ? 4 : 8;
115 bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse); // TODO: handle failure up stack
117 lmInverse.setIdentity();
120 gatherer->write(lmInverse);
121 gatherer->write(gradData.fColor4fs, stops);
122 gatherer->write(gradData.fOffsets, stops);
123 gatherer->write(gradData.fPoints[0]);
124 gatherer->write(gradData.fPoints[1]);
125 gatherer->write(static_cast<int>(gradData.fTM));
126 gatherer->write(0.0f); // padding
127 gatherer->write(0.0f);
128 gatherer->write(0.0f);
130 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
133 void add_radial_gradient_uniform_data(const SkShaderCodeDictionary* dict,
134 SkBuiltInCodeSnippetID codeSnippetID,
135 const GradientData& gradData,
136 SkPipelineDataGatherer* gatherer) {
137 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
138 int stops = codeSnippetID == SkBuiltInCodeSnippetID::kRadialGradientShader4 ? 4 : 8;
141 bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse); // TODO: handle failure up stack
143 lmInverse.setIdentity();
146 gatherer->write(lmInverse);
147 gatherer->write(gradData.fColor4fs, stops);
148 gatherer->write(gradData.fOffsets, stops);
149 gatherer->write(gradData.fPoints[0]);
150 gatherer->write(gradData.fRadii[0]);
151 gatherer->write(static_cast<int>(gradData.fTM));
153 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
156 void add_sweep_gradient_uniform_data(const SkShaderCodeDictionary* dict,
157 SkBuiltInCodeSnippetID codeSnippetID,
158 const GradientData& gradData,
159 SkPipelineDataGatherer* gatherer) {
160 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
161 int stops = codeSnippetID == SkBuiltInCodeSnippetID::kSweepGradientShader4 ? 4 : 8;
164 bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse); // TODO: handle failure up stack
166 lmInverse.setIdentity();
169 gatherer->write(lmInverse);
170 gatherer->write(gradData.fColor4fs, stops);
171 gatherer->write(gradData.fOffsets, stops);
172 gatherer->write(gradData.fPoints[0]);
173 gatherer->write(gradData.fBias);
174 gatherer->write(gradData.fScale);
175 gatherer->write(static_cast<int>(gradData.fTM));
176 gatherer->write(0.0f); // padding
177 gatherer->write(0.0f);
178 gatherer->write(0.0f);
180 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
183 void add_conical_gradient_uniform_data(const SkShaderCodeDictionary* dict,
184 SkBuiltInCodeSnippetID codeSnippetID,
185 const GradientData& gradData,
186 SkPipelineDataGatherer* gatherer) {
187 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
188 int stops = codeSnippetID == SkBuiltInCodeSnippetID::kConicalGradientShader4 ? 4 : 8;
191 bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse); // TODO: handle failure up stack
193 lmInverse.setIdentity();
196 gatherer->write(lmInverse);
197 gatherer->write(gradData.fColor4fs, stops);
198 gatherer->write(gradData.fOffsets, stops);
199 gatherer->write(gradData.fPoints[0]);
200 gatherer->write(gradData.fPoints[1]);
201 gatherer->write(gradData.fRadii[0]);
202 gatherer->write(gradData.fRadii[1]);
203 gatherer->write(static_cast<int>(gradData.fTM));
204 gatherer->write(0.0f); // padding
206 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
209 #endif // SK_GRAPHITE_ENABLED
211 } // anonymous namespace
213 GradientData::GradientData(SkShader::GradientType type,
217 , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
222 , fNumStops(numStops) {
223 sk_bzero(fColor4fs, sizeof(fColor4fs));
224 sk_bzero(fOffsets, sizeof(fOffsets));
227 GradientData::GradientData(SkShader::GradientType type,
229 SkPoint point0, SkPoint point1,
230 float radius0, float radius1,
231 float bias, float scale,
237 , fLocalMatrix(localMatrix)
241 , fNumStops(std::min(numStops, kMaxStops)) {
242 SkASSERT(fNumStops >= 1);
248 memcpy(fColor4fs, color4fs, fNumStops * sizeof(SkColor4f));
250 memcpy(fOffsets, offsets, fNumStops * sizeof(float));
252 for (int i = 0; i < fNumStops; ++i) {
253 fOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
257 // Extend the colors and offset, if necessary, to fill out the arrays
258 // TODO: this should be done later when the actual code snippet has been selected!!
259 for (int i = fNumStops ; i < kMaxStops; ++i) {
260 fColor4fs[i] = fColor4fs[fNumStops-1];
261 fOffsets[i] = fOffsets[fNumStops-1];
265 void AddToKey(const SkKeyContext& keyContext,
266 SkPaintParamsKeyBuilder *builder,
267 SkPipelineDataGatherer* gatherer,
268 const GradientData& gradData) {
270 #ifdef SK_GRAPHITE_ENABLED
271 if (builder->backend() == SkBackend::kGraphite) {
272 auto dict = keyContext.dict();
273 SkBuiltInCodeSnippetID codeSnippetID = SkBuiltInCodeSnippetID::kSolidColorShader;
274 switch (gradData.fType) {
275 case SkShader::kLinear_GradientType:
276 codeSnippetID = gradData.fNumStops <= 4
277 ? SkBuiltInCodeSnippetID::kLinearGradientShader4
278 : SkBuiltInCodeSnippetID::kLinearGradientShader8;
280 add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
283 case SkShader::kRadial_GradientType:
284 codeSnippetID = gradData.fNumStops <= 4
285 ? SkBuiltInCodeSnippetID::kRadialGradientShader4
286 : SkBuiltInCodeSnippetID::kRadialGradientShader8;
288 add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
291 case SkShader::kSweep_GradientType:
292 codeSnippetID = gradData.fNumStops <= 4
293 ? SkBuiltInCodeSnippetID::kSweepGradientShader4
294 : SkBuiltInCodeSnippetID::kSweepGradientShader8;
296 add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
299 case SkShader::GradientType::kConical_GradientType:
300 codeSnippetID = gradData.fNumStops <= 4
301 ? SkBuiltInCodeSnippetID::kConicalGradientShader4
302 : SkBuiltInCodeSnippetID::kConicalGradientShader8;
304 add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
307 case SkShader::GradientType::kColor_GradientType:
308 case SkShader::GradientType::kNone_GradientType:
314 builder->beginBlock(codeSnippetID);
317 validate_block_header(builder, codeSnippetID, kBlockDataSize);
320 #endif // SK_GRAPHITE_ENABLED
322 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
323 // TODO: add implementation of other backends
324 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
328 } // namespace GradientShaderBlocks
330 //--------------------------------------------------------------------------------------------------
331 namespace LocalMatrixShaderBlock {
335 #ifdef SK_GRAPHITE_ENABLED
337 void add_localmatrixshader_uniform_data(const SkShaderCodeDictionary* dict,
338 const SkM44& localMatrix,
339 SkPipelineDataGatherer* gatherer) {
340 VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kLocalMatrixShader)
343 bool wasInverted = localMatrix.invert(&lmInverse); // TODO: handle failure up stack
345 lmInverse.setIdentity();
348 gatherer->write(lmInverse);
351 dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kLocalMatrixShader));
354 #endif // SK_GRAPHITE_ENABLED
356 } // anonymous namespace
358 void AddToKey(const SkKeyContext& keyContext,
359 SkPaintParamsKeyBuilder* builder,
360 SkPipelineDataGatherer* gatherer,
361 const LMShaderData& lmShaderData) {
363 #ifdef SK_GRAPHITE_ENABLED
364 if (builder->backend() == SkBackend::kGraphite) {
365 auto dict = keyContext.dict();
366 // When extracted into SkShaderInfo::SnippetEntries the children will appear after their
367 // parent. Thus, the parent's uniform data must appear in the uniform block before the
368 // uniform data of the children.
370 add_localmatrixshader_uniform_data(dict, lmShaderData.fLocalMatrix, gatherer);
373 builder->beginBlock(SkBuiltInCodeSnippetID::kLocalMatrixShader);
375 // Child blocks always go right after the parent block's header
376 // TODO: add startChild/endChild entry points to SkPaintParamsKeyBuilder. They could be
377 // used to compute and store the number of children w/in a block's header.
378 int start = builder->sizeInBytes();
379 as_SB(lmShaderData.fProxyShader)->addToKey(keyContext, builder, gatherer);
380 int childShaderSize = builder->sizeInBytes() - start;
384 validate_block_header(builder,
385 SkBuiltInCodeSnippetID::kLocalMatrixShader,
389 #endif // SK_GRAPHITE_ENABLED
391 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
392 // TODO: add implementation for other backends
393 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
397 } // namespace LocalMatrixShaderBlock
399 //--------------------------------------------------------------------------------------------------
400 namespace ImageShaderBlock {
404 #ifdef SK_GRAPHITE_ENABLED
406 void add_image_uniform_data(const SkShaderCodeDictionary* dict,
407 const ImageData& imgData,
408 SkPipelineDataGatherer* gatherer) {
409 VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kImageShader)
412 bool wasInverted = imgData.fLocalMatrix.invert(&lmInverse); // TODO: handle failure up stack
414 lmInverse.setIdentity();
417 gatherer->write(SkM44(lmInverse));
418 gatherer->write(imgData.fSubset);
419 gatherer->write(static_cast<int>(imgData.fTileModes[0]));
420 gatherer->write(static_cast<int>(imgData.fTileModes[1]));
421 gatherer->write(imgData.fTextureProxy->dimensions().fWidth);
422 gatherer->write(imgData.fTextureProxy->dimensions().fHeight);
424 gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kImageShader));
427 #endif // SK_GRAPHITE_ENABLED
429 } // anonymous namespace
431 ImageData::ImageData(const SkSamplingOptions& sampling,
432 SkTileMode tileModeX,
433 SkTileMode tileModeY,
435 const SkMatrix& localMatrix)
436 : fSampling(sampling)
437 , fTileModes{tileModeX, tileModeY}
439 , fLocalMatrix(localMatrix) {
442 void AddToKey(const SkKeyContext& keyContext,
443 SkPaintParamsKeyBuilder* builder,
444 SkPipelineDataGatherer* gatherer,
445 const ImageData& imgData) {
447 #ifdef SK_GRAPHITE_ENABLED
448 if (builder->backend() == SkBackend::kGraphite) {
449 // TODO: allow through lazy proxies
450 if (gatherer && !imgData.fTextureProxy) {
451 // We're dropping the ImageShader here. This could be an instance of trying to draw
452 // a raster-backed image w/ a Graphite-backed canvas.
453 // TODO: At some point the pre-compile path should also be creating a texture
454 // proxy (i.e., we can remove the 'pipelineData' in the above test).
455 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
459 auto dict = keyContext.dict();
460 builder->beginBlock(SkBuiltInCodeSnippetID::kImageShader);
464 gatherer->add(imgData.fSampling,
466 imgData.fTextureProxy);
468 add_image_uniform_data(dict, imgData, gatherer);
473 #endif // SK_GRAPHITE_ENABLED
475 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
476 // TODO: add implementation for other backends
477 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
481 } // namespace ImageShaderBlock
483 //--------------------------------------------------------------------------------------------------
484 namespace BlendShaderBlock {
488 #ifdef SK_GRAPHITE_ENABLED
490 void add_blendshader_uniform_data(const SkShaderCodeDictionary* dict,
492 SkPipelineDataGatherer* gatherer) {
493 VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kBlendShader)
494 gatherer->write(SkTo<int>(bm));
495 gatherer->write(0); // padding - remove
496 gatherer->write(0); // padding - remove
497 gatherer->write(0); // padding - remove
499 gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kBlendShader));
502 #endif // SK_GRAPHITE_ENABLED
504 } // anonymous namespace
506 void AddToKey(const SkKeyContext& keyContext,
507 SkPaintParamsKeyBuilder *builder,
508 SkPipelineDataGatherer* gatherer,
509 const BlendShaderData& blendData) {
511 #ifdef SK_GRAPHITE_ENABLED
512 if (builder->backend() == SkBackend::kGraphite) {
513 auto dict = keyContext.dict();
514 // When extracted into SkShaderInfo::SnippetEntries the children will appear after their
515 // parent. Thus, the parent's uniform data must appear in the uniform block before the
516 // uniform data of the children.
518 add_blendshader_uniform_data(dict, blendData.fBM, gatherer);
521 builder->beginBlock(SkBuiltInCodeSnippetID::kBlendShader);
523 // Child blocks always go right after the parent block's header
524 // TODO: add startChild/endChild entry points to SkPaintParamsKeyBuilder. They could be
525 // used to compute and store the number of children w/in a block's header.
526 int start = builder->sizeInBytes();
527 as_SB(blendData.fDst)->addToKey(keyContext, builder, gatherer);
528 int firstShaderSize = builder->sizeInBytes() - start;
530 start = builder->sizeInBytes();
531 as_SB(blendData.fSrc)->addToKey(keyContext, builder, gatherer);
532 int secondShaderSize = builder->sizeInBytes() - start;
536 int expectedBlockSize = firstShaderSize + secondShaderSize;
537 validate_block_header(builder,
538 SkBuiltInCodeSnippetID::kBlendShader,
542 #endif // SK_GRAPHITE_ENABLED
544 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
545 // TODO: add implementation for other backends
546 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
550 } // namespace BlendShaderBlock
552 //--------------------------------------------------------------------------------------------------
553 #ifdef SK_GRAPHITE_ENABLED
556 constexpr SkPipelineDataGatherer::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
557 skgpu::BlendCoeff dstCoeff) {
558 return { skgpu::BlendEquation::kAdd,
561 SK_PMColor4fTRANSPARENT,
562 skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
565 static constexpr int kNumCoeffModes = (int)SkBlendMode::kLastCoeffMode + 1;
566 /*>> No coverage, input color unknown <<*/
567 static constexpr SkPipelineDataGatherer::BlendInfo gBlendTable[kNumCoeffModes] = {
568 /* clear */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
569 /* src */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kZero),
570 /* dst */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
571 /* src-over */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
572 /* dst-over */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
573 /* src-in */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
574 /* dst-in */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
575 /* src-out */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
576 /* dst-out */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
577 /* src-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
578 /* dst-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kSA),
579 /* xor */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
580 /* plus */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
581 /* modulate */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
582 /* screen */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC)
585 const SkPipelineDataGatherer::BlendInfo& get_blend_info(SkBlendMode bm) {
586 if (bm <= SkBlendMode::kLastCoeffMode) {
587 return gBlendTable[(int) bm];
590 return gBlendTable[(int) SkBlendMode::kSrc];
593 } // anonymous namespace
594 #endif // SK_GRAPHITE_ENABLED
596 namespace BlendModeBlock {
598 #ifdef SK_GRAPHITE_ENABLED
599 static const int kFixedFunctionBlockDataSize = 0;
600 static const int kShaderBasedBlockDataSize = 0;
604 void add_shaderbasedblender_uniform_data(const SkShaderCodeDictionary* dict,
606 SkPipelineDataGatherer* gatherer) {
607 VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kShaderBasedBlender)
608 gatherer->write(SkTo<int>(bm));
609 gatherer->write(0); // padding - remove
610 gatherer->write(0); // padding - remove
611 gatherer->write(0); // padding - remove
614 dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kShaderBasedBlender));
617 } // anonymous namespace
619 #endif // SK_GRAPHITE_ENABLED
621 void AddToKey(const SkKeyContext& keyContext,
622 SkPaintParamsKeyBuilder *builder,
623 SkPipelineDataGatherer* gatherer,
626 #ifdef SK_GRAPHITE_ENABLED
627 if (builder->backend() == SkBackend::kGraphite) {
628 auto dict = keyContext.dict();
630 if (bm <= SkBlendMode::kLastCoeffMode) {
631 builder->beginBlock(SkBuiltInCodeSnippetID::kFixedFunctionBlender);
634 validate_block_header(builder,
635 SkBuiltInCodeSnippetID::kFixedFunctionBlender,
636 kFixedFunctionBlockDataSize);
639 gatherer->setBlendInfo(get_blend_info(bm));
642 builder->beginBlock(SkBuiltInCodeSnippetID::kShaderBasedBlender);
645 validate_block_header(builder,
646 SkBuiltInCodeSnippetID::kShaderBasedBlender,
647 kShaderBasedBlockDataSize);
650 add_shaderbasedblender_uniform_data(dict, bm, gatherer);
651 // TODO: set up the correct blend info
652 gatherer->setBlendInfo(SkPipelineDataGatherer::BlendInfo());
657 #endif// SK_GRAPHITE_ENABLED
659 if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
660 // TODO: add implementation for other backends
661 SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
665 } // namespace BlendModeBlock
667 //--------------------------------------------------------------------------------------------------
668 // TODO: we need to feed the number of stops in the gradients into this method from the
670 SkUniquePaintParamsID CreateKey(const SkKeyContext& keyContext,
671 SkPaintParamsKeyBuilder* builder,
675 SkDEBUGCODE(builder->checkReset());
677 // TODO: split out the portion of the block data that is always required from the portion
678 // that is only required to gather uniforms. Right now we're passing in a lot of unused
679 // data and it is unclear what is actually used.
681 case SkShaderType::kSolidColor:
682 SolidColorShaderBlock::AddToKey(keyContext, builder, nullptr,
683 /* unused */ kErrorColor);
685 case SkShaderType::kLinearGradient:
686 GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
687 // only the type and numStops are used
688 { SkShader::kLinear_GradientType, tm, 0 });
690 case SkShaderType::kRadialGradient:
691 GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
692 // only the type and numStops are used
693 { SkShader::kRadial_GradientType, tm, 0 });
695 case SkShaderType::kSweepGradient:
696 GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
697 // only the type and numStops are used
698 { SkShader::kSweep_GradientType, tm, 0 });
700 case SkShaderType::kConicalGradient:
701 GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
702 // only the type and numStops are used
703 { SkShader::kConical_GradientType, tm, 0 });
705 case SkShaderType::kLocalMatrix:
706 LocalMatrixShaderBlock::AddToKey(keyContext, builder, nullptr,
707 // only the proxy shader is used
708 { nullptr, SkMatrix::I() });
710 case SkShaderType::kImage:
711 ImageShaderBlock::AddToKey(keyContext, builder, nullptr,
712 // none of the ImageData is used
713 { SkSamplingOptions(),
714 SkTileMode::kClamp, SkTileMode::kClamp,
715 SkRect::MakeEmpty(), SkMatrix::I() });
717 case SkShaderType::kBlendShader:
718 BlendShaderBlock::AddToKey(keyContext, builder, nullptr,
719 // both the dst and src are used
720 { nullptr, nullptr, SkBlendMode::kSrc });
724 // TODO: the blendInfo should be filled in by BlendModeBlock::AddToKey
725 #ifdef SK_GRAPHITE_ENABLED
726 SkPipelineDataGatherer::BlendInfo blendInfo = get_blend_info(bm);
729 BlendModeBlock::AddToKey(keyContext, builder, /* pipelineData*/ nullptr, bm); // 'bm' is used
730 SkPaintParamsKey key = builder->lockAsKey();
732 auto dict = keyContext.dict();
734 auto entry = dict->findOrCreate(
736 #ifdef SK_GRAPHITE_ENABLED
741 return entry->uniqueID();