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