Flutter Engine
The Flutter Engine
SkSLFindAndDeclareBuiltinVariables.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 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
10#include "src/core/SkTHash.h"
29
30#include <algorithm>
31#include <memory>
32#include <string_view>
33#include <vector>
34
35namespace SkSL {
36namespace Transform {
37namespace {
38
39class BuiltinVariableScanner {
40public:
41 BuiltinVariableScanner(const Context& context, const SymbolTable& symbols)
42 : fContext(context)
43 , fSymbols(symbols) {}
44
45 void addDeclaringElement(const ProgramElement* decl) {
46 // Make sure we only add a built-in variable once. We only have a small handful of built-in
47 // variables to declare, so linear search here is good enough.
48 if (std::find(fNewElements.begin(), fNewElements.end(), decl) == fNewElements.end()) {
49 fNewElements.push_back(decl);
50 }
51 }
52
53 void addDeclaringElement(const Symbol* symbol) {
54 if (!symbol || !symbol->is<Variable>()) {
55 return;
56 }
57 const Variable& var = symbol->as<Variable>();
58 if (const GlobalVarDeclaration* decl = var.globalVarDeclaration()) {
59 this->addDeclaringElement(decl);
60 } else if (const InterfaceBlock* block = var.interfaceBlock()) {
61 this->addDeclaringElement(block);
62 } else {
63 // Double-check that this variable isn't associated with a global or an interface block.
64 // (Locals and parameters will come along naturally as part of the associated function.)
67 "%.*s", (int)var.name().size(), var.name().data());
68 }
69 }
70
71 void addImplicitFragColorWrite(SkSpan<const std::unique_ptr<ProgramElement>> elements) {
72 for (const std::unique_ptr<ProgramElement>& pe : elements) {
73 if (!pe->is<FunctionDefinition>()) {
74 continue;
75 }
76 const FunctionDefinition& funcDef = pe->as<FunctionDefinition>();
77 if (funcDef.declaration().isMain()) {
78 if (funcDef.declaration().returnType().matches(*fContext.fTypes.fHalf4)) {
79 // We synthesize writes to sk_FragColor if main() returns a color, even if it's
80 // otherwise unreferenced.
81 this->addDeclaringElement(fSymbols.findBuiltinSymbol(Compiler::FRAGCOLOR_NAME));
82 }
83 // Now that main() has been found, we can stop scanning.
84 break;
85 }
86 }
87 }
88
89 static std::string_view GlobalVarBuiltinName(const ProgramElement& elem) {
90 return elem.as<GlobalVarDeclaration>().varDeclaration().var()->name();
91 }
92
93 static std::string_view InterfaceBlockName(const ProgramElement& elem) {
94 return elem.as<InterfaceBlock>().instanceName();
95 }
96
97 void sortNewElements() {
98 std::sort(fNewElements.begin(),
99 fNewElements.end(),
100 [](const ProgramElement* a, const ProgramElement* b) {
101 if (a->kind() != b->kind()) {
102 return a->kind() < b->kind();
103 }
104 switch (a->kind()) {
105 case ProgramElement::Kind::kGlobalVar:
106 SkASSERT(a == b ||
107 GlobalVarBuiltinName(*a) != GlobalVarBuiltinName(*b));
108 return GlobalVarBuiltinName(*a) < GlobalVarBuiltinName(*b);
109
110 case ProgramElement::Kind::kInterfaceBlock:
111 SkASSERT(a == b || InterfaceBlockName(*a) != InterfaceBlockName(*b));
112 return InterfaceBlockName(*a) < InterfaceBlockName(*b);
113
114 default:
115 SkUNREACHABLE;
116 }
117 });
118 }
119
121 const SymbolTable& fSymbols;
122 std::vector<const ProgramElement*> fNewElements;
123};
124
125} // namespace
126
128 using Interface = Program::Interface;
129 const Context& context = *program.fContext;
130 const SymbolTable& symbols = *program.fSymbols;
131 BuiltinVariableScanner scanner(context, symbols);
132
133 if (ProgramConfig::IsFragment(program.fConfig->fKind)) {
134 // Find main() in the program and check its return type.
135 // If it's half4, we treat that as an implicit write to sk_FragColor and add a reference.
136 scanner.addImplicitFragColorWrite(program.fOwnedElements);
137 }
138
139 // Scan all the variables used by the program and declare any built-ins.
140 for (const auto& [var, counts] : program.fUsage->fVariableCounts) {
141 if (var->isBuiltin()) {
142 scanner.addDeclaringElement(var);
143
144 switch (var->layout().fBuiltin) {
145 // Set the RTFlip program input if we find sk_FragCoord or sk_Clockwise.
147 if (!context.fConfig->fSettings.fForceNoRTFlip) {
148 program.fInterface.fRTFlipUniform |= Interface::kRTFlip_FragCoord;
149 }
150 break;
151
153 if (!context.fConfig->fSettings.fForceNoRTFlip) {
154 program.fInterface.fRTFlipUniform |= Interface::kRTFlip_Clockwise;
155 }
156 break;
157
158 // Set the UseLastFragColor program input if we find sk_LastFragColor.
159 // Metal and Dawn define this as a program input, rather than a global variable.
161 program.fInterface.fUseLastFragColor = true;
162 break;
163
164 // Set secondary color output if we find sk_SecondaryFragColor.
166 program.fInterface.fOutputSecondaryColor = true;
167 break;
168 }
169 }
170 }
171
172 // Sort the referenced builtin functions into a consistent order; otherwise our output will
173 // become non-deterministic. The exact order isn't particularly important.
174 scanner.sortNewElements();
175
176 // Add all the newly-declared elements to the program, and update ProgramUsage to match.
177 program.fSharedElements.insert(program.fSharedElements.begin(),
178 scanner.fNewElements.begin(),
179 scanner.fNewElements.end());
180
181 for (const ProgramElement* element : scanner.fNewElements) {
182 program.fUsage->add(*element);
183 }
184}
185
186} // namespace Transform
187} // namespace SkSL
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
constexpr int SK_CLOCKWISE_BUILTIN
Definition: SkSLCompiler.h:31
constexpr int SK_LASTFRAGCOLOR_BUILTIN
Definition: SkSLCompiler.h:28
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
Definition: SkSLCompiler.h:29
constexpr int SK_FRAGCOORD_BUILTIN
Definition: SkSLCompiler.h:30
const Context & fContext
std::vector< const ProgramElement * > fNewElements
const SymbolTable & fSymbols
int find(T *array, int N, T item)
static constexpr const char FRAGCOLOR_NAME[]
Definition: SkSLCompiler.h:71
ProgramConfig * fConfig
Definition: SkSLContext.h:33
const FunctionDeclaration & declaration() const
bool is() const
Definition: SkSLIRNode.h:124
const T & as() const
Definition: SkSLIRNode.h:133
std::string_view name() const
Definition: SkSLSymbol.h:51
bool matches(const Type &other) const
Definition: SkSLType.h:269
Storage storage() const
Definition: SkSLVariable.h:103
GlobalVarDeclaration * globalVarDeclaration() const
virtual InterfaceBlock * interfaceBlock() const
Definition: SkSLVariable.h:125
static bool b
struct MyStruct a[10]
switch(prop_id)
void FindAndDeclareBuiltinVariables(Program &program)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core counts
Definition: switches.h:239
skgpu::graphite::Transform Transform
ProgramSettings fSettings
static bool IsFragment(ProgramKind kind)
std::vector< std::unique_ptr< ProgramElement > > fOwnedElements
Definition: SkSLProgram.h:161
std::shared_ptr< Context > fContext
Definition: SkSLProgram.h:154
std::unique_ptr< ProgramUsage > fUsage
Definition: SkSLProgram.h:155
ProgramInterface fInterface
Definition: SkSLProgram.h:165
ProgramInterface Interface
Definition: SkSLProgram.h:167
std::unique_ptr< SymbolTable > fSymbols
Definition: SkSLProgram.h:158
std::vector< const ProgramElement * > fSharedElements
Definition: SkSLProgram.h:164
std::unique_ptr< ProgramConfig > fConfig
Definition: SkSLProgram.h:153