Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
constexpr int SK_CLOCKWISE_BUILTIN
constexpr int SK_LASTFRAGCOLOR_BUILTIN
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
constexpr int SK_FRAGCOORD_BUILTIN
const Context & fContext
std::vector< const ProgramElement * > fNewElements
const SymbolTable & fSymbols
static constexpr const char FRAGCOLOR_NAME[]
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
GlobalVarDeclaration * globalVarDeclaration() const
virtual InterfaceBlock * interfaceBlock() const
static bool b
struct MyStruct a[10]
switch(prop_id)
void FindAndDeclareBuiltinVariables(Program &program)
ProgramSettings fSettings
static bool IsFragment(ProgramKind kind)
std::vector< std::unique_ptr< ProgramElement > > fOwnedElements
std::shared_ptr< Context > fContext
std::unique_ptr< ProgramUsage > fUsage
ProgramInterface fInterface
ProgramInterface Interface
std::unique_ptr< SymbolTable > fSymbols
std::vector< const ProgramElement * > fSharedElements
std::unique_ptr< ProgramConfig > fConfig