Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / core / SkKeyHelpers.cpp
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 #include "src/core/SkKeyHelpers.h"
9
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"
18
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"
24 #endif
25
26 #define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID) \
27     SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)
28
29 constexpr SkPMColor4f kErrorColor = { 1, 0, 0, 1 };
30
31 namespace {
32
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,
37                            int blockDataSize) {
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) ==
42              fullBlockSize);
43 }
44 #endif
45
46 } // anonymous namespace
47
48 //--------------------------------------------------------------------------------------------------
49 namespace SolidColorShaderBlock {
50
51 namespace {
52
53 #ifdef SK_GRAPHITE_ENABLED
54 static const int kBlockDataSize = 0;
55
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);
61
62     gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kSolidColorShader));
63 }
64 #endif // SK_GRAPHITE_ENABLED
65
66 } // anonymous namespace
67
68 void AddToKey(const SkKeyContext& keyContext,
69               SkPaintParamsKeyBuilder* builder,
70               SkPipelineDataGatherer* gatherer,
71               const SkPMColor4f& premulColor) {
72
73 #ifdef SK_GRAPHITE_ENABLED
74     if (builder->backend() == SkBackend::kGraphite) {
75         auto dict = keyContext.dict();
76
77         builder->beginBlock(SkBuiltInCodeSnippetID::kSolidColorShader);
78         builder->endBlock();
79
80         validate_block_header(builder,
81                               SkBuiltInCodeSnippetID::kSolidColorShader,
82                               kBlockDataSize);
83
84         if (gatherer) {
85             add_solid_uniform_data(dict, premulColor, gatherer);
86         }
87         return;
88     }
89 #endif // SK_GRAPHITE_ENABLED
90
91     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
92         // TODO: add implementation of other backends
93     }
94
95 }
96
97 } // namespace SolidColorShaderBlock
98
99 //--------------------------------------------------------------------------------------------------
100 namespace GradientShaderBlocks {
101
102 namespace {
103
104 #ifdef SK_GRAPHITE_ENABLED
105 static const int kBlockDataSize = 0;
106
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;
113
114     SkM44 lmInverse;
115     bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse);  // TODO: handle failure up stack
116     if (!wasInverted) {
117         lmInverse.setIdentity();
118     }
119
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);
129
130     gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
131 };
132
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;
139
140     SkM44 lmInverse;
141     bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse);  // TODO: handle failure up stack
142     if (!wasInverted) {
143         lmInverse.setIdentity();
144     }
145
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));
152
153     gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
154 };
155
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;
162
163     SkM44 lmInverse;
164     bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse);  // TODO: handle failure up stack
165     if (!wasInverted) {
166         lmInverse.setIdentity();
167     }
168
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);
179
180     gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
181 };
182
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;
189
190     SkM44 lmInverse;
191     bool wasInverted = gradData.fLocalMatrix.invert(&lmInverse);  // TODO: handle failure up stack
192     if (!wasInverted) {
193         lmInverse.setIdentity();
194     }
195
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
205
206     gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
207 };
208
209 #endif // SK_GRAPHITE_ENABLED
210
211 } // anonymous namespace
212
213 GradientData::GradientData(SkShader::GradientType type,
214                            SkTileMode tm,
215                            int numStops)
216         : fType(type)
217         , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
218         , fRadii{0.0f, 0.0f}
219         , fBias(0.0f)
220         , fScale(0.0f)
221         , fTM(tm)
222         , fNumStops(numStops) {
223     sk_bzero(fColor4fs, sizeof(fColor4fs));
224     sk_bzero(fOffsets, sizeof(fOffsets));
225 }
226
227 GradientData::GradientData(SkShader::GradientType type,
228                            SkM44 localMatrix,
229                            SkPoint point0, SkPoint point1,
230                            float radius0, float radius1,
231                            float bias, float scale,
232                            SkTileMode tm,
233                            int numStops,
234                            SkColor4f* color4fs,
235                            float* offsets)
236         : fType(type)
237         , fLocalMatrix(localMatrix)
238         , fBias(bias)
239         , fScale(scale)
240         , fTM(tm)
241         , fNumStops(std::min(numStops, kMaxStops)) {
242     SkASSERT(fNumStops >= 1);
243
244     fPoints[0] = point0;
245     fPoints[1] = point1;
246     fRadii[0] = radius0;
247     fRadii[1] = radius1;
248     memcpy(fColor4fs, color4fs, fNumStops * sizeof(SkColor4f));
249     if (offsets) {
250         memcpy(fOffsets, offsets, fNumStops * sizeof(float));
251     } else {
252         for (int i = 0; i < fNumStops; ++i) {
253             fOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
254         }
255     }
256
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];
262     }
263 }
264
265 void AddToKey(const SkKeyContext& keyContext,
266               SkPaintParamsKeyBuilder *builder,
267               SkPipelineDataGatherer* gatherer,
268               const GradientData& gradData) {
269
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;
279                 if (gatherer) {
280                     add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
281                 }
282                 break;
283             case SkShader::kRadial_GradientType:
284                 codeSnippetID = gradData.fNumStops <= 4
285                                         ? SkBuiltInCodeSnippetID::kRadialGradientShader4
286                                         : SkBuiltInCodeSnippetID::kRadialGradientShader8;
287                 if (gatherer) {
288                     add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
289                 }
290                 break;
291             case SkShader::kSweep_GradientType:
292                 codeSnippetID = gradData.fNumStops <= 4
293                                         ? SkBuiltInCodeSnippetID::kSweepGradientShader4
294                                         : SkBuiltInCodeSnippetID::kSweepGradientShader8;
295                 if (gatherer) {
296                     add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
297                 }
298                 break;
299             case SkShader::GradientType::kConical_GradientType:
300                 codeSnippetID = gradData.fNumStops <= 4
301                                         ? SkBuiltInCodeSnippetID::kConicalGradientShader4
302                                         : SkBuiltInCodeSnippetID::kConicalGradientShader8;
303                 if (gatherer) {
304                     add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
305                 }
306                 break;
307             case SkShader::GradientType::kColor_GradientType:
308             case SkShader::GradientType::kNone_GradientType:
309             default:
310                 SkASSERT(0);
311                 break;
312         }
313
314         builder->beginBlock(codeSnippetID);
315         builder->endBlock();
316
317         validate_block_header(builder, codeSnippetID, kBlockDataSize);
318         return;
319     }
320 #endif // SK_GRAPHITE_ENABLED
321
322     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
323         // TODO: add implementation of other backends
324         SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
325     }
326 }
327
328 } // namespace GradientShaderBlocks
329
330 //--------------------------------------------------------------------------------------------------
331 namespace LocalMatrixShaderBlock {
332
333 namespace {
334
335 #ifdef SK_GRAPHITE_ENABLED
336
337 void add_localmatrixshader_uniform_data(const SkShaderCodeDictionary* dict,
338                                         const SkM44& localMatrix,
339                                         SkPipelineDataGatherer* gatherer) {
340     VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kLocalMatrixShader)
341
342     SkM44 lmInverse;
343     bool wasInverted = localMatrix.invert(&lmInverse);  // TODO: handle failure up stack
344     if (!wasInverted) {
345         lmInverse.setIdentity();
346     }
347
348     gatherer->write(lmInverse);
349
350     gatherer->addFlags(
351             dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kLocalMatrixShader));
352 }
353
354 #endif // SK_GRAPHITE_ENABLED
355
356 } // anonymous namespace
357
358 void AddToKey(const SkKeyContext& keyContext,
359               SkPaintParamsKeyBuilder* builder,
360               SkPipelineDataGatherer* gatherer,
361               const LMShaderData& lmShaderData) {
362
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.
369         if (gatherer) {
370             add_localmatrixshader_uniform_data(dict, lmShaderData.fLocalMatrix, gatherer);
371         }
372
373         builder->beginBlock(SkBuiltInCodeSnippetID::kLocalMatrixShader);
374
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;
381
382         builder->endBlock();
383
384         validate_block_header(builder,
385                               SkBuiltInCodeSnippetID::kLocalMatrixShader,
386                               childShaderSize);
387         return;
388     }
389 #endif // SK_GRAPHITE_ENABLED
390
391     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
392         // TODO: add implementation for other backends
393         SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
394     }
395 }
396
397 } // namespace LocalMatrixShaderBlock
398
399 //--------------------------------------------------------------------------------------------------
400 namespace ImageShaderBlock {
401
402 namespace {
403
404 #ifdef SK_GRAPHITE_ENABLED
405
406 void add_image_uniform_data(const SkShaderCodeDictionary* dict,
407                             const ImageData& imgData,
408                             SkPipelineDataGatherer* gatherer) {
409     VALIDATE_UNIFORMS(gatherer, dict, SkBuiltInCodeSnippetID::kImageShader)
410
411     SkMatrix lmInverse;
412     bool wasInverted = imgData.fLocalMatrix.invert(&lmInverse);  // TODO: handle failure up stack
413     if (!wasInverted) {
414         lmInverse.setIdentity();
415     }
416
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);
423
424     gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kImageShader));
425 }
426
427 #endif // SK_GRAPHITE_ENABLED
428
429 } // anonymous namespace
430
431 ImageData::ImageData(const SkSamplingOptions& sampling,
432                      SkTileMode tileModeX,
433                      SkTileMode tileModeY,
434                      SkRect subset,
435                      const SkMatrix& localMatrix)
436     : fSampling(sampling)
437     , fTileModes{tileModeX, tileModeY}
438     , fSubset(subset)
439     , fLocalMatrix(localMatrix) {
440 }
441
442 void AddToKey(const SkKeyContext& keyContext,
443               SkPaintParamsKeyBuilder* builder,
444               SkPipelineDataGatherer* gatherer,
445               const ImageData& imgData) {
446
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);
456             return;
457         }
458
459         auto dict = keyContext.dict();
460         builder->beginBlock(SkBuiltInCodeSnippetID::kImageShader);
461         builder->endBlock();
462
463         if (gatherer) {
464             gatherer->add(imgData.fSampling,
465                           imgData.fTileModes,
466                           imgData.fTextureProxy);
467
468             add_image_uniform_data(dict, imgData, gatherer);
469         }
470
471         return;
472     }
473 #endif // SK_GRAPHITE_ENABLED
474
475     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
476         // TODO: add implementation for other backends
477         SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
478     }
479 }
480
481 } // namespace ImageShaderBlock
482
483 //--------------------------------------------------------------------------------------------------
484 namespace BlendShaderBlock {
485
486 namespace {
487
488 #ifdef SK_GRAPHITE_ENABLED
489
490 void add_blendshader_uniform_data(const SkShaderCodeDictionary* dict,
491                                   SkBlendMode bm,
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
498
499     gatherer->addFlags(dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kBlendShader));
500 }
501
502 #endif // SK_GRAPHITE_ENABLED
503
504 } // anonymous namespace
505
506 void AddToKey(const SkKeyContext& keyContext,
507               SkPaintParamsKeyBuilder *builder,
508               SkPipelineDataGatherer* gatherer,
509               const BlendShaderData& blendData) {
510
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.
517         if (gatherer) {
518             add_blendshader_uniform_data(dict, blendData.fBM, gatherer);
519         }
520
521         builder->beginBlock(SkBuiltInCodeSnippetID::kBlendShader);
522
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;
529
530         start = builder->sizeInBytes();
531         as_SB(blendData.fSrc)->addToKey(keyContext, builder, gatherer);
532         int secondShaderSize = builder->sizeInBytes() - start;
533
534         builder->endBlock();
535
536         int expectedBlockSize = firstShaderSize + secondShaderSize;
537         validate_block_header(builder,
538                               SkBuiltInCodeSnippetID::kBlendShader,
539                               expectedBlockSize);
540         return;
541     }
542 #endif // SK_GRAPHITE_ENABLED
543
544     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
545         // TODO: add implementation for other backends
546         SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
547     }
548 }
549
550 } // namespace BlendShaderBlock
551
552 //--------------------------------------------------------------------------------------------------
553 #ifdef SK_GRAPHITE_ENABLED
554 namespace {
555
556 constexpr SkPipelineDataGatherer::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
557                                                                   skgpu::BlendCoeff dstCoeff) {
558     return { skgpu::BlendEquation::kAdd,
559              srcCoeff,
560              dstCoeff,
561              SK_PMColor4fTRANSPARENT,
562              skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
563 }
564
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)
583 };
584
585 const SkPipelineDataGatherer::BlendInfo& get_blend_info(SkBlendMode bm) {
586     if (bm <= SkBlendMode::kLastCoeffMode) {
587         return gBlendTable[(int) bm];
588     }
589
590     return gBlendTable[(int) SkBlendMode::kSrc];
591 }
592
593 } // anonymous namespace
594 #endif // SK_GRAPHITE_ENABLED
595
596 namespace BlendModeBlock {
597
598 #ifdef SK_GRAPHITE_ENABLED
599 static const int kFixedFunctionBlockDataSize = 0;
600 static const int kShaderBasedBlockDataSize = 0;
601
602 namespace {
603
604 void add_shaderbasedblender_uniform_data(const SkShaderCodeDictionary* dict,
605                                          SkBlendMode bm,
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
612
613     gatherer->addFlags(
614             dict->getSnippetRequirementFlags(SkBuiltInCodeSnippetID::kShaderBasedBlender));
615 }
616
617 } // anonymous namespace
618
619 #endif // SK_GRAPHITE_ENABLED
620
621 void AddToKey(const SkKeyContext& keyContext,
622               SkPaintParamsKeyBuilder *builder,
623               SkPipelineDataGatherer* gatherer,
624               SkBlendMode bm) {
625
626 #ifdef SK_GRAPHITE_ENABLED
627     if (builder->backend() == SkBackend::kGraphite) {
628         auto dict = keyContext.dict();
629
630         if (bm <= SkBlendMode::kLastCoeffMode) {
631             builder->beginBlock(SkBuiltInCodeSnippetID::kFixedFunctionBlender);
632             builder->endBlock();
633
634             validate_block_header(builder,
635                                   SkBuiltInCodeSnippetID::kFixedFunctionBlender,
636                                   kFixedFunctionBlockDataSize);
637
638             if (gatherer) {
639                 gatherer->setBlendInfo(get_blend_info(bm));
640             }
641         } else {
642             builder->beginBlock(SkBuiltInCodeSnippetID::kShaderBasedBlender);
643             builder->endBlock();
644
645             validate_block_header(builder,
646                                   SkBuiltInCodeSnippetID::kShaderBasedBlender,
647                                   kShaderBasedBlockDataSize);
648
649             if (gatherer) {
650                 add_shaderbasedblender_uniform_data(dict, bm, gatherer);
651                 // TODO: set up the correct blend info
652                 gatherer->setBlendInfo(SkPipelineDataGatherer::BlendInfo());
653             }
654         }
655         return;
656     }
657 #endif// SK_GRAPHITE_ENABLED
658
659     if (builder->backend() == SkBackend::kSkVM || builder->backend() == SkBackend::kGanesh) {
660         // TODO: add implementation for other backends
661         SolidColorShaderBlock::AddToKey(keyContext, builder, gatherer, kErrorColor);
662     }
663 }
664
665 } // namespace BlendModeBlock
666
667 //--------------------------------------------------------------------------------------------------
668 // TODO: we need to feed the number of stops in the gradients into this method from the
669 // combination code
670 SkUniquePaintParamsID CreateKey(const SkKeyContext& keyContext,
671                                 SkPaintParamsKeyBuilder* builder,
672                                 SkShaderType s,
673                                 SkTileMode tm,
674                                 SkBlendMode bm) {
675     SkDEBUGCODE(builder->checkReset());
676
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.
680     switch (s) {
681         case SkShaderType::kSolidColor:
682             SolidColorShaderBlock::AddToKey(keyContext, builder, nullptr,
683                                             /* unused */ kErrorColor);
684             break;
685         case SkShaderType::kLinearGradient:
686             GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
687                                            // only the type and numStops are used
688                                            { SkShader::kLinear_GradientType, tm, 0 });
689             break;
690         case SkShaderType::kRadialGradient:
691             GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
692                                            // only the type and numStops are used
693                                            { SkShader::kRadial_GradientType, tm, 0 });
694             break;
695         case SkShaderType::kSweepGradient:
696             GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
697                                            // only the type and numStops are used
698                                            { SkShader::kSweep_GradientType, tm, 0 });
699             break;
700         case SkShaderType::kConicalGradient:
701             GradientShaderBlocks::AddToKey(keyContext, builder, nullptr,
702                                            // only the type and numStops are used
703                                            { SkShader::kConical_GradientType, tm, 0 });
704             break;
705         case SkShaderType::kLocalMatrix:
706             LocalMatrixShaderBlock::AddToKey(keyContext, builder, nullptr,
707                                              // only the proxy shader is used
708                                              { nullptr, SkMatrix::I() });
709             break;
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() });
716             break;
717         case SkShaderType::kBlendShader:
718             BlendShaderBlock::AddToKey(keyContext, builder, nullptr,
719                                        // both the dst and src are used
720                                        { nullptr, nullptr, SkBlendMode::kSrc });
721             break;
722     }
723
724     // TODO: the blendInfo should be filled in by BlendModeBlock::AddToKey
725 #ifdef SK_GRAPHITE_ENABLED
726     SkPipelineDataGatherer::BlendInfo blendInfo = get_blend_info(bm);
727 #endif
728
729     BlendModeBlock::AddToKey(keyContext, builder, /* pipelineData*/ nullptr, bm); // 'bm' is used
730     SkPaintParamsKey key = builder->lockAsKey();
731
732     auto dict = keyContext.dict();
733
734     auto entry = dict->findOrCreate(
735             key
736 #ifdef SK_GRAPHITE_ENABLED
737             , blendInfo
738 #endif
739             );
740
741     return  entry->uniqueID();
742 }