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/sksl/SkSLModuleLoader.h"
9
10 #include "include/core/SkTypes.h"
11 #include "include/private/base/SkMutex.h"
12 #include "src/base/SkNoDestructor.h"
13 #include "src/sksl/SkSLBuiltinTypes.h"
14 #include "src/sksl/SkSLCompiler.h"
15 #include "src/sksl/SkSLModule.h"
16 #include "src/sksl/SkSLPosition.h"
17 #include "src/sksl/SkSLProgramKind.h"
18 #include "src/sksl/ir/SkSLIRNode.h"
19 #include "src/sksl/ir/SkSLLayout.h"
20 #include "src/sksl/ir/SkSLModifierFlags.h"
21 #include "src/sksl/ir/SkSLProgramElement.h"
22 #include "src/sksl/ir/SkSLSymbolTable.h"
23 #include "src/sksl/ir/SkSLType.h"
24 #include "src/sksl/ir/SkSLVariable.h"
25
26 #include <algorithm>
27 #include <memory>
28 #include <string>
29 #include <utility>
30 #include <vector>
31
32 #define MODULE_DATA(type) ModuleType::type, GetModuleData(ModuleType::type, #type ".sksl")
33
34 namespace SkSL {
35
36 #define TYPE(t) &BuiltinTypes::f ## t
37
38 static constexpr BuiltinTypePtr kRootTypes[] = {
39 TYPE(Void),
40
41 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
42 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
43 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
44 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
45 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
46 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
47 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
48
49 TYPE(Float2x2), TYPE(Float2x3), TYPE(Float2x4),
50 TYPE(Float3x2), TYPE(Float3x3), TYPE(Float3x4),
51 TYPE(Float4x2), TYPE(Float4x3), TYPE(Float4x4),
52
53 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
54 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
55 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
56
57 TYPE(SquareMat), TYPE(SquareHMat),
58 TYPE(Mat), TYPE(HMat),
59
60 // TODO(skia:12349): generic short/ushort
61 TYPE(GenType), TYPE(GenIType), TYPE(GenUType),
62 TYPE(GenHType), /* (GenSType) (GenUSType) */
63 TYPE(GenBType),
64 TYPE(IntLiteral),
65 TYPE(FloatLiteral),
66
67 TYPE(Vec), TYPE(IVec), TYPE(UVec),
68 TYPE(HVec), TYPE(SVec), TYPE(USVec),
69 TYPE(BVec),
70
71 TYPE(ColorFilter),
72 TYPE(Shader),
73 TYPE(Blender),
74 };
75
76 static constexpr BuiltinTypePtr kPrivateTypes[] = {
77 TYPE(Sampler2D), TYPE(SamplerExternalOES), TYPE(Sampler2DRect),
78
79 TYPE(SubpassInput), TYPE(SubpassInputMS),
80
81 TYPE(Sampler),
82 TYPE(Texture2D_sample),
83 TYPE(Texture2D), TYPE(ReadOnlyTexture2D), TYPE(WriteOnlyTexture2D),
84 TYPE(GenTexture2D), TYPE(ReadableTexture2D), TYPE(WritableTexture2D),
85
86 TYPE(AtomicUInt), TYPE(Atomic_uint),
87 };
88
89 #undef TYPE
90
91 struct ModuleLoader::Impl {
92 Impl();
93
94 void makeRootSymbolTable();
95
96 // This mutex is taken when ModuleLoader::Get is called, and released when the returned
97 // ModuleLoader object falls out of scope.
98 SkMutex fMutex;
99 const BuiltinTypes fBuiltinTypes;
100
101 std::unique_ptr<const Module> fRootModule;
102
103 std::unique_ptr<const Module> fSharedModule; // [Root] + Public intrinsics
104 std::unique_ptr<const Module> fGPUModule; // [Shared] + Non-public intrinsics/
105 // helper functions
106 std::unique_ptr<const Module> fVertexModule; // [GPU] + Vertex stage decls
107 std::unique_ptr<const Module> fFragmentModule; // [GPU] + Fragment stage decls
108 std::unique_ptr<const Module> fComputeModule; // [GPU] + Compute stage decls
109 std::unique_ptr<const Module> fGraphiteVertexModule; // [Vert] + Graphite vertex helpers
110 std::unique_ptr<const Module> fGraphiteFragmentModule; // [Frag] + Graphite fragment helpers
111 std::unique_ptr<const Module> fGraphiteVertexES2Module; // [Vert] + Graphite vertex ES2 helpers
112 std::unique_ptr<const Module> fGraphiteFragmentES2Module;//[Frag] + Graphite fragment ES2 " "
113
114 std::unique_ptr<const Module> fPublicModule; // [Shared] minus Private types +
115 // Runtime effect intrinsics
116 std::unique_ptr<const Module> fRuntimeShaderModule; // [Public] + Runtime shader decls
117 };
118
Get()119 ModuleLoader ModuleLoader::Get() {
120 static SkNoDestructor<ModuleLoader::Impl> sModuleLoaderImpl;
121 return ModuleLoader(*sModuleLoaderImpl);
122 }
123
ModuleLoader(ModuleLoader::Impl & m)124 ModuleLoader::ModuleLoader(ModuleLoader::Impl& m) : fModuleLoader(m) {
125 fModuleLoader.fMutex.acquire();
126 }
127
~ModuleLoader()128 ModuleLoader::~ModuleLoader() {
129 fModuleLoader.fMutex.release();
130 }
131
unloadModules()132 void ModuleLoader::unloadModules() {
133 fModuleLoader.fSharedModule = nullptr;
134 fModuleLoader.fGPUModule = nullptr;
135 fModuleLoader.fVertexModule = nullptr;
136 fModuleLoader.fFragmentModule = nullptr;
137 fModuleLoader.fComputeModule = nullptr;
138 fModuleLoader.fGraphiteVertexModule = nullptr;
139 fModuleLoader.fGraphiteFragmentModule = nullptr;
140 fModuleLoader.fPublicModule = nullptr;
141 fModuleLoader.fRuntimeShaderModule = nullptr;
142 }
143
Impl()144 ModuleLoader::Impl::Impl() {
145 this->makeRootSymbolTable();
146 }
147
compile_and_shrink(SkSL::Compiler * compiler,ProgramKind kind,ModuleType moduleType,std::string moduleSource,const Module * parent)148 static std::unique_ptr<Module> compile_and_shrink(SkSL::Compiler* compiler,
149 ProgramKind kind,
150 ModuleType moduleType,
151 std::string moduleSource,
152 const Module* parent) {
153 std::unique_ptr<Module> m = compiler->compileModule(kind,
154 moduleType,
155 std::move(moduleSource),
156 parent,
157 /*shouldInline=*/true);
158 if (!m) {
159 SK_ABORT("Unable to load module %s", ModuleTypeToString(moduleType));
160 }
161
162 // We can eliminate FunctionPrototypes without changing the meaning of the module; the function
163 // declaration is still safely in the symbol table. This only impacts our ability to recreate
164 // the input verbatim, which we don't care about at runtime.
165 m->fElements.erase(std::remove_if(m->fElements.begin(), m->fElements.end(),
166 [](const std::unique_ptr<ProgramElement>& element) {
167 switch (element->kind()) {
168 case ProgramElement::Kind::kFunction:
169 case ProgramElement::Kind::kGlobalVar:
170 case ProgramElement::Kind::kInterfaceBlock:
171 case ProgramElement::Kind::kStructDefinition:
172 // We need to preserve these.
173 return false;
174
175 case ProgramElement::Kind::kFunctionPrototype:
176 // These are already in the symbol table; the
177 // ProgramElement isn't needed anymore.
178 return true;
179
180 default:
181 SkDEBUGFAILF("Unsupported element: %s\n",
182 element->description().c_str());
183 return false;
184 }
185 }),
186 m->fElements.end());
187
188 m->fElements.shrink_to_fit();
189 return m;
190 }
191
builtinTypes()192 const BuiltinTypes& ModuleLoader::builtinTypes() {
193 return fModuleLoader.fBuiltinTypes;
194 }
195
rootModule()196 const Module* ModuleLoader::rootModule() {
197 return fModuleLoader.fRootModule.get();
198 }
199
addPublicTypeAliases(const SkSL::Module * module)200 void ModuleLoader::addPublicTypeAliases(const SkSL::Module* module) {
201 const SkSL::BuiltinTypes& types = this->builtinTypes();
202 SymbolTable* symbols = module->fSymbols.get();
203
204 // Add some aliases to the runtime effect modules so that it's friendlier, and more like GLSL.
205 symbols->addWithoutOwnershipOrDie(types.fVec2.get());
206 symbols->addWithoutOwnershipOrDie(types.fVec3.get());
207 symbols->addWithoutOwnershipOrDie(types.fVec4.get());
208
209 symbols->addWithoutOwnershipOrDie(types.fIVec2.get());
210 symbols->addWithoutOwnershipOrDie(types.fIVec3.get());
211 symbols->addWithoutOwnershipOrDie(types.fIVec4.get());
212
213 symbols->addWithoutOwnershipOrDie(types.fUVec2.get());
214 symbols->addWithoutOwnershipOrDie(types.fUVec3.get());
215 symbols->addWithoutOwnershipOrDie(types.fUVec4.get());
216
217 symbols->addWithoutOwnershipOrDie(types.fBVec2.get());
218 symbols->addWithoutOwnershipOrDie(types.fBVec3.get());
219 symbols->addWithoutOwnershipOrDie(types.fBVec4.get());
220
221 symbols->addWithoutOwnershipOrDie(types.fMat2.get());
222 symbols->addWithoutOwnershipOrDie(types.fMat3.get());
223 symbols->addWithoutOwnershipOrDie(types.fMat4.get());
224
225 symbols->addWithoutOwnershipOrDie(types.fMat2x2.get());
226 symbols->addWithoutOwnershipOrDie(types.fMat2x3.get());
227 symbols->addWithoutOwnershipOrDie(types.fMat2x4.get());
228 symbols->addWithoutOwnershipOrDie(types.fMat3x2.get());
229 symbols->addWithoutOwnershipOrDie(types.fMat3x3.get());
230 symbols->addWithoutOwnershipOrDie(types.fMat3x4.get());
231 symbols->addWithoutOwnershipOrDie(types.fMat4x2.get());
232 symbols->addWithoutOwnershipOrDie(types.fMat4x3.get());
233 symbols->addWithoutOwnershipOrDie(types.fMat4x4.get());
234
235 // Hide all the private symbols by aliasing them all to "invalid". This will prevent code from
236 // using built-in names like `sampler2D` as variable names.
237 for (BuiltinTypePtr privateType : kPrivateTypes) {
238 symbols->inject(Type::MakeAliasType((types.*privateType)->name(), *types.fInvalid));
239 }
240 }
241
loadPublicModule(SkSL::Compiler * compiler)242 const Module* ModuleLoader::loadPublicModule(SkSL::Compiler* compiler) {
243 if (!fModuleLoader.fPublicModule) {
244 const Module* sharedModule = this->loadSharedModule(compiler);
245 fModuleLoader.fPublicModule = compile_and_shrink(compiler,
246 ProgramKind::kFragment,
247 MODULE_DATA(sksl_public),
248 sharedModule);
249 this->addPublicTypeAliases(fModuleLoader.fPublicModule.get());
250 }
251 return fModuleLoader.fPublicModule.get();
252 }
253
loadPrivateRTShaderModule(SkSL::Compiler * compiler)254 const Module* ModuleLoader::loadPrivateRTShaderModule(SkSL::Compiler* compiler) {
255 if (!fModuleLoader.fRuntimeShaderModule) {
256 const Module* publicModule = this->loadPublicModule(compiler);
257 fModuleLoader.fRuntimeShaderModule = compile_and_shrink(compiler,
258 ProgramKind::kFragment,
259 MODULE_DATA(sksl_rt_shader),
260 publicModule);
261 }
262 return fModuleLoader.fRuntimeShaderModule.get();
263 }
264
loadSharedModule(SkSL::Compiler * compiler)265 const Module* ModuleLoader::loadSharedModule(SkSL::Compiler* compiler) {
266 if (!fModuleLoader.fSharedModule) {
267 const Module* rootModule = this->rootModule();
268 fModuleLoader.fSharedModule = compile_and_shrink(compiler,
269 ProgramKind::kFragment,
270 MODULE_DATA(sksl_shared),
271 rootModule);
272 }
273 return fModuleLoader.fSharedModule.get();
274 }
275
loadGPUModule(SkSL::Compiler * compiler)276 const Module* ModuleLoader::loadGPUModule(SkSL::Compiler* compiler) {
277 if (!fModuleLoader.fGPUModule) {
278 const Module* sharedModule = this->loadSharedModule(compiler);
279 fModuleLoader.fGPUModule = compile_and_shrink(compiler,
280 ProgramKind::kFragment,
281 MODULE_DATA(sksl_gpu),
282 sharedModule);
283 }
284 return fModuleLoader.fGPUModule.get();
285 }
286
loadFragmentModule(SkSL::Compiler * compiler)287 const Module* ModuleLoader::loadFragmentModule(SkSL::Compiler* compiler) {
288 if (!fModuleLoader.fFragmentModule) {
289 const Module* gpuModule = this->loadGPUModule(compiler);
290 fModuleLoader.fFragmentModule = compile_and_shrink(compiler,
291 ProgramKind::kFragment,
292 MODULE_DATA(sksl_frag),
293 gpuModule);
294 }
295 return fModuleLoader.fFragmentModule.get();
296 }
297
loadVertexModule(SkSL::Compiler * compiler)298 const Module* ModuleLoader::loadVertexModule(SkSL::Compiler* compiler) {
299 if (!fModuleLoader.fVertexModule) {
300 const Module* gpuModule = this->loadGPUModule(compiler);
301 fModuleLoader.fVertexModule = compile_and_shrink(compiler,
302 ProgramKind::kVertex,
303 MODULE_DATA(sksl_vert),
304 gpuModule);
305 }
306 return fModuleLoader.fVertexModule.get();
307 }
308
loadComputeModule(SkSL::Compiler * compiler)309 const Module* ModuleLoader::loadComputeModule(SkSL::Compiler* compiler) {
310 if (!fModuleLoader.fComputeModule) {
311 const Module* gpuModule = this->loadGPUModule(compiler);
312 fModuleLoader.fComputeModule = compile_and_shrink(compiler,
313 ProgramKind::kCompute,
314 MODULE_DATA(sksl_compute),
315 gpuModule);
316 }
317 return fModuleLoader.fComputeModule.get();
318 }
319
loadGraphiteFragmentModule(SkSL::Compiler * compiler)320 const Module* ModuleLoader::loadGraphiteFragmentModule(SkSL::Compiler* compiler) {
321 if (!fModuleLoader.fGraphiteFragmentModule) {
322 const Module* fragmentModule = this->loadFragmentModule(compiler);
323 fModuleLoader.fGraphiteFragmentModule = compile_and_shrink(compiler,
324 ProgramKind::kGraphiteFragment,
325 MODULE_DATA(sksl_graphite_frag),
326 fragmentModule);
327 }
328 return fModuleLoader.fGraphiteFragmentModule.get();
329 }
330
loadGraphiteFragmentES2Module(SkSL::Compiler * compiler)331 const Module* ModuleLoader::loadGraphiteFragmentES2Module(SkSL::Compiler* compiler) {
332 if (!fModuleLoader.fGraphiteFragmentES2Module) {
333 const Module* fragmentModule = this->loadFragmentModule(compiler);
334 fModuleLoader.fGraphiteFragmentES2Module =
335 compile_and_shrink(compiler,
336 ProgramKind::kGraphiteFragmentES2,
337 MODULE_DATA(sksl_graphite_frag_es2),
338 fragmentModule);
339 }
340 return fModuleLoader.fGraphiteFragmentES2Module.get();
341 }
342
loadGraphiteVertexModule(SkSL::Compiler * compiler)343 const Module* ModuleLoader::loadGraphiteVertexModule(SkSL::Compiler* compiler) {
344 if (!fModuleLoader.fGraphiteVertexModule) {
345 const Module* vertexModule = this->loadVertexModule(compiler);
346 fModuleLoader.fGraphiteVertexModule = compile_and_shrink(compiler,
347 ProgramKind::kGraphiteVertex,
348 MODULE_DATA(sksl_graphite_vert),
349 vertexModule);
350 }
351 return fModuleLoader.fGraphiteVertexModule.get();
352 }
353
loadGraphiteVertexES2Module(SkSL::Compiler * compiler)354 const Module* ModuleLoader::loadGraphiteVertexES2Module(SkSL::Compiler* compiler) {
355 if (!fModuleLoader.fGraphiteVertexES2Module) {
356 const Module* vertexModule = this->loadVertexModule(compiler);
357 fModuleLoader.fGraphiteVertexES2Module =
358 compile_and_shrink(compiler,
359 ProgramKind::kGraphiteVertexES2,
360 MODULE_DATA(sksl_graphite_vert_es2),
361 vertexModule);
362 }
363 return fModuleLoader.fGraphiteVertexES2Module.get();
364 }
365
makeRootSymbolTable()366 void ModuleLoader::Impl::makeRootSymbolTable() {
367 auto rootModule = std::make_unique<Module>();
368 rootModule->fSymbols = std::make_unique<SymbolTable>(/*builtin=*/true);
369
370 for (BuiltinTypePtr rootType : kRootTypes) {
371 rootModule->fSymbols->addWithoutOwnershipOrDie((fBuiltinTypes.*rootType).get());
372 }
373
374 for (BuiltinTypePtr privateType : kPrivateTypes) {
375 rootModule->fSymbols->addWithoutOwnershipOrDie((fBuiltinTypes.*privateType).get());
376 }
377
378 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
379 // treat it as builtin (ie, no need to clone it into the Program).
380 rootModule->fSymbols->addOrDie(Variable::Make(/*pos=*/Position(),
381 /*modifiersPosition=*/Position(),
382 Layout{},
383 ModifierFlag::kNone,
384 fBuiltinTypes.fSkCaps.get(),
385 "sk_Caps",
386 /*mangledName=*/"",
387 /*builtin=*/false,
388 Variable::Storage::kGlobal));
389 fRootModule = std::move(rootModule);
390 }
391
392 } // namespace SkSL
393