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 17namespace SkSL { 18 19std::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 26String 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 39void 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 96bool 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 157std::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 204std::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