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