• 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 
8 #include "include/core/SkTypes.h"
9 #include "src/core/SkTHash.h"
10 #include "src/sksl/SkSLContext.h"
11 #include "src/sksl/SkSLIntrinsicList.h"
12 #include "src/sksl/SkSLProgramSettings.h"
13 #include "src/sksl/analysis/SkSLProgramUsage.h"
14 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
15 #include "src/sksl/ir/SkSLFunctionDefinition.h"
16 #include "src/sksl/ir/SkSLProgram.h"
17 #include "src/sksl/transform/SkSLTransform.h"
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <memory>
22 #include <string>
23 #include <string_view>
24 #include <vector>
25 
26 namespace SkSL {
27 
28 class ProgramElement;
29 
FindAndDeclareBuiltinFunctions(Program & program)30 void Transform::FindAndDeclareBuiltinFunctions(Program& program) {
31     ProgramUsage* usage = program.fUsage.get();
32     Context& context = *program.fContext;
33 
34     std::vector<const FunctionDefinition*> addedBuiltins;
35     for (;;) {
36         // Find all the built-ins referenced by the program but not yet included in the code.
37         size_t numBuiltinsAtStart = addedBuiltins.size();
38         for (const auto& [fn, count] : usage->fCallCounts) {
39             if (!fn->isBuiltin() || count == 0) {
40                 // Not a built-in; skip it.
41                 continue;
42             }
43             if (fn->intrinsicKind() == k_dFdy_IntrinsicKind) {
44                 // Programs that invoke the `dFdy` intrinsic will need the RTFlip input.
45                 program.fInputs.fUseFlipRTUniform = !context.fConfig->fSettings.fForceNoRTFlip;
46             }
47             if (const FunctionDefinition* builtinDef = fn->definition()) {
48                 // Make sure we only add a built-in function once. We rarely add more than a handful
49                 // of builtin functions, so linear search here is good enough.
50                 if (std::find(addedBuiltins.begin(), addedBuiltins.end(), builtinDef) ==
51                     addedBuiltins.end()) {
52                     addedBuiltins.push_back(builtinDef);
53                 }
54             }
55         }
56 
57         if (addedBuiltins.size() == numBuiltinsAtStart) {
58             // If we didn't reference any more built-in functions than before, we're done.
59             break;
60         }
61 
62         // Sort the referenced builtin functions into a consistent order; otherwise our output will
63         // become non-deterministic. The exact order isn't particularly important; we sort backwards
64         // because we add elements to the shared-elements in reverse order at the end.
65         std::sort(addedBuiltins.begin() + numBuiltinsAtStart,
66                   addedBuiltins.end(),
67                   [](const FunctionDefinition* aDefinition, const FunctionDefinition* bDefinition) {
68                       const FunctionDeclaration& a = aDefinition->declaration();
69                       const FunctionDeclaration& b = bDefinition->declaration();
70                       if (a.name() != b.name()) {
71                           return a.name() > b.name();
72                       }
73                       return a.description() > b.description();
74                   });
75 
76         // Update the ProgramUsage to track all these newly discovered functions.
77         int usageCallCounts = usage->fCallCounts.count();
78 
79         for (size_t index = numBuiltinsAtStart; index < addedBuiltins.size(); ++index) {
80             usage->add(*addedBuiltins[index]);
81         }
82 
83         if (usage->fCallCounts.count() == usageCallCounts) {
84             // If we aren't making any more unique function calls than before, we're done.
85             break;
86         }
87     }
88 
89     // Insert the new functions into the program's shared elements, right at the front.
90     // They are added in reverse so that the deepest dependencies are added to the top.
91     program.fSharedElements.insert(program.fSharedElements.begin(),
92                                    addedBuiltins.rbegin(), addedBuiltins.rend());
93 }
94 
95 }  // namespace SkSL
96