• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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