• 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 #ifdef SKSL_EXT
92         permitted |= Modifiers::kBuffer_Flag;
93         if (modifiers.fFlags & Modifiers::kBuffer_Flag) {
94             permitted |= Modifiers::kReadOnly_Flag | Modifiers::kWriteOnly_Flag;
95         }
96 #endif
97     }
98     // TODO(skbug.com/11301): Migrate above checks into building a mask of permitted layout flags
99     modifiers.checkPermitted(context, line, permitted, /*permittedLayoutFlags=*/~0);
100 }
101 
ErrorCheckAndCoerce(const Context & context,const Variable & var,std::unique_ptr<Expression> & value)102 bool VarDeclaration::ErrorCheckAndCoerce(const Context& context, const Variable& var,
103         std::unique_ptr<Expression>& value) {
104     const Type* baseType = &var.type();
105     if (baseType->isArray()) {
106         baseType = &baseType->componentType();
107     }
108     ErrorCheck(context, var.fLine, var.modifiers(), baseType, var.storage());
109     if (value) {
110         if (var.type().isOpaque()) {
111             context.fErrors->error(value->fLine,
112                     "opaque type '" + var.type().name() + "' cannot use initializer expressions");
113             return false;
114         }
115         if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
116             context.fErrors->error(value->fLine,
117                     "'in' variables cannot use initializer expressions");
118             return false;
119         }
120         if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
121             context.fErrors->error(value->fLine,
122                     "'uniform' variables cannot use initializer expressions");
123             return false;
124         }
125         if (var.storage() == Variable::Storage::kInterfaceBlock) {
126             context.fErrors->error(value->fLine,
127                     "initializers are not permitted on interface block fields");
128             return false;
129         }
130         value = var.type().coerceExpression(std::move(value), context);
131         if (!value) {
132             return false;
133         }
134     }
135     if (var.modifiers().fFlags & Modifiers::kConst_Flag) {
136         if (!value) {
137             context.fErrors->error(var.fLine, "'const' variables must be initialized");
138             return false;
139         }
140         if (!Analysis::IsConstantExpression(*value)) {
141             context.fErrors->error(value->fLine,
142                     "'const' variable initializer must be a constant expression");
143             return false;
144         }
145     }
146     if (var.storage() == Variable::Storage::kInterfaceBlock) {
147         if (var.type().isOpaque()) {
148             context.fErrors->error(var.fLine, "opaque type '" + var.type().name() +
149                     "' is not permitted in an interface block");
150             return false;
151         }
152     }
153     if (var.storage() == Variable::Storage::kGlobal) {
154         if (value && !Analysis::IsConstantExpression(*value)) {
155             context.fErrors->error(value->fLine,
156                     "global variable initializer must be a constant expression");
157             return false;
158         }
159     }
160     return true;
161 }
162 
Convert(const Context & context,std::unique_ptr<Variable> var,std::unique_ptr<Expression> value,bool addToSymbolTable)163 std::unique_ptr<Statement> VarDeclaration::Convert(const Context& context,
164         std::unique_ptr<Variable> var, std::unique_ptr<Expression> value, bool addToSymbolTable) {
165     if (!ErrorCheckAndCoerce(context, *var, value)) {
166         return nullptr;
167     }
168     const Type* baseType = &var->type();
169     int arraySize = 0;
170     if (baseType->isArray()) {
171         arraySize = baseType->columns();
172         baseType = &baseType->componentType();
173     }
174     std::unique_ptr<Statement> varDecl = VarDeclaration::Make(context, var.get(), baseType,
175             arraySize, std::move(value));
176     if (!varDecl) {
177         return nullptr;
178     }
179 
180     // Detect the declaration of magical variables.
181     if ((var->storage() == Variable::Storage::kGlobal) && var->name() == Compiler::FRAGCOLOR_NAME) {
182         // Silently ignore duplicate definitions of `sk_FragColor`.
183         const Symbol* symbol = (*ThreadContext::SymbolTable())[var->name()];
184         if (symbol) {
185             return nullptr;
186         }
187     } else if ((var->storage() == Variable::Storage::kGlobal ||
188                 var->storage() == Variable::Storage::kInterfaceBlock) &&
189                var->name() == Compiler::RTADJUST_NAME) {
190         // `sk_RTAdjust` is special, and makes the IR generator emit position-fixup expressions.
191         if (ThreadContext::RTAdjustState().fVar || ThreadContext::RTAdjustState().fInterfaceBlock) {
192             context.fErrors->error(var->fLine, "duplicate definition of 'sk_RTAdjust'");
193             return nullptr;
194         }
195         if (var->type() != *context.fTypes.fFloat4) {
196             context.fErrors->error(var->fLine, "sk_RTAdjust must have type 'float4'");
197             return nullptr;
198         }
199         ThreadContext::RTAdjustState().fVar = var.get();
200     }
201 
202     if (addToSymbolTable) {
203         ThreadContext::SymbolTable()->add(std::move(var));
204     } else {
205         ThreadContext::SymbolTable()->takeOwnershipOfSymbol(std::move(var));
206     }
207     return varDecl;
208 }
209 
Make(const Context & context,Variable * var,const Type * baseType,int arraySize,std::unique_ptr<Expression> value)210 std::unique_ptr<Statement> VarDeclaration::Make(const Context& context, Variable* var,
211         const Type* baseType, int arraySize, std::unique_ptr<Expression> value) {
212     SkASSERT(!baseType->isArray());
213     // function parameters cannot have variable declarations
214     SkASSERT(var->storage() != Variable::Storage::kParameter);
215     // 'const' variables must be initialized
216     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) || value);
217     // 'const' variable initializer must be a constant expression
218     SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) ||
219              Analysis::IsConstantExpression(*value));
220     // global variable initializer must be a constant expression
221     SkASSERT(!(value && var->storage() == Variable::Storage::kGlobal &&
222                !Analysis::IsConstantExpression(*value)));
223     // opaque type not permitted on an interface block
224     SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && var->type().isOpaque()));
225     // initializers are not permitted on interface block fields
226     SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && value));
227     // opaque type cannot use initializer expressions
228     SkASSERT(!(value && var->type().isOpaque()));
229     // 'in' variables cannot use initializer expressions
230     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kIn_Flag)));
231     // 'uniform' variables cannot use initializer expressions
232     SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kUniform_Flag)));
233 
234     auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
235     var->setDeclaration(result.get());
236     return std::move(result);
237 }
238 
239 }  // namespace SkSL
240