1 /*
2 * Copyright 2025 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 "tests/Test.h"
9
10 #if defined(SK_GRAPHITE)
11
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColorSpace.h"
14 #include "include/core/SkString.h"
15 #include "include/effects/SkRuntimeEffect.h"
16 #include "include/gpu/graphite/Context.h"
17 #include "include/gpu/graphite/PrecompileContext.h"
18 #include "include/gpu/graphite/Surface.h"
19 #include "include/gpu/graphite/precompile/PaintOptions.h"
20 #include "include/gpu/graphite/precompile/Precompile.h"
21 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
22 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
23 #include "include/gpu/graphite/precompile/PrecompileRuntimeEffect.h"
24 #include "include/gpu/graphite/precompile/PrecompileShader.h"
25 #include "src/core/SkRuntimeEffectPriv.h"
26 #include "src/gpu/graphite/ContextPriv.h"
27 #include "src/gpu/graphite/PrecompileContextPriv.h"
28 #include "src/gpu/graphite/ShaderCodeDictionary.h"
29 #include "tools/graphite/ContextFactory.h"
30 #include "tools/graphite/GraphiteToolUtils.h"
31 #include "tools/graphite/UniqueKeyUtils.h"
32 #include "tools/graphite/precompile/PipelineCallbackHandler.h"
33 #include "tools/graphite/precompile/PrecompileEffectFactories.h"
34
35 using namespace::skgpu::graphite;
36 using namespace skiatest::graphite;
37 using namespace skiatools::graphite;
38
39 namespace {
40
create_paint_and_options(bool addBlenders)41 std::pair<SkPaint, PaintOptions> create_paint_and_options(bool addBlenders) {
42 SkPaint paint;
43 PaintOptions paintOptions;
44
45 auto [shader, shaderOption] = PrecompileFactories::CreateAnnulusRuntimeShader();
46
47 paint.setShader(std::move(shader));
48 paintOptions.setShaders({ std::move(shaderOption) });
49
50 auto [colorFilter, colorFilterOption] = PrecompileFactories::CreateComboRuntimeColorFilter();
51
52 paint.setColorFilter(std::move(colorFilter));
53 paintOptions.setColorFilters({ std::move(colorFilterOption) });
54
55 if (addBlenders) {
56 auto [blender, blenderOption] = PrecompileFactories::CreateComboRuntimeBlender();
57
58 paint.setBlender(std::move(blender));
59 paintOptions.setBlenders({ std::move(blenderOption) });
60 }
61
62 return { paint, paintOptions };
63 }
64
draw_with_normal_api(skgpu::graphite::Context * context,skgpu::graphite::Recorder * recorder,const SkPaint & paint)65 bool draw_with_normal_api(skgpu::graphite::Context* context,
66 skgpu::graphite::Recorder* recorder,
67 const SkPaint& paint) {
68 auto ii = SkImageInfo::Make({ 256, 256 }, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
69
70 sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(recorder, ii, skgpu::Mipmapped::kNo);
71 if (!surface) {
72 return false;
73 }
74
75 SkCanvas* canvas = surface->getCanvas();
76
77 canvas->drawRect({0, 0, 100, 100}, paint);
78
79 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
80 if (!recording) {
81 return false;
82 }
83
84 if (!context->insertRecording({ recording.get() })) {
85 return false;
86 }
87
88 if (!context->submit(skgpu::graphite::SyncToCpu::kYes)) {
89 return false;
90 }
91
92 return true;
93 }
94
fetch_keys_and_reset(skiatest::Reporter * reporter,PipelineCallBackHandler * handler,PrecompileContext * precompileContext,std::vector<skgpu::UniqueKey> * uniqueKeys,std::vector<sk_sp<SkData>> * serializedKeys,bool reset)95 void fetch_keys_and_reset(skiatest::Reporter* reporter,
96 PipelineCallBackHandler* handler,
97 PrecompileContext* precompileContext,
98 std::vector<skgpu::UniqueKey>* uniqueKeys,
99 std::vector<sk_sp<SkData>>* serializedKeys,
100 bool reset) {
101 UniqueKeyUtils::FetchUniqueKeys(precompileContext, uniqueKeys);
102 handler->retrieve(serializedKeys);
103
104 if (reset) {
105 GlobalCache* globalCache = precompileContext->priv().globalCache();
106
107 globalCache->resetGraphicsPipelines();
108 REPORTER_ASSERT(reporter, globalCache->numGraphicsPipelines() == 0);
109 handler->reset();
110 REPORTER_ASSERT(reporter, handler->numKeys() == 0);
111 }
112 }
113
114 // Get the existing keys, reset, and try recreating them all w/ the serialized pipeline keys
reset_and_recreate_pipelines_with_serialized_keys(skiatest::Reporter * reporter,Context * context,Recorder * recorder,PrecompileContext * precompileContext,PipelineCallBackHandler * handler)115 void reset_and_recreate_pipelines_with_serialized_keys(
116 skiatest::Reporter* reporter,
117 Context* context,
118 Recorder* recorder,
119 PrecompileContext* precompileContext,
120 PipelineCallBackHandler* handler) {
121 GlobalCache* globalCache = precompileContext->priv().globalCache();
122 ShaderCodeDictionary* shaderCodeDictionary = context->priv().shaderCodeDictionary();
123
124 auto [paint, _] = create_paint_and_options(/* addBlenders= */ true);
125
126 draw_with_normal_api(context, recorder, paint);
127
128 // None of the user-defined stable runtime effects should've been transmuted to not-stable
129 REPORTER_ASSERT(reporter, !shaderCodeDictionary->numUserDefinedRuntimeEffects());
130
131 std::vector<skgpu::UniqueKey> origKeys;
132 std::vector<sk_sp<SkData>> androidStyleKeys;
133
134 fetch_keys_and_reset(reporter, handler, precompileContext,
135 &origKeys, &androidStyleKeys, /* reset= */ true);
136
137 // Given 'draw_with_normal_api' we expect one serialized key - full of user-defined stable keys
138 REPORTER_ASSERT(reporter, origKeys.size() == 1);
139 REPORTER_ASSERT(reporter, androidStyleKeys.size() == 1);
140
141 // Use the serialized keys to regenerate the Pipelines
142 for (sk_sp<SkData>& d : androidStyleKeys) {
143 bool result = precompileContext->precompile(d);
144 SkAssertResult(result);
145 }
146
147 // None of the user-defined stable runtime effects should've been transmuted to not-stable
148 REPORTER_ASSERT(reporter, !shaderCodeDictionary->numUserDefinedRuntimeEffects());
149
150 std::vector<skgpu::UniqueKey> recreatedKeys;
151 std::vector<sk_sp<SkData>> recreatedAndroidStyleKeys;
152
153 fetch_keys_and_reset(reporter, handler, precompileContext,
154 &recreatedKeys, &recreatedAndroidStyleKeys, /* reset= */ false);
155
156 REPORTER_ASSERT(reporter, recreatedKeys.size() == 1);
157 REPORTER_ASSERT(reporter, origKeys[0] == recreatedKeys[0]);
158
159 REPORTER_ASSERT(reporter, recreatedAndroidStyleKeys.size() == 1);
160 REPORTER_ASSERT(reporter, androidStyleKeys[0]->equals(recreatedAndroidStyleKeys[0].get()));
161
162 int numBeforeSecondDraw = globalCache->numGraphicsPipelines();
163
164 draw_with_normal_api(context, recorder, paint);
165
166 // None of the user-defined stable runtime effects should've been transmuted to not-stable
167 REPORTER_ASSERT(reporter, !shaderCodeDictionary->numUserDefinedRuntimeEffects());
168
169 // Re-drawing shouldn't create any new pipelines
170 REPORTER_ASSERT(reporter, numBeforeSecondDraw == globalCache->numGraphicsPipelines(),
171 "%d != %d", numBeforeSecondDraw, globalCache->numGraphicsPipelines());
172 }
173
174 // Get the existing keys, reset, and then try recreating them all using the normal precompile API
reset_and_recreate_pipelines_with_normal_precompile_api(skiatest::Reporter * reporter,Context * context,Recorder * recorder,PrecompileContext * precompileContext,PipelineCallBackHandler * handler)175 void reset_and_recreate_pipelines_with_normal_precompile_api(
176 skiatest::Reporter* reporter,
177 Context* context,
178 Recorder* recorder,
179 PrecompileContext* precompileContext,
180 PipelineCallBackHandler* handler) {
181 // We don't attach runtime blenders to the SkPaint and PaintOptions in this case bc that will
182 // force a dest read and complicate the normal-pipeline/Precompile-pipeline
183 // comparison on Native Mac and Vulkan. This is bc, for those platforms, Precompile skips some
184 // LoadOp combinations which don't matter for those platforms (please see 'numLoadOps' in
185 // Precompile) but are serialized (for simplicity) in the serialized pipeline keys.
186 auto [paint, paintOptions] = create_paint_and_options(/* addBlenders= */ false);
187
188 draw_with_normal_api(context, recorder, paint);
189
190 std::vector<skgpu::UniqueKey> origKeys;
191 std::vector<sk_sp<SkData>> androidStyleKeys;
192
193 fetch_keys_and_reset(reporter, handler, precompileContext,
194 &origKeys, &androidStyleKeys, /* reset= */ true);
195
196 // Given 'draw_with_normal_api' we expect one serialized key - full of user-defined stable keys
197 REPORTER_ASSERT(reporter, origKeys.size() == 1);
198 REPORTER_ASSERT(reporter, androidStyleKeys.size() == 1);
199
200 RenderPassProperties renderPassProps;
201 renderPassProps.fDSFlags = DepthStencilFlags::kDepth;
202
203 Precompile(precompileContext,
204 paintOptions,
205 DrawTypeFlags::kSimpleShape,
206 { renderPassProps });
207
208 std::vector<skgpu::UniqueKey> recreatedKeys;
209 std::vector<sk_sp<SkData>> recreatedAndroidStyleKeys;
210
211 fetch_keys_and_reset(reporter, handler, precompileContext,
212 &recreatedKeys, &recreatedAndroidStyleKeys, /* reset= */ true);
213
214 // The normal precompile API will overgenerate, so we need to search for a match
215 {
216 bool foundIt = false;
217 for (const skgpu::UniqueKey& k : recreatedKeys) {
218 if (origKeys[0] == k) {
219 foundIt = true;
220 break;
221 }
222 }
223 REPORTER_ASSERT(reporter, foundIt);
224 }
225 {
226 bool foundIt = false;
227 for (const sk_sp<SkData>& k : recreatedAndroidStyleKeys) {
228 if (androidStyleKeys[0]->equals(k.get())) {
229 foundIt = true;
230 break;
231 }
232 }
233 REPORTER_ASSERT(reporter, foundIt);
234 }
235 }
236
237 // This helper creates a defective user-defined known runtime effect pair:
238 // the blessed shader will have a user-defined stable key
239 // the cursed shader has the same SkSL as the blessed one but no stable key
make_defective_annulus_shader_pair()240 std::pair<sk_sp<SkShader>, sk_sp<SkShader>> make_defective_annulus_shader_pair() {
241 SkRuntimeEffect* blessed = PrecompileFactories::GetAnnulusShaderEffect();
242
243 sk_sp<SkRuntimeEffect> cursed(SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
244 PrecompileFactories::GetAnnulusShaderCode()));
245
246 SkASSERT(blessed != cursed.get());
247
248 static const float kUniforms[4] = { 50.0f, 50.0f, 40.0f, 50.0f };
249
250 sk_sp<SkData> uniforms = SkData::MakeWithCopy(kUniforms, sizeof(kUniforms));
251
252 return { blessed->makeShader(uniforms, /* children= */ {}),
253 cursed->makeShader(uniforms, /* children= */ {}) };
254 }
255
256 // Draw once with a registered runtime effect, reset, and then re-draw w/ an un-registered
257 // runtime effect that uses the same SkSL.
test_sksl_reuse(skiatest::Reporter * reporter,Context * context,Recorder * recorder,PrecompileContext * precompileContext,PipelineCallBackHandler * handler)258 void test_sksl_reuse(skiatest::Reporter* reporter,
259 Context* context,
260 Recorder* recorder,
261 PrecompileContext* precompileContext,
262 PipelineCallBackHandler* handler) {
263 auto [blessedShader, cursedShader] = make_defective_annulus_shader_pair();
264
265 SkASSERT(blessedShader != cursedShader);
266
267 // The blessed paint is the static one from the PrecompileFactories which has been
268 // registered as a user-defined known runtime effect.
269 SkPaint blessedPaint;
270 blessedPaint.setShader(std::move(blessedShader));
271
272 // The cursed paint uses the same SkSL as the blessed version but uses a wholly separate
273 // runtime effect (which is not registered).
274 SkPaint cursedPaint;
275 cursedPaint.setShader(std::move(cursedShader));
276
277 draw_with_normal_api(context, recorder, blessedPaint);
278
279 std::vector<skgpu::UniqueKey> origKeys;
280 std::vector<sk_sp<SkData>> serializedKeys;
281
282 fetch_keys_and_reset(reporter, handler, precompileContext,
283 &origKeys, &serializedKeys, /* reset= */ true);
284
285 // Given 'draw_with_normal_api' we expect one serialized key - full of user-defined stable keys
286 REPORTER_ASSERT(reporter, origKeys.size() == 1);
287 REPORTER_ASSERT(reporter, serializedKeys.size() == 1);
288
289 draw_with_normal_api(context, recorder, cursedPaint);
290
291 std::vector<skgpu::UniqueKey> recreatedKeys;
292 std::vector<sk_sp<SkData>> recreatedSerializedKeys;
293
294 fetch_keys_and_reset(reporter, handler, precompileContext,
295 &recreatedKeys, &recreatedSerializedKeys, /* reset= */ true);
296
297 REPORTER_ASSERT(reporter, recreatedKeys.size() == 1);
298 REPORTER_ASSERT(reporter, origKeys[0] == recreatedKeys[0]);
299
300 // The un-registered runtime effect should've been mapped back to the registered one
301 // and successfully serialized.
302 REPORTER_ASSERT(reporter, recreatedSerializedKeys.size() == 1);
303 REPORTER_ASSERT(reporter, serializedKeys[0]->equals(recreatedSerializedKeys[0].get()));
304 }
305
test_get_pipeline_label_api(skiatest::Reporter * reporter,Context * context,Recorder * recorder,PrecompileContext * precompileContext,PipelineCallBackHandler * handler)306 void test_get_pipeline_label_api(skiatest::Reporter* reporter,
307 Context* context,
308 Recorder* recorder,
309 PrecompileContext* precompileContext,
310 PipelineCallBackHandler* handler) {
311 auto [paint, paintOptions] = create_paint_and_options(/* addBlenders= */ true);
312
313 draw_with_normal_api(context, recorder, paint);
314
315 std::vector<skgpu::UniqueKey> origKeys;
316 std::vector<sk_sp<SkData>> androidStyleKeys;
317
318 fetch_keys_and_reset(reporter, handler, precompileContext,
319 &origKeys, &androidStyleKeys, /* reset= */ true);
320
321 // Given 'draw_with_normal_api' we expect one serialized key - full of user-defined stable keys
322 REPORTER_ASSERT(reporter, origKeys.size() == 1);
323 REPORTER_ASSERT(reporter, androidStyleKeys.size() == 1);
324
325 std::string label = precompileContext->getPipelineLabel(androidStyleKeys[0]);
326
327 REPORTER_ASSERT(reporter, std::string::npos != label.find("AnnulusShader"));
328 REPORTER_ASSERT(reporter, std::string::npos != label.find("SrcBlender"));
329 REPORTER_ASSERT(reporter, std::string::npos != label.find("DstBlender"));
330 REPORTER_ASSERT(reporter, std::string::npos != label.find("ComboBlender"));
331 REPORTER_ASSERT(reporter, std::string::npos != label.find("DoubleColorFilter"));
332 REPORTER_ASSERT(reporter, std::string::npos != label.find("ComboColorFilter"));
333 // We withheld the HalfColorFilter name to test the default name case
334 REPORTER_ASSERT(reporter, std::string::npos == label.find("HalfColorFilter"));
335 REPORTER_ASSERT(reporter, std::string::npos != label.find("UserDefinedKnownRuntimeEffect"));
336 }
337
338
339 } // anonymous namespace
340
341 // This test adds some user-defined stably-keyed runtime effects and then verifies that
342 // everything behaves as expected. For the purposes of this test, "behaves as expected" means:
343 // 1) the user-defined stably keyed runtime effects appear as such in the ShaderCodeDictionary
344 // 2) the user-defined stable keys appear in the serialized Pipeline
345 // keys (i.e., from the PipelineCallBackHandler)
346 // 3) said keys correctly (re)generate the desired pipelines
347 // 4) the normal (non-serialized-key) Precompile API generates the same keys.
348 // 5) if the blessed stable runtime-effects aren't used, the free-range runtime-effects are
349 // mapped back to the stable runtime-effects (clients really shouldn't do this though!)
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest,skgpu::IsRenderingContext,reporter,origContext,origTestContext,origOptions,nullptr,true,CtsEnforcement::kNever)350 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest,
351 skgpu::IsRenderingContext,
352 reporter,
353 origContext,
354 origTestContext,
355 origOptions,
356 /* optionsProc= */ nullptr,
357 /* condition= */ true,
358 CtsEnforcement::kNever) {
359
360 std::unique_ptr<PipelineCallBackHandler> pipelineHandler(new PipelineCallBackHandler);
361
362 TestOptions newOptions(origOptions);
363 newOptions.fContextOptions.fPipelineCallbackContext = pipelineHandler.get();
364 newOptions.fContextOptions.fPipelineCallback = PipelineCallBackHandler::CallBack;
365
366 // We're going to also use all these runtime effects via the normal API
367 // (c.f. create_paint_and_options)
368 static const int kNumUserDefinedStableKeys = 7;
369 sk_sp<SkRuntimeEffect> userDefinedKnownRuntimeEffects[kNumUserDefinedStableKeys] = {
370 sk_ref_sp(PrecompileFactories::GetAnnulusShaderEffect()),
371
372 sk_ref_sp(PrecompileFactories::GetSrcBlenderEffect()),
373 sk_ref_sp(PrecompileFactories::GetDstBlenderEffect()),
374 sk_ref_sp(PrecompileFactories::GetComboBlenderEffect()),
375
376 sk_ref_sp(PrecompileFactories::GetDoubleColorFilterEffect()),
377 sk_ref_sp(PrecompileFactories::GetHalfColorFilterEffect()),
378 sk_ref_sp(PrecompileFactories::GetComboColorFilterEffect()),
379 };
380
381 for (const sk_sp<SkRuntimeEffect>& e: userDefinedKnownRuntimeEffects) {
382 // The PrecompileFactories runtime effects are static so prior runs may have already
383 // set their StableKeys. Reset the StableKeys so all our expectations/asserts will be met.
384 SkRuntimeEffectPriv::ResetStableKey(e.get());
385 }
386
387 newOptions.fContextOptions.fUserDefinedKnownRuntimeEffects = { userDefinedKnownRuntimeEffects };
388
389 ContextFactory workaroundFactory(newOptions);
390 ContextInfo ctxInfo = workaroundFactory.getContextInfo(origTestContext->contextType());
391
392 Context* newContext = ctxInfo.fContext;
393 std::unique_ptr<PrecompileContext> precompileContext = newContext->makePrecompileContext();
394 GlobalCache* globalCache = precompileContext->priv().globalCache();
395 ShaderCodeDictionary* shaderCodeDictionary = newContext->priv().shaderCodeDictionary();
396 std::unique_ptr<Recorder> recorder =
397 newContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
398
399 REPORTER_ASSERT(reporter, !globalCache->numGraphicsPipelines());
400 // The next two lines check #1 above
401 REPORTER_ASSERT(reporter, !shaderCodeDictionary->numUserDefinedRuntimeEffects());
402 REPORTER_ASSERT(reporter, shaderCodeDictionary->numUserDefinedKnownRuntimeEffects() ==
403 kNumUserDefinedStableKeys);
404
405 // This verifies #2 and #3 above
406 reset_and_recreate_pipelines_with_serialized_keys(reporter,
407 newContext,
408 recorder.get(),
409 precompileContext.get(),
410 pipelineHandler.get());
411
412 globalCache->resetGraphicsPipelines();
413 pipelineHandler->reset();
414
415 // This tests out #4 above
416 reset_and_recreate_pipelines_with_normal_precompile_api(reporter,
417 newContext,
418 recorder.get(),
419 precompileContext.get(),
420 pipelineHandler.get());
421
422 globalCache->resetGraphicsPipelines();
423 pipelineHandler->reset();
424
425 // This tests out #5 above
426 test_sksl_reuse(reporter,
427 newContext,
428 recorder.get(),
429 precompileContext.get(),
430 pipelineHandler.get());
431
432 globalCache->resetGraphicsPipelines();
433 pipelineHandler->reset();
434
435 // Extra little test to check on the getPipelineLabel API
436 test_get_pipeline_label_api(reporter,
437 newContext,
438 recorder.get(),
439 precompileContext.get(),
440 pipelineHandler.get());
441 }
442
443 // Test that the ShaderCodeDictionary can deduplicate the user-defined known runtime effect list
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Duplicates,skgpu::IsRenderingContext,reporter,context,testContext,origOptions,nullptr,true,CtsEnforcement::kNever)444 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Duplicates,
445 skgpu::IsRenderingContext,
446 reporter,
447 context,
448 testContext,
449 origOptions,
450 /* optionsProc= */ nullptr,
451 /* condition= */ true,
452 CtsEnforcement::kNever) {
453
454 std::unique_ptr<PipelineCallBackHandler> pipelineHandler(new PipelineCallBackHandler);
455
456 TestOptions newOptions(origOptions);
457 newOptions.fContextOptions.fPipelineCallbackContext = pipelineHandler.get();
458 newOptions.fContextOptions.fPipelineCallback = PipelineCallBackHandler::CallBack;
459
460 sk_sp<SkRuntimeEffect> userDefinedKnownRuntimeEffects[] = {
461 sk_ref_sp(PrecompileFactories::GetAnnulusShaderEffect()),
462 sk_ref_sp(PrecompileFactories::GetAnnulusShaderEffect()),
463 };
464
465 for (const sk_sp<SkRuntimeEffect>& e: userDefinedKnownRuntimeEffects) {
466 // The PrecompileFactories runtime effects are static so prior runs may have already
467 // set their StableKeys. Reset the StableKeys so all our expectations/asserts will be met.
468 SkRuntimeEffectPriv::ResetStableKey(e.get());
469 }
470
471 newOptions.fContextOptions.fUserDefinedKnownRuntimeEffects = { userDefinedKnownRuntimeEffects };
472
473 ContextFactory workaroundFactory(newOptions);
474 ContextInfo ctxInfo = workaroundFactory.getContextInfo(testContext->contextType());
475
476 ShaderCodeDictionary* shaderCodeDictionary = ctxInfo.fContext->priv().shaderCodeDictionary();
477
478 REPORTER_ASSERT(reporter, shaderCodeDictionary->numUserDefinedKnownRuntimeEffects() == 1);
479 }
480
481 // Test that the ShaderCodeDictionary can handle nullptrs in the
482 // user-defined known runtime effect list
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Nullptrs,skgpu::IsRenderingContext,reporter,context,testContext,origOptions,nullptr,true,CtsEnforcement::kNever)483 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Nullptrs,
484 skgpu::IsRenderingContext,
485 reporter,
486 context,
487 testContext,
488 origOptions,
489 /* optionsProc= */ nullptr,
490 /* condition= */ true,
491 CtsEnforcement::kNever) {
492
493 std::unique_ptr<PipelineCallBackHandler> pipelineHandler(new PipelineCallBackHandler);
494
495 TestOptions newOptions(origOptions);
496 newOptions.fContextOptions.fPipelineCallbackContext = pipelineHandler.get();
497 newOptions.fContextOptions.fPipelineCallback = PipelineCallBackHandler::CallBack;
498
499 sk_sp<SkRuntimeEffect> userDefinedKnownRuntimeEffects[] = {
500 sk_ref_sp(PrecompileFactories::GetAnnulusShaderEffect()),
501 nullptr,
502 sk_ref_sp(PrecompileFactories::GetSrcBlenderEffect()),
503 };
504
505 for (const sk_sp<SkRuntimeEffect>& e : userDefinedKnownRuntimeEffects) {
506 // The PrecompileFactories runtime effects are static so prior runs may have already
507 // set their StableKeys. Reset the StableKeys so all our expectations/asserts will be met.
508 if (e) {
509 SkRuntimeEffectPriv::ResetStableKey(e.get());
510 }
511 }
512
513 newOptions.fContextOptions.fUserDefinedKnownRuntimeEffects = { userDefinedKnownRuntimeEffects };
514
515 ContextFactory workaroundFactory(newOptions);
516 ContextInfo ctxInfo = workaroundFactory.getContextInfo(testContext->contextType());
517
518 ShaderCodeDictionary* shaderCodeDictionary = ctxInfo.fContext->priv().shaderCodeDictionary();
519
520 REPORTER_ASSERT(reporter, shaderCodeDictionary->numUserDefinedKnownRuntimeEffects() == 2);
521 }
522
523 // Test that the ShaderCodeDictionary can handle excess user-defined known runtime effects
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Overflow,skgpu::IsRenderingContext,reporter,context,testContext,origOptions,nullptr,true,CtsEnforcement::kNever)524 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(UserDefinedStableKeyTest_Overflow,
525 skgpu::IsRenderingContext,
526 reporter,
527 context,
528 testContext,
529 origOptions,
530 /* optionsProc= */ nullptr,
531 /* condition= */ true,
532 CtsEnforcement::kNever) {
533
534 std::unique_ptr<PipelineCallBackHandler> pipelineHandler(new PipelineCallBackHandler);
535
536 TestOptions newOptions(origOptions);
537 newOptions.fContextOptions.fPipelineCallbackContext = pipelineHandler.get();
538 newOptions.fContextOptions.fPipelineCallback = PipelineCallBackHandler::CallBack;
539
540 std::vector<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects;
541
542 for (int i = 0; i < 2*SkKnownRuntimeEffects::kUserDefinedKnownRuntimeEffectsReservedCnt; ++i) {
543 SkString sksl;
544 sksl.printf("half4 main(float2 xy) { return half4(%d/255.0, %d/255.0, %d/255.0, 1.0); }",
545 i, i, i);
546 userDefinedKnownRuntimeEffects.push_back(SkRuntimeEffect::MakeForShader(sksl).effect);
547 }
548
549 newOptions.fContextOptions.fUserDefinedKnownRuntimeEffects = { userDefinedKnownRuntimeEffects };
550
551 ContextFactory workaroundFactory(newOptions);
552 ContextInfo ctxInfo = workaroundFactory.getContextInfo(testContext->contextType());
553
554 ShaderCodeDictionary* shaderCodeDictionary = ctxInfo.fContext->priv().shaderCodeDictionary();
555
556 REPORTER_ASSERT(reporter, shaderCodeDictionary->numUserDefinedKnownRuntimeEffects() ==
557 SkKnownRuntimeEffects::kUserDefinedKnownRuntimeEffectsReservedCnt);
558 }
559
560 #endif // SK_GRAPHITE
561