xref: /aosp_15_r20/external/skia/src/sksl/SkSLModuleLoader.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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