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