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