• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkDebugUtils.h"
11 #include "src/core/SkPaintParamsKey.h"
12 #include "src/core/SkShaderCodeDictionary.h"
13 #include "src/core/SkUniform.h"
14 #include "src/core/SkUniformData.h"
15 #include "src/shaders/SkShaderBase.h"
16 
17 #ifdef SK_GRAPHITE_ENABLED
18 #include "experimental/graphite/src/UniformManager.h"
19 #endif
20 
21 namespace {
22 
23 #if defined(SK_DEBUG) && defined(SK_GRAPHITE_ENABLED)
read_code_snippet_id(const SkPaintParamsKey & key,int headerOffset)24 SkBuiltInCodeSnippetID read_code_snippet_id(const SkPaintParamsKey& key, int headerOffset) {
25     uint8_t byte = key.byte(headerOffset);
26 
27     SkASSERT(byte <= static_cast<int>(SkBuiltInCodeSnippetID::kLast));
28 
29     return static_cast<SkBuiltInCodeSnippetID>(byte);
30 }
31 
validate_block_header_key(const SkPaintParamsKey & key,int headerOffset,SkBuiltInCodeSnippetID codeSnippetID,int blockDataSize)32 void validate_block_header_key(const SkPaintParamsKey& key,
33                                int headerOffset,
34                                SkBuiltInCodeSnippetID codeSnippetID,
35                                int blockDataSize) {
36     SkASSERT(key.byte(headerOffset) == static_cast<int>(codeSnippetID));
37     SkASSERT(key.byte(headerOffset+SkPaintParamsKey::kBlockSizeOffsetInBytes) ==
38              SkPaintParamsKey::kBlockHeaderSizeInBytes + blockDataSize);
39 }
40 #endif
41 
42 // This can be used to catch errors in blocks that have a fixed, known block data size
validate_block_header(const SkPaintParamsKeyBuilder * builder,SkBuiltInCodeSnippetID codeSnippetID,int blockDataSize)43 void validate_block_header(const SkPaintParamsKeyBuilder* builder,
44                            SkBuiltInCodeSnippetID codeSnippetID,
45                            int blockDataSize) {
46     SkDEBUGCODE(int fullBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes + blockDataSize;)
47     SkDEBUGCODE(int headerOffset = builder->sizeInBytes() - fullBlockSize;)
48     SkASSERT(builder->byte(headerOffset) == static_cast<int>(codeSnippetID));
49     SkASSERT(builder->byte(headerOffset+SkPaintParamsKey::kBlockSizeOffsetInBytes) ==
50              fullBlockSize);
51 }
52 
53 #ifdef SK_GRAPHITE_ENABLED
add_blendmode_to_key(SkPaintParamsKeyBuilder * builder,SkBlendMode bm)54 void add_blendmode_to_key(SkPaintParamsKeyBuilder* builder, SkBlendMode bm) {
55     SkASSERT(static_cast<int>(bm) <= std::numeric_limits<uint8_t>::max());
56     builder->addByte(static_cast<uint8_t>(bm));
57 }
58 
59 #ifdef SK_DEBUG
to_blendmode(uint8_t data)60 SkBlendMode to_blendmode(uint8_t data) {
61     SkASSERT(data <= static_cast<int>(SkBlendMode::kLastMode));
62     return static_cast<SkBlendMode>(data);
63 }
64 
to_tilemode(uint8_t data)65 SkTileMode to_tilemode(uint8_t data) {
66     SkASSERT(data <= static_cast<int>(SkTileMode::kLastTileMode));
67     return static_cast<SkTileMode>(data);
68 }
69 #endif // SK_DEBUG
70 
71 #endif // SK_GRAPHITE_ENABLED
72 
73 } // anonymous namespace
74 
75 //--------------------------------------------------------------------------------------------------
76 namespace DepthStencilOnlyBlock {
77 
78 static const int kBlockDataSize = 0;
79 
AddToKey(SkShaderCodeDictionary *,SkBackend,SkPaintParamsKeyBuilder * builder,SkUniformBlock *)80 void AddToKey(SkShaderCodeDictionary* /* dict */,
81               SkBackend /* backend */,
82               SkPaintParamsKeyBuilder* builder,
83               SkUniformBlock* /* uniformBlock */) {
84     builder->beginBlock(SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw);
85     builder->endBlock();
86 
87     validate_block_header(builder,
88                           SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw,
89                           kBlockDataSize);
90 }
91 
92 #ifdef SK_DEBUG
Dump(const SkPaintParamsKey & key,int headerOffset)93 void Dump(const SkPaintParamsKey& key, int headerOffset) {
94 #ifdef SK_GRAPHITE_ENABLED
95     validate_block_header_key(key,
96                               headerOffset,
97                               SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw,
98                               kBlockDataSize);
99 
100     SkDebugf("kDepthStencilOnlyDraw\n");
101 #endif // SK_GRAPHITE_ENABLED
102 }
103 #endif // SK_DEBUG
104 
105 } // namespace DepthStencilOnlyBlock
106 
107 //--------------------------------------------------------------------------------------------------
108 namespace SolidColorShaderBlock {
109 
110 namespace {
111 
112 #ifdef SK_GRAPHITE_ENABLED
113 static const int kBlockDataSize = 0;
114 
make_solid_uniform_data(SkShaderCodeDictionary * dict,SkColor4f color)115 sk_sp<SkUniformData> make_solid_uniform_data(SkShaderCodeDictionary* dict, SkColor4f color) {
116     static constexpr size_t kExpectedNumUniforms = 1;
117 
118     SkSpan<const SkUniform> uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kSolidColorShader);
119     SkASSERT(uniforms.size() == kExpectedNumUniforms);
120 
121     skgpu::UniformManager mgr(skgpu::Layout::kMetal);
122 
123     size_t dataSize = mgr.writeUniforms(uniforms, nullptr, nullptr, nullptr);
124 
125     sk_sp<SkUniformData> result = SkUniformData::Make(uniforms, dataSize);
126 
127     const void* srcs[kExpectedNumUniforms] = { &color };
128 
129     mgr.writeUniforms(result->uniforms(), srcs, result->offsets(), result->data());
130     return result;
131 }
132 #endif // SK_GRAPHITE_ENABLED
133 
134 } // anonymous namespace
135 
AddToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock,const SkColor4f & color)136 void AddToKey(SkShaderCodeDictionary* dict,
137               SkBackend backend,
138               SkPaintParamsKeyBuilder* builder,
139               SkUniformBlock* uniformBlock,
140               const SkColor4f& color) {
141 
142 #ifdef SK_GRAPHITE_ENABLED
143     if (backend == SkBackend::kGraphite) {
144         builder->beginBlock(SkBuiltInCodeSnippetID::kSolidColorShader);
145         builder->endBlock();
146 
147         validate_block_header(builder,
148                               SkBuiltInCodeSnippetID::kSolidColorShader,
149                               kBlockDataSize);
150 
151         if (uniformBlock) {
152             uniformBlock->add(make_solid_uniform_data(dict, color));
153         }
154         return;
155     }
156 #endif // SK_GRAPHITE_ENABLED
157 
158     if (backend == SkBackend::kSkVM || backend == SkBackend::kGanesh) {
159         // TODO: add implementation of other backends
160     }
161 
162 }
163 
164 #ifdef SK_DEBUG
Dump(const SkPaintParamsKey & key,int headerOffset)165 void Dump(const SkPaintParamsKey& key, int headerOffset) {
166 
167 #ifdef SK_GRAPHITE_ENABLED
168     validate_block_header_key(key,
169                               headerOffset,
170                               SkBuiltInCodeSnippetID::kSolidColorShader,
171                               kBlockDataSize);
172 
173     SkDebugf("kSolidColorShader\n");
174 #endif
175 
176 }
177 #endif
178 
179 } // namespace SolidColorShaderBlock
180 
181 //--------------------------------------------------------------------------------------------------
182 namespace GradientShaderBlocks {
183 
184 namespace {
185 
186 #ifdef SK_GRAPHITE_ENABLED
187 static const int kBlockDataSize = 1;
188 static const int kExpectedNumGradientUniforms = 7;
189 
make_gradient_uniform_data_common(SkSpan<const SkUniform> uniforms,const void * srcs[kExpectedNumGradientUniforms])190 sk_sp<SkUniformData> make_gradient_uniform_data_common(
191         SkSpan<const SkUniform> uniforms,
192         const void* srcs[kExpectedNumGradientUniforms]) {
193     skgpu::UniformManager mgr(skgpu::Layout::kMetal);
194 
195     // TODO: Given that, for the sprint, we always know the uniforms we could cache 'dataSize'
196     // for each layout and skip the first call.
197     size_t dataSize = mgr.writeUniforms(uniforms, nullptr, nullptr, nullptr);
198 
199     sk_sp<SkUniformData> result = SkUniformData::Make(uniforms, dataSize);
200 
201     mgr.writeUniforms(result->uniforms(), srcs, result->offsets(), result->data());
202     return result;
203 }
204 
make_linear_gradient_uniform_data(SkShaderCodeDictionary * dict,const GradientData & gradData)205 sk_sp<SkUniformData> make_linear_gradient_uniform_data(SkShaderCodeDictionary* dict,
206                                                        const GradientData& gradData) {
207 
208     auto uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kLinearGradientShader);
209     SkASSERT(uniforms.size() == kExpectedNumGradientUniforms);
210 
211     SkPoint padding{0, 0};
212     const void* srcs[kExpectedNumGradientUniforms] = {
213         gradData.fColor4fs,
214         gradData.fOffsets,
215         &gradData.fPoints[0],
216         &gradData.fPoints[1],
217         &gradData.fRadii[0], // unused
218         &gradData.fRadii[1], // unused
219         &padding
220     };
221 
222     return make_gradient_uniform_data_common(uniforms, srcs);
223 };
224 
make_radial_gradient_uniform_data(SkShaderCodeDictionary * dict,const GradientData & gradData)225 sk_sp<SkUniformData> make_radial_gradient_uniform_data(SkShaderCodeDictionary* dict,
226                                                        const GradientData& gradData) {
227 
228     auto uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kRadialGradientShader);
229     SkASSERT(uniforms.size() == kExpectedNumGradientUniforms);
230 
231     SkPoint padding{0, 0};
232     const void* srcs[kExpectedNumGradientUniforms] = {
233         gradData.fColor4fs,
234         gradData.fOffsets,
235         &gradData.fPoints[0],
236         &gradData.fPoints[1], // unused
237         &gradData.fRadii[0],
238         &gradData.fRadii[1],  // unused
239         &padding
240     };
241 
242     return make_gradient_uniform_data_common(uniforms, srcs);
243 };
244 
make_sweep_gradient_uniform_data(SkShaderCodeDictionary * dict,const GradientData & gradData)245 sk_sp<SkUniformData> make_sweep_gradient_uniform_data(SkShaderCodeDictionary* dict,
246                                                       const GradientData& gradData) {
247 
248     auto uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kSweepGradientShader);
249     SkASSERT(uniforms.size() == kExpectedNumGradientUniforms);
250 
251     SkPoint padding{0, 0};
252     const void* srcs[kExpectedNumGradientUniforms] = {
253         gradData.fColor4fs,
254         gradData.fOffsets,
255         &gradData.fPoints[0],
256         &gradData.fPoints[1], // unused
257         &gradData.fRadii[0],  // unused
258         &gradData.fRadii[1],  // unused
259         &padding
260     };
261 
262     return make_gradient_uniform_data_common(uniforms, srcs);
263 };
264 
make_conical_gradient_uniform_data(SkShaderCodeDictionary * dict,const GradientData & gradData)265 sk_sp<SkUniformData> make_conical_gradient_uniform_data(SkShaderCodeDictionary* dict,
266                                                         const GradientData& gradData) {
267 
268     auto uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kConicalGradientShader);
269     SkASSERT(uniforms.size() == kExpectedNumGradientUniforms);
270 
271     SkPoint padding{0, 0};
272     const void* srcs[kExpectedNumGradientUniforms] = {
273         gradData.fColor4fs,
274         gradData.fOffsets,
275         &gradData.fPoints[0],
276         &gradData.fPoints[1],
277         &gradData.fRadii[0],
278         &gradData.fRadii[1],
279         &padding,
280     };
281 
282     return make_gradient_uniform_data_common(uniforms, srcs);
283 };
284 
285 #endif // SK_GRAPHITE_ENABLED
286 
287 } // anonymous namespace
288 
GradientData(SkShader::GradientType type,SkTileMode tm,int numStops)289 GradientData::GradientData(SkShader::GradientType type,
290                            SkTileMode tm,
291                            int numStops)
292         : fType(type)
293         , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
294         , fRadii{0.0f, 0.0f}
295         , fTM(tm)
296         , fNumStops(numStops) {
297     sk_bzero(fColor4fs, sizeof(fColor4fs));
298     sk_bzero(fOffsets, sizeof(fOffsets));
299 }
300 
GradientData(SkShader::GradientType type,SkPoint point0,SkPoint point1,float radius0,float radius1,SkTileMode tm,int numStops,SkColor4f * color4fs,float * offsets)301 GradientData::GradientData(SkShader::GradientType type,
302                            SkPoint point0, SkPoint point1,
303                            float radius0, float radius1,
304                            SkTileMode tm,
305                            int numStops,
306                            SkColor4f* color4fs,
307                            float* offsets)
308         : fType(type)
309         , fTM(tm)
310         , fNumStops(std::min(numStops, kMaxStops)) {
311     SkASSERT(fNumStops >= 1);
312 
313     fPoints[0] = point0;
314     fPoints[1] = point1;
315     fRadii[0] = radius0;
316     fRadii[1] = radius1;
317     memcpy(fColor4fs, color4fs, fNumStops * sizeof(SkColor4f));
318     if (offsets) {
319         memcpy(fOffsets, offsets, fNumStops * sizeof(float));
320     } else {
321         for (int i = 0; i < fNumStops; ++i) {
322             fOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
323         }
324     }
325 
326     // Extend the colors and offset, if necessary, to fill out the arrays
327     // TODO: this should be done later when the actual code snippet has been selected!!
328     for (int i = fNumStops ; i < kMaxStops; ++i) {
329         fColor4fs[i] = fColor4fs[fNumStops-1];
330         fOffsets[i] = fOffsets[fNumStops-1];
331     }
332 }
333 
AddToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock,const GradientData & gradData)334 void AddToKey(SkShaderCodeDictionary* dict,
335               SkBackend backend,
336               SkPaintParamsKeyBuilder *builder,
337               SkUniformBlock* uniformBlock,
338               const GradientData& gradData) {
339 
340 #ifdef SK_GRAPHITE_ENABLED
341     if (backend == SkBackend::kGraphite) {
342         SkBuiltInCodeSnippetID codeSnippetID = SkBuiltInCodeSnippetID::kSolidColorShader;
343         switch (gradData.fType) {
344             case SkShader::kLinear_GradientType:
345                 codeSnippetID = SkBuiltInCodeSnippetID::kLinearGradientShader;
346                 if (uniformBlock) {
347                     uniformBlock->add(make_linear_gradient_uniform_data(dict, gradData));
348                 }
349                 break;
350             case SkShader::kRadial_GradientType:
351                 codeSnippetID = SkBuiltInCodeSnippetID::kRadialGradientShader;
352                 if (uniformBlock) {
353                     uniformBlock->add(make_radial_gradient_uniform_data(dict, gradData));
354                 }
355                 break;
356             case SkShader::kSweep_GradientType:
357                 codeSnippetID = SkBuiltInCodeSnippetID::kSweepGradientShader;
358                 if (uniformBlock) {
359                     uniformBlock->add(make_sweep_gradient_uniform_data(dict, gradData));
360                 }
361                 break;
362             case SkShader::GradientType::kConical_GradientType:
363                 codeSnippetID = SkBuiltInCodeSnippetID::kConicalGradientShader;
364                 if (uniformBlock) {
365                     uniformBlock->add(make_conical_gradient_uniform_data(dict, gradData));
366                 }
367                 break;
368             case SkShader::GradientType::kColor_GradientType:
369             case SkShader::GradientType::kNone_GradientType:
370             default:
371                 SkASSERT(0);
372                 break;
373         }
374 
375         builder->beginBlock(codeSnippetID);
376 
377         SkASSERT(static_cast<int>(gradData.fTM) <= std::numeric_limits<uint8_t>::max());
378         builder->addByte(static_cast<uint8_t>(gradData.fTM));
379 
380         builder->endBlock();
381 
382         validate_block_header(builder, codeSnippetID, kBlockDataSize);
383         return;
384     }
385 #endif // SK_GRAPHITE_ENABLED
386 
387     if (backend == SkBackend::kSkVM || backend == SkBackend::kGanesh) {
388         // TODO: add implementation of other backends
389         SolidColorShaderBlock::AddToKey(dict, backend, builder, uniformBlock, SkColors::kRed);
390     }
391 }
392 
393 #ifdef SK_DEBUG
394 
395 #ifdef SK_GRAPHITE_ENABLED
396 
ExtractFromKey(const SkPaintParamsKey & key,uint32_t headerOffset)397 std::pair<SkBuiltInCodeSnippetID, SkTileMode> ExtractFromKey(const SkPaintParamsKey& key,
398                                                              uint32_t headerOffset) {
399     SkBuiltInCodeSnippetID id = read_code_snippet_id(key, headerOffset);
400 
401     SkASSERT(id == SkBuiltInCodeSnippetID::kLinearGradientShader ||
402              id == SkBuiltInCodeSnippetID::kRadialGradientShader ||
403              id == SkBuiltInCodeSnippetID::kSweepGradientShader ||
404              id == SkBuiltInCodeSnippetID::kConicalGradientShader);
405     SkASSERT(key.byte(headerOffset+SkPaintParamsKey::kBlockSizeOffsetInBytes) ==
406              SkPaintParamsKey::kBlockHeaderSizeInBytes+kBlockDataSize);
407 
408     uint8_t data = key.byte(headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes);
409     SkTileMode tm = to_tilemode(data);
410 
411     return { id, tm };
412 }
413 
414 #endif // SK_GRAPHITE_ENABLED
415 
Dump(const SkPaintParamsKey & key,int headerOffset)416 void Dump(const SkPaintParamsKey& key, int headerOffset) {
417 
418 #ifdef SK_GRAPHITE_ENABLED
419     auto [id, tm] =  ExtractFromKey(key, headerOffset);
420 
421     switch (id) {
422         case SkBuiltInCodeSnippetID::kLinearGradientShader:
423             SkDebugf("kLinearGradientShader: %s\n", SkTileModeToStr(tm));
424             break;
425         case SkBuiltInCodeSnippetID::kRadialGradientShader:
426             SkDebugf("kRadialGradientShader: %s\n", SkTileModeToStr(tm));
427             break;
428         case SkBuiltInCodeSnippetID::kSweepGradientShader:
429             SkDebugf("kSweepGradientShader: %s\n", SkTileModeToStr(tm));
430             break;
431         case SkBuiltInCodeSnippetID::kConicalGradientShader:
432             SkDebugf("kConicalGradientShader: %s\n", SkTileModeToStr(tm));
433             break;
434         default:
435             SkDebugf("Unknown!!\n");
436             break;
437     }
438 #endif // SK_GRAPHITE_ENABLED
439 
440 }
441 #endif
442 
443 } // namespace GradientShaderBlocks
444 
445 //--------------------------------------------------------------------------------------------------
446 namespace ImageShaderBlock {
447 
448 namespace {
449 
450 #ifdef SK_GRAPHITE_ENABLED
451 
452 inline static constexpr int kTileModeBits = 2;
453 
454 static const int kXTileModeShift = 0;
455 static const int kYTileModeShift = kTileModeBits;
456 
457 #ifdef SK_DEBUG
458 static const int kBlockDataSize = 1;
459 
460 inline static constexpr int kTileModeMask = 0x3;
461 
ExtractFromKey(const SkPaintParamsKey & key,uint32_t headerOffset)462 ImageData ExtractFromKey(const SkPaintParamsKey& key, uint32_t headerOffset) {
463     validate_block_header_key(key,
464                               headerOffset,
465                               SkBuiltInCodeSnippetID::kImageShader,
466                               kBlockDataSize);
467 
468     uint8_t data = key.byte(headerOffset+SkPaintParamsKey::kBlockHeaderSizeInBytes);
469 
470     SkTileMode tmX = to_tilemode(((data) >> kXTileModeShift) & kTileModeMask);
471     SkTileMode tmY = to_tilemode(((data) >> kYTileModeShift) & kTileModeMask);
472 
473     return { tmX, tmY };
474 }
475 #endif // SK_DEBUG
476 
make_image_uniform_data(SkShaderCodeDictionary * dict,const ImageData & imgData)477 sk_sp<SkUniformData> make_image_uniform_data(SkShaderCodeDictionary* dict,
478                                              const ImageData& imgData) {
479     SkDEBUGCODE(static constexpr size_t kExpectedNumUniforms = 0;)
480 
481     SkSpan<const SkUniform> uniforms = dict->getUniforms(SkBuiltInCodeSnippetID::kImageShader);
482     SkASSERT(uniforms.size() == kExpectedNumUniforms);
483 
484     skgpu::UniformManager mgr(skgpu::Layout::kMetal);
485 
486     size_t dataSize = mgr.writeUniforms(uniforms, nullptr, nullptr, nullptr);
487 
488     sk_sp<SkUniformData> result = SkUniformData::Make(uniforms, dataSize);
489 
490     // TODO: add the required data to ImageData and assemble the uniforms here
491 
492     mgr.writeUniforms(result->uniforms(), nullptr, result->offsets(), result->data());
493     return result;
494 }
495 
496 #endif // SK_GRAPHITE_ENABLED
497 
498 } // anonymous namespace
499 
AddToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock,const ImageData & imgData)500 void AddToKey(SkShaderCodeDictionary* dict,
501               SkBackend backend,
502               SkPaintParamsKeyBuilder* builder,
503               SkUniformBlock* uniformBlock,
504               const ImageData& imgData) {
505 
506 #ifdef SK_GRAPHITE_ENABLED
507     if (backend == SkBackend::kGraphite) {
508 
509         uint8_t data = (static_cast<uint8_t>(imgData.fTileModes[0]) << kXTileModeShift) |
510                        (static_cast<uint8_t>(imgData.fTileModes[1]) << kYTileModeShift);
511 
512         builder->beginBlock(SkBuiltInCodeSnippetID::kImageShader);
513 
514         builder->addByte(data);
515 
516         builder->endBlock();
517 
518         if (uniformBlock) {
519             uniformBlock->add(make_image_uniform_data(dict, imgData));
520         }
521         return;
522     }
523 #endif // SK_GRAPHITE_ENABLED
524 
525     if (backend == SkBackend::kSkVM || backend == SkBackend::kGanesh) {
526         // TODO: add implementation for other backends
527         SolidColorShaderBlock::AddToKey(dict, backend, builder, uniformBlock, SkColors::kRed);
528     }
529 }
530 
531 #ifdef SK_DEBUG
Dump(const SkPaintParamsKey & key,int headerOffset)532 void Dump(const SkPaintParamsKey& key, int headerOffset) {
533 
534 #ifdef SK_GRAPHITE_ENABLED
535     ImageData imgData = ExtractFromKey(key, headerOffset);
536 
537     SkDebugf("kImageShader: tileModes(%s, %s) ",
538              SkTileModeToStr(imgData.fTileModes[0]),
539              SkTileModeToStr(imgData.fTileModes[1]));
540 #endif // SK_GRAPHITE_ENABLED
541 
542 }
543 #endif // SK_DEBUG
544 
545 } // namespace ImageShaderBlock
546 
547 //--------------------------------------------------------------------------------------------------
548 namespace BlendShaderBlock {
549 
AddToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock,const BlendData & blendData)550 void AddToKey(SkShaderCodeDictionary* dict,
551               SkBackend backend,
552               SkPaintParamsKeyBuilder *builder,
553               SkUniformBlock* uniformBlock,
554               const BlendData& blendData) {
555 
556 #ifdef SK_GRAPHITE_ENABLED
557     if (backend == SkBackend::kGraphite) {
558         builder->beginBlock(SkBuiltInCodeSnippetID::kBlendShader);
559 
560         // Child blocks always go right after the parent block's header
561         // TODO: add startChild/endChild entry points to SkPaintParamsKeyBuilder. They could be
562         // used to compute and store the number of children w/in a block's header.
563         int start = builder->sizeInBytes();
564         as_SB(blendData.fDst)->addToKey(dict, backend, builder, uniformBlock);
565         int firstShaderSize = builder->sizeInBytes() - start;
566 
567         start = builder->sizeInBytes();
568         as_SB(blendData.fSrc)->addToKey(dict, backend, builder, uniformBlock);
569         int secondShaderSize = builder->sizeInBytes() - start;
570 
571         add_blendmode_to_key(builder, blendData.fBM);
572 
573         builder->endBlock();
574 
575         int expectedBlockSize = 1 + firstShaderSize + secondShaderSize;
576         validate_block_header(builder,
577                               SkBuiltInCodeSnippetID::kBlendShader,
578                               expectedBlockSize);
579         return;
580     }
581 #endif // SK_GRAPHITE_ENABLED
582 
583     if (backend == SkBackend::kSkVM || backend == SkBackend::kGanesh) {
584         // TODO: add implementation for other backends
585         SolidColorShaderBlock::AddToKey(dict, backend, builder, uniformBlock, SkColors::kRed);
586     }
587 }
588 
589 #ifdef SK_DEBUG
Dump(const SkPaintParamsKey & key,int headerOffset)590 void Dump(const SkPaintParamsKey& key, int headerOffset) {
591 #ifdef SK_GRAPHITE_ENABLED
592     auto [id, storedBlockSize] = key.readCodeSnippetID(headerOffset);
593     SkASSERT(id == SkBuiltInCodeSnippetID::kBlendShader);
594 
595     int runningOffset = headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes;
596 
597     SkDebugf("\nDst:  ");
598     int firstBlockSize = SkPaintParamsKey::DumpBlock(key, runningOffset);
599     runningOffset += firstBlockSize;
600 
601     SkDebugf("Src: ");
602     int secondBlockSize = SkPaintParamsKey::DumpBlock(key, runningOffset);
603     runningOffset += secondBlockSize;
604 
605     uint8_t data = key.byte(runningOffset);
606     SkBlendMode bm = to_blendmode(data);
607 
608     SkDebugf("BlendMode: %s\n", SkBlendMode_Name(bm));
609     runningOffset += 1; // 1 byte for blendmode
610 
611     int calculatedBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes +
612                               firstBlockSize + secondBlockSize + 1;
613     SkASSERT(calculatedBlockSize == storedBlockSize);
614 #endif// SK_GRAPHITE_ENABLED
615 }
616 #endif
617 
618 } // namespace BlendShaderBlock
619 
620 //--------------------------------------------------------------------------------------------------
621 namespace BlendModeBlock {
622 
623 #ifdef SK_GRAPHITE_ENABLED
624 static const int kBlockDataSize = 1;
625 #endif
626 
AddToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock,SkBlendMode bm)627 void AddToKey(SkShaderCodeDictionary* dict,
628               SkBackend backend,
629               SkPaintParamsKeyBuilder *builder,
630               SkUniformBlock* uniformBlock,
631               SkBlendMode bm) {
632 
633 #ifdef SK_GRAPHITE_ENABLED
634     if (backend == SkBackend::kGraphite) {
635         builder->beginBlock(SkBuiltInCodeSnippetID::kSimpleBlendMode);
636         add_blendmode_to_key(builder, bm);
637         builder->endBlock();
638 
639         validate_block_header(builder,
640                               SkBuiltInCodeSnippetID::kSimpleBlendMode,
641                               kBlockDataSize);
642         return;
643     }
644 #endif// SK_GRAPHITE_ENABLED
645 
646     if (backend == SkBackend::kSkVM || backend == SkBackend::kGanesh) {
647         // TODO: add implementation for other backends
648         SolidColorShaderBlock::AddToKey(dict, backend, builder, uniformBlock, SkColors::kRed);
649     }
650 }
651 
652 #ifdef SK_DEBUG
653 
654 #ifdef SK_GRAPHITE_ENABLED
ExtractFromKey(const SkPaintParamsKey & key,uint32_t headerOffset)655 SkBlendMode ExtractFromKey(const SkPaintParamsKey& key, uint32_t headerOffset) {
656     validate_block_header_key(key,
657                               headerOffset,
658                               SkBuiltInCodeSnippetID::kSimpleBlendMode,
659                               kBlockDataSize);
660 
661     uint8_t data = key.byte(headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes);
662     return to_blendmode(data);
663 }
664 #endif // SK_GRAPHITE_ENABLED
665 
Dump(const SkPaintParamsKey & key,int headerOffset)666 void Dump(const SkPaintParamsKey& key, int headerOffset) {
667 
668 #ifdef SK_GRAPHITE_ENABLED
669     SkBlendMode bm = ExtractFromKey(key, headerOffset);
670 
671     SkDebugf("kSimpleBlendMode: %s\n", SkBlendMode_Name(bm));
672 #endif
673 
674 }
675 #endif
676 
677 } // namespace BlendModeBlock
678 
679 //--------------------------------------------------------------------------------------------------
680 #ifdef SK_GRAPHITE_ENABLED
CreateKey(SkShaderCodeDictionary * dict,SkBackend backend,skgpu::ShaderCombo::ShaderType s,SkTileMode tm,SkBlendMode bm)681 std::unique_ptr<SkPaintParamsKey> CreateKey(SkShaderCodeDictionary* dict,
682                                             SkBackend backend,
683                                             skgpu::ShaderCombo::ShaderType s,
684                                             SkTileMode tm,
685                                             SkBlendMode bm) {
686     SkPaintParamsKeyBuilder builder(dict);
687 
688     switch (s) {
689         case skgpu::ShaderCombo::ShaderType::kNone:
690             DepthStencilOnlyBlock::AddToKey(dict, backend, &builder, nullptr);
691             break;
692         case skgpu::ShaderCombo::ShaderType::kSolidColor:
693             SolidColorShaderBlock::AddToKey(dict, backend, &builder, nullptr, SkColors::kRed);
694             break;
695         case skgpu::ShaderCombo::ShaderType::kLinearGradient:
696             GradientShaderBlocks::AddToKey(dict, backend, &builder, nullptr,
697                                            { SkShader::kLinear_GradientType, tm, 0 });
698             break;
699         case skgpu::ShaderCombo::ShaderType::kRadialGradient:
700             GradientShaderBlocks::AddToKey(dict, backend, &builder, nullptr,
701                                            { SkShader::kRadial_GradientType, tm, 0 });
702             break;
703         case skgpu::ShaderCombo::ShaderType::kSweepGradient:
704             GradientShaderBlocks::AddToKey(dict, backend, &builder, nullptr,
705                                            { SkShader::kSweep_GradientType, tm, 0 });
706             break;
707         case skgpu::ShaderCombo::ShaderType::kConicalGradient:
708             GradientShaderBlocks::AddToKey(dict, backend, &builder, nullptr,
709                                            { SkShader::kConical_GradientType, tm, 0 });
710             break;
711     }
712 
713     BlendModeBlock::AddToKey(dict, backend, &builder, nullptr, bm);
714     return builder.snap();
715 }
716 #endif
717