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 "tests/Test.h"
9 
10 #include "include/effects/SkRuntimeEffect.h"
11 #include "include/gpu/graphite/Context.h"
12 #include "src/core/SkRuntimeEffectPriv.h"
13 #include "src/gpu/graphite/ContextPriv.h"
14 #include "src/gpu/graphite/KeyHelpers.h"
15 #include "src/gpu/graphite/ShaderCodeDictionary.h"
16 
17 using namespace skgpu::graphite;
18 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(Shader_FindOrCreateSnippetForRuntimeEffect,reporter,context)19 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(Shader_FindOrCreateSnippetForRuntimeEffect, reporter, context) {
20     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
21 
22     std::unique_ptr<SkRuntimeEffect> testEffect(SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
23         "half4 main(float2 coords) {"
24             "return half4(coords.xy01);"
25         "}"
26     ));
27 
28     // Create a new runtime-effect snippet.
29     int snippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
30     REPORTER_ASSERT(reporter, snippetID >= kBuiltInCodeSnippetIDCount);
31 
32     // Verify that it can be looked up and its name is 'RuntimeEffect'. (The name isn't meaningful,
33     // but this is an easy way to verify that we didn't get an unrelated snippet.)
34     const ShaderSnippet* snippet = dict->getEntry(snippetID);
35     REPORTER_ASSERT(reporter, snippet);
36     REPORTER_ASSERT(reporter, std::string_view(snippet->fName) == "RuntimeEffect");
37 
38     // If we pass the same effect again, we should get the same snippet ID as before.
39     int foundSnippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
40     REPORTER_ASSERT(reporter, foundSnippetID == snippetID);
41 }
42 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ColorFilter_FindOrCreateSnippetForRuntimeEffect,reporter,context)43 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ColorFilter_FindOrCreateSnippetForRuntimeEffect,
44                                    reporter,
45                                    context) {
46     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
47 
48     std::unique_ptr<SkRuntimeEffect> testEffect(SkMakeRuntimeEffect(
49             SkRuntimeEffect::MakeForColorFilter,
50                 "half4 main(half4 color) {"
51                     "return color.gbra;"
52                 "}"
53             ));
54 
55     // Create a new runtime-effect snippet.
56     int snippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
57     REPORTER_ASSERT(reporter, snippetID >= kBuiltInCodeSnippetIDCount);
58 
59     // Verify that it can be looked up and its name is 'RuntimeEffect'. (The name isn't meaningful,
60     // but this is an easy way to verify that we didn't get an unrelated snippet.)
61     const ShaderSnippet* snippet = dict->getEntry(snippetID);
62     REPORTER_ASSERT(reporter, snippet);
63     REPORTER_ASSERT(reporter, std::string_view(snippet->fName) == "RuntimeEffect");
64 
65     // If we pass the same effect again, we should get the same snippet ID as before.
66     int foundSnippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
67     REPORTER_ASSERT(reporter, foundSnippetID == snippetID);
68 }
69 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ShaderUniforms_FindOrCreateSnippetForRuntimeEffect,reporter,context)70 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ShaderUniforms_FindOrCreateSnippetForRuntimeEffect,
71                                    reporter, context) {
72     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
73 
74     std::unique_ptr<SkRuntimeEffect> testEffect(SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
75         "uniform float3x3 MyFloat3x3Uniform;"
76         "uniform int4 MyInt4ArrayUniform[1];"
77         "uniform half2 MyHalf2ArrayUniform[99];"
78         "half4 main(float2 coords) {"
79             "return half4(coords.xy01);"
80         "}"
81     ));
82 
83     // Create a new runtime-effect snippet.
84     int snippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
85     REPORTER_ASSERT(reporter, snippetID >= kBuiltInCodeSnippetIDCount);
86 
87     // Delete the test effect.
88     testEffect = nullptr;
89 
90     // Verify that it can be looked up by its snippet ID.
91     const ShaderSnippet* snippet = dict->getEntry(snippetID);
92     REPORTER_ASSERT(reporter, snippet);
93 
94     // The uniform span should match our expectations even though the runtime effect was deleted.
95     REPORTER_ASSERT(reporter, snippet->fUniforms.size() == 3);
96 
97     REPORTER_ASSERT(reporter,
98                     std::string_view(snippet->fUniforms[0].name()) == "MyFloat3x3Uniform");
99     REPORTER_ASSERT(reporter, snippet->fUniforms[0].type() == SkSLType::kFloat3x3);
100     REPORTER_ASSERT(reporter, snippet->fUniforms[0].count() == 0);
101 
102     REPORTER_ASSERT(reporter,
103                     std::string_view(snippet->fUniforms[1].name()) == "MyInt4ArrayUniform");
104     REPORTER_ASSERT(reporter, snippet->fUniforms[1].type() == SkSLType::kInt4);
105     REPORTER_ASSERT(reporter, snippet->fUniforms[1].count() == 1);
106 
107     REPORTER_ASSERT(reporter,
108                     std::string_view(snippet->fUniforms[2].name()) == "MyHalf2ArrayUniform");
109     REPORTER_ASSERT(reporter, snippet->fUniforms[2].type() == SkSLType::kHalf2);
110     REPORTER_ASSERT(reporter, snippet->fUniforms[2].count() == 99);
111 }
112 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ColorFilterUniforms_FindOrCreateSnippetForRuntimeEffect,reporter,context)113 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ColorFilterUniforms_FindOrCreateSnippetForRuntimeEffect,
114                                    reporter, context) {
115     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
116 
117     std::unique_ptr<SkRuntimeEffect> testEffect(SkMakeRuntimeEffect(
118             SkRuntimeEffect::MakeForColorFilter,
119                 "uniform float3x3 MyFloat3x3Uniform;"
120                 "uniform int4 MyInt4ArrayUniform[1];"
121                 "uniform half2 MyHalf2ArrayUniform[99];"
122                 "half4 main(half4 color) {"
123                     "return color.gbra;"
124                 "}"
125             ));
126 
127     // Create a new runtime-effect snippet.
128     int snippetID = dict->findOrCreateRuntimeEffectSnippet(testEffect.get());
129     REPORTER_ASSERT(reporter, snippetID >= kBuiltInCodeSnippetIDCount);
130 
131     // Delete the test effect.
132     testEffect = nullptr;
133 
134     // Verify that it can be looked up by its snippet ID.
135     const ShaderSnippet* snippet = dict->getEntry(snippetID);
136     REPORTER_ASSERT(reporter, snippet);
137 
138     // The uniform span should match our expectations even though the runtime effect was deleted.
139     REPORTER_ASSERT(reporter, snippet->fUniforms.size() == 3);
140 
141     REPORTER_ASSERT(reporter,
142                     std::string_view(snippet->fUniforms[0].name()) == "MyFloat3x3Uniform");
143     REPORTER_ASSERT(reporter, snippet->fUniforms[0].type() == SkSLType::kFloat3x3);
144     REPORTER_ASSERT(reporter, snippet->fUniforms[0].count() == 0);
145 
146     REPORTER_ASSERT(reporter,
147                     std::string_view(snippet->fUniforms[1].name()) == "MyInt4ArrayUniform");
148     REPORTER_ASSERT(reporter, snippet->fUniforms[1].type() == SkSLType::kInt4);
149     REPORTER_ASSERT(reporter, snippet->fUniforms[1].count() == 1);
150 
151     REPORTER_ASSERT(reporter,
152                     std::string_view(snippet->fUniforms[2].name()) == "MyHalf2ArrayUniform");
153     REPORTER_ASSERT(reporter, snippet->fUniforms[2].type() == SkSLType::kHalf2);
154     REPORTER_ASSERT(reporter, snippet->fUniforms[2].count() == 99);
155 }
156