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