• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/sksl/ir/SkSLVariable.h"
9 
10 #include "include/private/SkSLIRNode.h"
11 #include "include/private/SkSLLayout.h"
12 #include "include/sksl/SkSLErrorReporter.h"
13 #include "src/base/SkStringView.h"
14 #include "src/sksl/SkSLCompiler.h"
15 #include "src/sksl/SkSLContext.h"
16 #include "src/sksl/SkSLMangler.h"
17 #include "src/sksl/SkSLModifiersPool.h"
18 #include "src/sksl/SkSLProgramSettings.h"
19 #include "src/sksl/SkSLThreadContext.h"
20 #include "src/sksl/ir/SkSLExpression.h"
21 #include "src/sksl/ir/SkSLInterfaceBlock.h"
22 #include "src/sksl/ir/SkSLSymbolTable.h"
23 #include "src/sksl/ir/SkSLVarDeclarations.h"
24 
25 #include <type_traits>
26 #include <utility>
27 
28 namespace SkSL {
29 
~Variable()30 Variable::~Variable() {
31     // Unhook this Variable from its associated VarDeclaration, since we're being deleted.
32     if (VarDeclaration* declaration = this->varDeclaration()) {
33         declaration->detachDeadVariable();
34     }
35 }
36 
~InterfaceBlockVariable()37 InterfaceBlockVariable::~InterfaceBlockVariable() {
38     // Unhook this Variable from its associated InterfaceBlock, since we're being deleted.
39     if (fInterfaceBlockElement) {
40         fInterfaceBlockElement->detachDeadVariable();
41     }
42 }
43 
initialValue() const44 const Expression* Variable::initialValue() const {
45     VarDeclaration* declaration = this->varDeclaration();
46     return declaration ? declaration->value().get() : nullptr;
47 }
48 
varDeclaration() const49 VarDeclaration* Variable::varDeclaration() const {
50     if (!fDeclaringElement) {
51         return nullptr;
52     }
53     SkASSERT(fDeclaringElement->is<VarDeclaration>() ||
54              fDeclaringElement->is<GlobalVarDeclaration>());
55     return fDeclaringElement->is<GlobalVarDeclaration>()
56                ? &fDeclaringElement->as<GlobalVarDeclaration>().varDeclaration()
57                : &fDeclaringElement->as<VarDeclaration>();
58 }
59 
globalVarDeclaration() const60 GlobalVarDeclaration* Variable::globalVarDeclaration() const {
61     if (!fDeclaringElement) {
62         return nullptr;
63     }
64     SkASSERT(fDeclaringElement->is<VarDeclaration>() ||
65              fDeclaringElement->is<GlobalVarDeclaration>());
66     return fDeclaringElement->is<GlobalVarDeclaration>()
67                ? &fDeclaringElement->as<GlobalVarDeclaration>()
68                : nullptr;
69 }
70 
setVarDeclaration(VarDeclaration * declaration)71 void Variable::setVarDeclaration(VarDeclaration* declaration) {
72     SkASSERT(!fDeclaringElement || this == declaration->var());
73     if (!fDeclaringElement) {
74         fDeclaringElement = declaration;
75     }
76 }
77 
setGlobalVarDeclaration(GlobalVarDeclaration * global)78 void Variable::setGlobalVarDeclaration(GlobalVarDeclaration* global) {
79     SkASSERT(!fDeclaringElement || this == global->varDeclaration().var());
80     fDeclaringElement = global;
81 }
82 
mangledName() const83 std::string Variable::mangledName() const {
84     // Only private variables need to use name mangling.
85     std::string_view name = this->name();
86     if (!skstd::starts_with(name, '$')) {
87         return std::string(name);
88     }
89 
90     // The $ prefix will fail to compile in GLSL, so replace it with `sk_Priv`.
91     name.remove_prefix(1);
92     return "sk_Priv" + std::string(name);
93 }
94 
Convert(const Context & context,Position pos,Position modifiersPos,const Modifiers & modifiers,const Type * baseType,Position namePos,std::string_view name,bool isArray,std::unique_ptr<Expression> arraySize,Variable::Storage storage)95 std::unique_ptr<Variable> Variable::Convert(const Context& context,
96                                             Position pos,
97                                             Position modifiersPos,
98                                             const Modifiers& modifiers,
99                                             const Type* baseType,
100                                             Position namePos,
101                                             std::string_view name,
102                                             bool isArray,
103                                             std::unique_ptr<Expression> arraySize,
104                                             Variable::Storage storage) {
105     if (modifiers.fLayout.fLocation == 0 && modifiers.fLayout.fIndex == 0 &&
106         (modifiers.fFlags & Modifiers::kOut_Flag) &&
107         ProgramConfig::IsFragment(context.fConfig->fKind) && name != Compiler::FRAGCOLOR_NAME) {
108         context.fErrors->error(modifiersPos,
109                                "out location=0, index=0 is reserved for sk_FragColor");
110     }
111     if (baseType->isUnsizedArray() && storage != Variable::Storage::kInterfaceBlock) {
112         context.fErrors->error(pos, "unsized arrays are not permitted here");
113     }
114     if (ProgramConfig::IsCompute(ThreadContext::Context().fConfig->fKind) &&
115             modifiers.fLayout.fBuiltin == -1) {
116         if (storage == Variable::Storage::kGlobal) {
117             if (modifiers.fFlags & Modifiers::kIn_Flag) {
118                 context.fErrors->error(pos, "pipeline inputs not permitted in compute shaders");
119             } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
120                 context.fErrors->error(pos, "pipeline outputs not permitted in compute shaders");
121             }
122         }
123     }
124 
125     return Make(context, pos, modifiersPos, modifiers, baseType, name, isArray,
126                 std::move(arraySize), storage);
127 }
128 
Make(const Context & context,Position pos,Position modifiersPos,const Modifiers & modifiers,const Type * baseType,std::string_view name,bool isArray,std::unique_ptr<Expression> arraySize,Variable::Storage storage)129 std::unique_ptr<Variable> Variable::Make(const Context& context,
130                                          Position pos,
131                                          Position modifiersPos,
132                                          const Modifiers& modifiers,
133                                          const Type* baseType,
134                                          std::string_view name,
135                                          bool isArray,
136                                          std::unique_ptr<Expression> arraySize,
137                                          Variable::Storage storage) {
138     const Type* type = baseType;
139     int arraySizeValue = 0;
140     if (isArray) {
141         SkASSERT(arraySize);
142         arraySizeValue = type->convertArraySize(context, pos, std::move(arraySize));
143         if (!arraySizeValue) {
144             return nullptr;
145         }
146         type = ThreadContext::SymbolTable()->addArrayDimension(type, arraySizeValue);
147     }
148     if (type->componentType().isInterfaceBlock()) {
149         return std::make_unique<InterfaceBlockVariable>(pos,
150                                                         modifiersPos,
151                                                         context.fModifiersPool->add(modifiers),
152                                                         name,
153                                                         type,
154                                                         context.fConfig->fIsBuiltinCode,
155                                                         storage);
156     } else {
157         return std::make_unique<Variable>(pos,
158                                           modifiersPos,
159                                           context.fModifiersPool->add(modifiers),
160                                           name,
161                                           type,
162                                           context.fConfig->fIsBuiltinCode,
163                                           storage);
164     }
165 }
166 
MakeScratchVariable(const Context & context,Mangler & mangler,std::string_view baseName,const Type * type,const Modifiers & modifiers,SymbolTable * symbolTable,std::unique_ptr<Expression> initialValue)167 Variable::ScratchVariable Variable::MakeScratchVariable(const Context& context,
168                                                         Mangler& mangler,
169                                                         std::string_view baseName,
170                                                         const Type* type,
171                                                         const Modifiers& modifiers,
172                                                         SymbolTable* symbolTable,
173                                                         std::unique_ptr<Expression> initialValue) {
174     // $floatLiteral or $intLiteral aren't real types that we can use for scratch variables, so
175     // replace them if they ever appear here. If this happens, we likely forgot to coerce a type
176     // somewhere during compilation.
177     if (type->isLiteral()) {
178         SkDEBUGFAIL("found a $literal type in MakeScratchVariable");
179         type = &type->scalarTypeForLiteral();
180     }
181 
182     // Out-parameters aren't supported.
183     SkASSERT(!(modifiers.fFlags & Modifiers::kOut_Flag));
184 
185     // Provide our new variable with a unique name, and add it to our symbol table.
186     const std::string* name =
187             symbolTable->takeOwnershipOfString(mangler.uniqueName(baseName, symbolTable));
188 
189     // Create our new variable and add it to the symbol table.
190     ScratchVariable result;
191     auto var = std::make_unique<Variable>(initialValue ? initialValue->fPosition : Position(),
192                                           /*modifiersPosition=*/Position(),
193                                           context.fModifiersPool->add(Modifiers{}),
194                                           name->c_str(),
195                                           type,
196                                           symbolTable->isBuiltin(),
197                                           Variable::Storage::kLocal);
198 
199     // If we are creating an array type, reduce it to base type plus array-size.
200     int arraySize = 0;
201     if (type->isArray()) {
202         arraySize = type->columns();
203         type = &type->componentType();
204     }
205     // Create our variable declaration.
206     result.fVarDecl = VarDeclaration::Make(context, var.get(), type, arraySize,
207                                            std::move(initialValue));
208     result.fVarSymbol = symbolTable->add(std::move(var));
209     return result;
210 }
211 
212 } // namespace SkSL
213