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