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