• 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/SkSLVarDeclarations.h"
9 
10 #include "include/sksl/SkSLErrorReporter.h"
11 #include "src/sksl/SkSLAnalysis.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLContext.h"
14 #include "src/sksl/SkSLProgramSettings.h"
15 #include "src/sksl/SkSLThreadContext.h"
16 
17 namespace SkSL {
18 
clone() const19 std::unique_ptr<Statement> VarDeclaration::clone() const {
20     return std::make_unique<VarDeclaration>(&this->var(),
21                                             &this->baseType(),
22                                             fArraySize,
23                                             this->value() ? this->value()->clone() : nullptr);
24 }
25 
description() const26 String VarDeclaration::description() const {
27     String result = this->var().modifiers().description() + this->baseType().description() + " " +
28                     this->var().name();
29     if (this->arraySize() > 0) {
30         result.appendf("[%d]", this->arraySize());
31     }
32     if (this->value()) {
33         result += " = " + this->value()->description();
34     }
35     result += ";";
36     return result;
37 }
38 
ErrorCheck(const Context & context,int line,const Modifiers & modifiers,const Type * baseType,Variable::Storage storage)39 void VarDeclaration::ErrorCheck(const Context& context, int line, const Modifiers& modifiers,
40         const Type* baseType, Variable::Storage storage) {
41     if (*baseType == *context.fTypes.fInvalid) {
42         context.fErrors->error(line, "invalid type");
43         return;
44     }
45     if (context.fConfig->strictES2Mode() && baseType->isArray()) {
46         context.fErrors->error(line, "array size must appear after variable name");
47     }
48 
49     if (baseType->componentType().isOpaque() && storage != Variable::Storage::kGlobal) {
50         context.fErrors->error(line,
51                 "variables of type '" + baseType->displayName() + "' must be global");
52     }
53     if ((modifiers.fFlags & Modifiers::kIn_Flag) && baseType->isMatrix()) {
54         context.fErrors->error(line, "'in' variables may not have matrix type");
55     }
56     if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kUniform_Flag)) {
57         context.fErrors->error(line, "'in uniform' variables not permitted");
58     }
59     if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
60         if (modifiers.fFlags & Modifiers::kIn_Flag) {
61             context.fErrors->error(line, "'in' variables not permitted in runtime effects");
62         }
63     }
64     if (baseType->isEffectChild() && !(modifiers.fFlags & Modifiers::kUniform_Flag)) {
65         context.fErrors->error(line,
66                 "variables of type '" + baseType->displayName() + "' must be uniform");
67     }
68     if (modifiers.fLayout.fFlags & Layout::kSRGBUnpremul_Flag) {
69         if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
70             context.fErrors->error(line, "'srgb_unpremul' is only permitted in runtime effects");
71         }
72         if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) {
73             context.fErrors->error(line,
74                     "'srgb_unpremul' is only permitted on 'uniform' variables");
75         }
76         auto validColorXformType = [](const Type& t) {
77             return t.isVector() && t.componentType().isFloat() &&
78                    (t.columns() == 3 || t.columns() == 4);
79         };
80         if (!validColorXformType(*baseType) && !(baseType->isArray() &&
81                                                  validColorXformType(baseType->componentType()))) {
82             context.fErrors->error(line, "'srgb_unpremul' is only permitted on half3, half4, "
83                     "float3, or float4 variables");
84         }
85     }
86     int permitted = Modifiers::kConst_Flag | Modifiers::kHighp_Flag | Modifiers::kMediump_Flag |
87                     Modifiers::kLowp_Flag;
88     if (storage == Variable::Storage::kGlobal) {
89         permitted |= Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
90                      Modifiers::kFlat_Flag | Modifiers::kNoPerspective_Flag;
91     }
92     // TODO(skbug.com/11301): Migrate above checks into building a mask of permitted layout flags
93     modifiers.checkPermitted(context, line, permitted, /*permittedLayoutFlags=*/~0);
94 }
95 
ErrorCheckAndCoerce(const Context & context,const Variable & var,std::unique_ptr<Expression> & value)96 bool VarDeclaration::ErrorCheckAndCoerce(const Context& context, const Variable& var,
97         std::unique_ptr<Expression>& value) {
98     const Type* baseType = &var.type();
99     if (baseType->isArray()) {
100         baseType = &baseType->componentType();
101     }
102     ErrorCheck(context, var.fLine, var.modifiers(), baseType, var.storage());
103     if (value) {
104         if (var.type().isOpaque()) {
105             context.fErrors->error(value->fLine,
106                     "opaque type '" + var.type().name() + "' cannot use initializer expressions");
107             return false;
108         }
109         if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
110             context.fErrors->error(value->fLine,
111                     "'in' variables cannot use initializer expressions");
112             return false;
113         }
114         if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
115             context.fErrors->error(value->fLine,
116                     "'uniform' variables cannot use initializer expressions");
117             return false;
118         }
119         if (var.storage() == Variable::Storage::kInterfaceBlock) {
120             context.fErrors->error(value->fLine,
121                     "initializers are not permitted on interface block fields");
122             return false;
123         }
124         value = var.type().coerceExpression(std::move(value), context);
125         if (!value) {
126             return false;
127         }
128     }
129     if (var.modifiers().fFlags & Modifiers::kConst_Flag) {
130         if (!value) {
131             context.fErrors->error(var.fLine, "'const' variables must be initialized");
132             return false;
133         }
134         if (!Analysis::IsConstantExpression(*value)) {
135             context.fErrors->error(value->fLine,
136                     "'const' variable initializer must be a constant expression");
137             return false;
138         }
139     }
140     if (var.storage() == Variable::Storage::kInterfaceBlock) {
141         if (var.type().isOpaque()) {
142             context.fErrors->error(var.fLine, "opaque type '" + var.type().name() +
143                     "' is not permitted in an interface block");
144             return false;
145         }
146     }
147     if (var.storage() == Variable::Storage::kGlobal) {
148         if (value && !Analysis::IsConstantExpression(*value)) {
149             context.fErrors->error(value->fLine,
150                     "global variable initializer must be a constant expression");
151             return false;
152         }
153     }
154     return true;
155 }
156 
Convert(const Context & context,std::unique_ptr<Variable> var,std::unique_ptr<Expression> value,bool addToSymbolTable)157 std::unique_ptr<Statement> VarDeclaration::Convert(const Context& context,
158         std::unique_ptr<Variable> var, std::unique_ptr<Expression> value, bool addToSymbolTable) {
159     if (!ErrorCheckAndCoerce(context, *var, value)) {
160         return nullptr;
161     }
162     const Type* baseType = &var->type();
163     int arraySize = 0;
164     if (baseType->isArray()) {
165         arraySize = baseType->columns();
166         baseType = &baseType->componentType();
167     }
168     std::unique_ptr<Statement> varDecl = VarDeclaration::Make(context, var.get(), baseType,
169             arraySize, std::move(value));
170     if (!varDecl) {
171         return nullptr;
172     }
173 
174     // Detect the declaration of magical variables.
175     if ((var->storage() == Variable::Storage::kGlobal) && var->name() == Compiler::FRAGCOLOR_NAME) {
176         // Silently ignore duplicate definitions of `sk_FragColor`.
177         const Symbol* symbol = (*ThreadContext::SymbolTable())[var->name()];
178         if (symbol) {
179             return nullptr;
180         }
181     } else if ((var->storage() == Variable::Storage::kGlobal ||
182                 var->storage() == Variable::Storage::kInterfaceBlock) &&
183                var->name() == Compiler::RTADJUST_NAME) {
184         // `sk_RTAdjust` is special, and makes the IR generator emit position-fixup expressions.
185         if (ThreadContext::RTAdjustState().fVar || ThreadContext::RTAdjustState().fInterfaceBlock) {
186             context.fErrors->error(var->fLine, "duplicate definition of 'sk_RTAdjust'");
187             return nullptr;
188         }
189         if (var->type() != *context.fTypes.fFloat4) {
190             context.fErrors->error(var->fLine, "sk_RTAdjust must have type 'float4'");
191             return nullptr;
192         }
193         ThreadContext::RTAdjustState().fVar = var.get();
194     }
195 
196     if (addToSymbolTable) {
197         ThreadContext::SymbolTable()->add(std::move(var));
198     } else {
199         ThreadContext::SymbolTable()->takeOwnershipOfSymbol(std::move(var));
200     }
201     return varDecl;
202 }
203 
Make(const Context & context,Variable * var,const Type * baseType,int arraySize,std::unique_ptr<Expression> value)204 std::unique_ptr<Statement> VarDeclaration::Make(const Context& context, Variable* var,
205         const Type* baseType, int arraySize, std::unique_ptr<Expression> value) {
206     SkASSERT(!baseType->isArray());
207     // function parameters cannot have variable declarations
208     SkASSERT(var->storage() != Variable::Storage::kParameter);
209     // 'const' variables must be initialized
210     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) || value);
211     // 'const' variable initializer must be a constant expression
212     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) ||
213              Analysis::IsConstantExpression(*value));
214     // global variable initializer must be a constant expression
215     SkASSERT(!(value && var->storage() == Variable::Storage::kGlobal &&
216                !Analysis::IsConstantExpression(*value)));
217     // opaque type not permitted on an interface block
218     SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && var->type().isOpaque()));
219     // initializers are not permitted on interface block fields
220     SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && value));
221     // opaque type cannot use initializer expressions
222     SkASSERT(!(value && var->type().isOpaque()));
223     // 'in' variables cannot use initializer expressions
224     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kIn_Flag)));
225     // 'uniform' variables cannot use initializer expressions
226     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kUniform_Flag)));
227 
228     auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
229     var->setDeclaration(result.get());
230     return std::move(result);
231 }
232 
233 }  // namespace SkSL
234