xref: /aosp_15_r20/external/skia/src/sksl/transform/SkSLFindAndDeclareBuiltinStructs.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2024 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 "include/core/SkTypes.h"
9 #include "src/core/SkTHash.h"
10 #include "src/sksl/SkSLContext.h"  // IWYU pragma: keep
11 #include "src/sksl/SkSLModule.h"
12 #include "src/sksl/analysis/SkSLProgramUsage.h"
13 #include "src/sksl/ir/SkSLProgram.h"
14 #include "src/sksl/ir/SkSLProgramElement.h"
15 #include "src/sksl/ir/SkSLStructDefinition.h"
16 #include "src/sksl/ir/SkSLSymbol.h"
17 #include "src/sksl/ir/SkSLType.h"
18 #include "src/sksl/transform/SkSLTransform.h"
19 
20 #include <memory>
21 #include <type_traits>
22 #include <vector>
23 
24 using namespace skia_private;
25 
26 namespace SkSL {
27 
contains_builtin_struct(const ProgramUsage & usage)28 static bool contains_builtin_struct(const ProgramUsage& usage) {
29     for (const auto& [symbol, count] : usage.fStructCounts) {
30         const Type& type = symbol->as<Type>();
31         if (type.isBuiltin()) {
32             return true;
33         }
34     }
35     return false;
36 }
37 
get_struct_definitions_from_module(Program & program,const Module & module,std::vector<const ProgramElement * > * addedStructDefs)38 static void get_struct_definitions_from_module(
39         Program& program,
40         const Module& module,
41         std::vector<const ProgramElement*>* addedStructDefs) {
42     // We want to start at the root module and work our way towards the Program, so that structs
43     // are added to the program in the same order that they appear in the Module hierarchy.
44     if (module.fParent) {
45         get_struct_definitions_from_module(program, *module.fParent, addedStructDefs);
46     }
47 
48     // Find StructDefinitions from this Module that are used by the program, and copy them into our
49     // array of shared elements.
50     for (const std::unique_ptr<ProgramElement>& elem : module.fElements) {
51         if (elem->is<StructDefinition>()) {
52             const StructDefinition& structDef = elem->as<StructDefinition>();
53             int* structCount = program.fUsage->fStructCounts.find(&structDef.type());
54             if (structCount && *structCount > 0) {
55                 addedStructDefs->push_back(&structDef);
56             }
57         }
58     }
59 }
60 
FindAndDeclareBuiltinStructs(Program & program)61 void Transform::FindAndDeclareBuiltinStructs(Program& program) {
62     // Check if the program references any builtin structs at all.
63     if (contains_builtin_struct(*program.fUsage)) {
64         // Visit all of our modules to find struct definitions that were referenced by ProgramUsage.
65         std::vector<const ProgramElement*> addedStructDefs;
66         get_struct_definitions_from_module(program, *program.fContext->fModule, &addedStructDefs);
67 
68         // Copy the struct definitions into our shared elements, and update ProgramUsage to match.
69         program.fSharedElements.insert(program.fSharedElements.begin(),
70                                        addedStructDefs.begin(), addedStructDefs.end());
71 
72         for (const ProgramElement* element : addedStructDefs) {
73             program.fUsage->add(*element);
74         }
75     }
76 }
77 
78 }  // namespace SkSL
79