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