Flutter Engine
The Flutter Engine
Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
SkSL::VarDeclaration Class Referencefinal

#include <SkSLVarDeclarations.h>

Inheritance diagram for SkSL::VarDeclaration:
SkSL::Statement SkSL::IRNode SkSL::Poolable

Public Member Functions

 VarDeclaration (Variable *var, const Type *baseType, int arraySize, std::unique_ptr< Expression > value, bool isClone=false)
 
 ~VarDeclaration () override
 
const TypebaseType () const
 
Variablevar () const
 
void detachDeadVariable ()
 
int arraySize () const
 
std::unique_ptr< Expression > & value ()
 
const std::unique_ptr< Expression > & value () const
 
std::string description () const override
 
- Public Member Functions inherited from SkSL::Statement
 Statement (Position pos, Kind kind)
 
Kind kind () const
 
virtual bool isEmpty () const
 
- Public Member Functions inherited from SkSL::IRNode
virtual ~IRNode ()
 
virtual std::string description () const =0
 
 IRNode (const IRNode &)=delete
 
IRNodeoperator= (const IRNode &)=delete
 
Position position () const
 
void setPosition (Position p)
 
template<typename T >
bool is () const
 
template<typename T >
const Tas () const
 
template<typename T >
Tas ()
 

Static Public Member Functions

static void ErrorCheck (const Context &context, Position pos, Position modifiersPosition, const Layout &layout, ModifierFlags modifierFlags, const Type *type, const Type *baseType, Variable::Storage storage)
 
static std::unique_ptr< VarDeclarationConvert (const Context &context, Position overallPos, const Modifiers &modifiers, const Type &type, Position namePos, std::string_view name, VariableStorage storage, std::unique_ptr< Expression > value)
 
static std::unique_ptr< VarDeclarationConvert (const Context &context, std::unique_ptr< Variable > var, std::unique_ptr< Expression > value)
 
static std::unique_ptr< VarDeclarationMake (const Context &context, Variable *var, const Type *baseType, int arraySize, std::unique_ptr< Expression > value)
 
- Static Public Member Functions inherited from SkSL::Poolable
static void * operator new (const size_t size)
 
static void operator delete (void *ptr)
 

Static Public Attributes

static constexpr Kind kIRNodeKind = Kind::kVarDeclaration
 

Additional Inherited Members

- Public Types inherited from SkSL::Statement
using Kind = StatementKind
 
- Public Attributes inherited from SkSL::IRNode
Position fPosition
 
- Protected Member Functions inherited from SkSL::IRNode
 IRNode (Position position, int kind)
 
- Protected Attributes inherited from SkSL::IRNode
int fKind
 

Detailed Description

A single variable declaration statement. Multiple variables declared together are expanded to separate (sequential) statements. For instance, the SkSL 'int x = 2, y[3];' produces two VarDeclaration instances (wrapped in an unscoped Block).

Definition at line 37 of file SkSLVarDeclarations.h.

Constructor & Destructor Documentation

◆ VarDeclaration()

SkSL::VarDeclaration::VarDeclaration ( Variable var,
const Type baseType,
int  arraySize,
std::unique_ptr< Expression value,
bool  isClone = false 
)
inline

Definition at line 41 of file SkSLVarDeclarations.h.

46 : INHERITED(var->fPosition, kIRNodeKind)
47 , fVar(var)
48 , fBaseType(*baseType)
49 , fArraySize(arraySize)
50 , fValue(std::move(value))
51 , fIsClone(isClone) {}
Position fPosition
Definition: SkSLIRNode.h:109
const Type & baseType() const
std::unique_ptr< Expression > & value()
static constexpr Kind kIRNodeKind
Variable * var() const

◆ ~VarDeclaration()

SkSL::VarDeclaration::~VarDeclaration ( )
inlineoverride

Definition at line 53 of file SkSLVarDeclarations.h.

53 {
54 // Unhook this VarDeclaration from its associated Variable, since we're being deleted.
55 if (fVar && !fIsClone) {
57 }
58 }
void detachDeadVarDeclaration()
Definition: SkSLVariable.h:117

Member Function Documentation

◆ arraySize()

int SkSL::VarDeclaration::arraySize ( ) const
inline

Definition at line 104 of file SkSLVarDeclarations.h.

104 {
105 return fArraySize;
106 }

◆ baseType()

const Type & SkSL::VarDeclaration::baseType ( ) const
inline

Definition at line 92 of file SkSLVarDeclarations.h.

92 {
93 return fBaseType;
94 }

◆ Convert() [1/2]

std::unique_ptr< VarDeclaration > SkSL::VarDeclaration::Convert ( const Context context,
Position  overallPos,
const Modifiers modifiers,
const Type type,
Position  namePos,
std::string_view  name,
VariableStorage  storage,
std::unique_ptr< Expression value 
)
static

Definition at line 369 of file SkSLVarDeclarations.cpp.

376 {
377 // Parameter declaration-statements do not exist in the grammar (unlike, say, K&R C).
379
380 std::unique_ptr<Variable> var = Variable::Convert(context,
381 overallPos,
382 modifiers.fPosition,
383 modifiers.fLayout,
384 modifiers.fFlags,
385 &type,
386 namePos,
387 name,
388 storage);
389 if (!var) {
390 return nullptr;
391 }
392 return VarDeclaration::Convert(context, std::move(var), std::move(value));
393}
#define SkASSERT(cond)
Definition: SkAssert.h:116
GLenum type
static std::unique_ptr< VarDeclaration > Convert(const Context &context, Position overallPos, const Modifiers &modifiers, const Type &type, Position namePos, std::string_view name, VariableStorage storage, std::unique_ptr< Expression > value)
static std::unique_ptr< Variable > Convert(const Context &context, Position pos, Position modifiersPos, const Layout &layout, ModifierFlags flags, const Type *type, Position namePos, std::string_view name, Storage storage)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ Convert() [2/2]

std::unique_ptr< VarDeclaration > SkSL::VarDeclaration::Convert ( const Context context,
std::unique_ptr< Variable var,
std::unique_ptr< Expression value 
)
static

Definition at line 395 of file SkSLVarDeclarations.cpp.

397 {
398 const Type* baseType = &var->type();
399 int arraySize = 0;
400 if (baseType->isArray()) {
403 }
404 if (!ErrorCheckAndCoerce(context, *var, baseType, value)) {
405 return nullptr;
406 }
407 std::unique_ptr<VarDeclaration> varDecl = VarDeclaration::Make(context, var.get(), baseType,
408 arraySize, std::move(value));
409 if (!varDecl) {
410 return nullptr;
411 }
412
414 var->storage() == Variable::Storage::kInterfaceBlock) {
415 // Check if this globally-scoped variable name overlaps an existing symbol name.
416 if (context.fSymbolTable->find(var->name())) {
417 context.fErrors->error(var->fPosition,
418 "symbol '" + std::string(var->name()) + "' was already defined");
419 return nullptr;
420 }
421
422 // `sk_RTAdjust` is special, and makes the IR generator emit position-fixup expressions.
423 if (var->name() == Compiler::RTADJUST_NAME) {
424 if (!var->type().matches(*context.fTypes.fFloat4)) {
425 context.fErrors->error(var->fPosition, "sk_RTAdjust must have type 'float4'");
426 return nullptr;
427 }
428 }
429 }
430
431 context.fSymbolTable->add(context, std::move(var));
432 return varDecl;
433}
static constexpr const char RTADJUST_NAME[]
Definition: SkSLCompiler.h:72
std::string_view name() const
Definition: SkSLSymbol.h:51
const Type & type() const
Definition: SkSLSymbol.h:42
virtual bool isArray() const
Definition: SkSLType.h:532
virtual const Type & componentType() const
Definition: SkSLType.h:404
bool matches(const Type &other) const
Definition: SkSLType.h:269
virtual int columns() const
Definition: SkSLType.h:429
static std::unique_ptr< VarDeclaration > Make(const Context &context, Variable *var, const Type *baseType, int arraySize, std::unique_ptr< Expression > value)
Storage storage() const
Definition: SkSLVariable.h:103

◆ description()

std::string SkSL::VarDeclaration::description ( ) const
overridevirtual

Implements SkSL::IRNode.

Definition at line 82 of file SkSLVarDeclarations.cpp.

82 {
83 std::string result = this->var()->layout().paddedDescription() +
85 this->baseType().description() + ' ' + std::string(this->var()->name());
86 if (this->arraySize() > 0) {
87 String::appendf(&result, "[%d]", this->arraySize());
88 }
89 if (this->value()) {
90 result += " = " + this->value()->description();
91 }
92 result += ";";
93 return result;
94}
std::string paddedDescription() const
std::string description() const override
Definition: SkSLType.h:238
ModifierFlags modifierFlags() const
Definition: SkSLVariable.h:89
virtual const Layout & layout() const
GAsyncResult * result
std::string void appendf(std::string *str, const char *fmt,...) SK_PRINTF_LIKE(2
Definition: SkSLString.cpp:92
std::string paddedDescription() const

◆ detachDeadVariable()

void SkSL::VarDeclaration::detachDeadVariable ( )
inline

Definition at line 100 of file SkSLVarDeclarations.h.

100 {
101 fVar = nullptr;
102 }

◆ ErrorCheck()

void SkSL::VarDeclaration::ErrorCheck ( const Context context,
Position  pos,
Position  modifiersPosition,
const Layout layout,
ModifierFlags  modifierFlags,
const Type type,
const Type baseType,
Variable::Storage  storage 
)
static

Definition at line 96 of file SkSLVarDeclarations.cpp.

103 {
104 SkASSERT(type->isArray() ? baseType->matches(type->componentType())
105 : baseType->matches(*type));
106
108 storage != Variable::Storage::kGlobal) {
109 context.fErrors->error(pos, "variables of type '" + baseType->displayName() +
110 "' must be global");
111 }
112 if ((modifierFlags & ModifierFlag::kIn) && baseType->isMatrix()) {
113 context.fErrors->error(pos, "'in' variables may not have matrix type");
114 }
115 if ((modifierFlags & ModifierFlag::kIn) && type->isUnsizedArray()) {
116 context.fErrors->error(pos, "'in' variables may not have unsized array type");
117 }
118 if ((modifierFlags & ModifierFlag::kOut) && type->isUnsizedArray()) {
119 context.fErrors->error(pos, "'out' variables may not have unsized array type");
120 }
121 if ((modifierFlags & ModifierFlag::kIn) && modifierFlags.isUniform()) {
122 context.fErrors->error(pos, "'in uniform' variables not permitted");
123 }
124 if (modifierFlags.isReadOnly() && modifierFlags.isWriteOnly()) {
125 context.fErrors->error(pos, "'readonly' and 'writeonly' qualifiers cannot be combined");
126 }
127 if (modifierFlags.isUniform() && modifierFlags.isBuffer()) {
128 context.fErrors->error(pos, "'uniform buffer' variables not permitted");
129 }
130 if (modifierFlags.isWorkgroup() && (modifierFlags & (ModifierFlag::kIn |
132 context.fErrors->error(pos, "in / out variables may not be declared workgroup");
133 }
134 if (modifierFlags.isUniform()) {
135 check_valid_uniform_type(pos, baseType, context);
136 }
137 if (baseType->isEffectChild() && !modifierFlags.isUniform()) {
138 context.fErrors->error(pos, "variables of type '" + baseType->displayName() +
139 "' must be uniform");
140 }
141 if (baseType->isEffectChild() && context.fConfig->fKind == ProgramKind::kMeshVertex) {
142 context.fErrors->error(pos, "effects are not permitted in mesh vertex shaders");
143 }
145 // An atomic variable (or a struct or an array that contains an atomic member) must be
146 // either:
147 // a. Declared as a workgroup-shared variable, OR
148 // b. Declared as the member of writable storage buffer block (i.e. has no readonly
149 // restriction).
150 //
151 // The checks below will enforce these two rules on all declarations. If the variable is not
152 // declared with the workgroup modifier, then it must be declared in the interface block
153 // storage. If this is the declaration for an interface block that contains an atomic
154 // member, then it must have the `buffer` modifier and no `readonly` modifier.
155 bool isBlockMember = (storage == Variable::Storage::kInterfaceBlock);
156 bool isWritableStorageBuffer = modifierFlags.isBuffer() && !modifierFlags.isReadOnly();
157
158 if (!modifierFlags.isWorkgroup() &&
159 !(baseType->isInterfaceBlock() ? isWritableStorageBuffer : isBlockMember)) {
160 context.fErrors->error(pos, "atomics are only permitted in workgroup variables and "
161 "writable storage blocks");
162 }
163 }
164 if (layout.fFlags & LayoutFlag::kColor) {
165 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
166 context.fErrors->error(pos, "'layout(color)' is only permitted in runtime effects");
167 }
168 if (!modifierFlags.isUniform()) {
169 context.fErrors->error(pos, "'layout(color)' is only permitted on 'uniform' variables");
170 }
171 auto validColorXformType = [](const Type& t) {
172 return t.isVector() && t.componentType().isFloat() &&
173 (t.columns() == 3 || t.columns() == 4);
174 };
175 if (!validColorXformType(*baseType)) {
176 context.fErrors->error(pos, "'layout(color)' is not permitted on variables of type '" +
177 baseType->displayName() + "'");
178 }
179 }
180
183 if (storage == Variable::Storage::kGlobal) {
184 // Uniforms are allowed in all programs
185 permitted |= ModifierFlag::kUniform;
186
187 // No other modifiers are allowed in runtime effects.
188 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
189 if (baseType->isInterfaceBlock()) {
190 // Interface blocks allow `buffer`.
191 permitted |= ModifierFlag::kBuffer;
192
193 if (modifierFlags.isBuffer()) {
194 // Only storage blocks allow `readonly` and `writeonly`.
195 // (`readonly` and `writeonly` textures are converted to separate types via
196 // applyAccessQualifiers.)
198 }
199
200 // It is an error for an unsized array to appear anywhere but the last member of a
201 // "buffer" block.
202 const auto& fields = baseType->fields();
203 const int illegalRangeEnd = SkToInt(fields.size()) -
204 (modifierFlags.isBuffer() ? 1 : 0);
205 for (int i = 0; i < illegalRangeEnd; ++i) {
206 if (fields[i].fType->isUnsizedArray()) {
207 context.fErrors->error(
208 fields[i].fPosition,
209 "unsized array must be the last member of a storage block");
210 }
211 }
212 }
213
214 if (!baseType->isOpaque()) {
215 // Only non-opaque types allow `in` and `out`.
217 }
218 if (ProgramConfig::IsFragment(context.fConfig->fKind) && baseType->isStruct() &&
220 // Only structs in fragment shaders allow `pixel_local`.
221 permitted |= ModifierFlag::kPixelLocal;
222 }
223 if (ProgramConfig::IsCompute(context.fConfig->fKind)) {
224 // Only compute shaders allow `workgroup`.
225 if (!baseType->isOpaque() || baseType->isAtomic()) {
226 permitted |= ModifierFlag::kWorkgroup;
227 }
228 } else {
229 // Only vertex/fragment shaders allow `flat` and `noperspective`.
231 }
232 }
233 }
234
235 LayoutFlags permittedLayoutFlags = LayoutFlag::kAll;
236
237 // Pixel format modifiers are required on storage textures, and forbidden on other types.
238 if (baseType->isStorageTexture()) {
239 if (!(layout.fFlags & LayoutFlag::kAllPixelFormats)) {
240 context.fErrors->error(pos, "storage textures must declare a pixel format");
241 }
242 } else {
243 permittedLayoutFlags &= ~LayoutFlag::kAllPixelFormats;
244 }
245
246 // The `texture` and `sampler` modifiers can be present respectively on a texture and sampler or
247 // simultaneously on a combined image-sampler but they are not permitted on any other type.
248 switch (baseType->typeKind()) {
250 // Both texture and sampler flags are permitted
251 break;
253 permittedLayoutFlags &= ~LayoutFlag::kSampler;
254 break;
256 permittedLayoutFlags &= ~LayoutFlag::kTexture;
257 break;
258 default:
259 permittedLayoutFlags &= ~(LayoutFlag::kTexture | LayoutFlag::kSampler);
260 break;
261 }
262
263 // We don't allow 'binding' or 'set' on normal uniform variables, only on textures, samplers,
264 // and interface blocks (holding uniform variables). They're also only allowed at global scope,
265 // not on interface block fields (or locals/parameters).
266 bool permitBindingAndSet = baseType->typeKind() == Type::TypeKind::kSampler ||
270 if (storage != Variable::Storage::kGlobal || (modifierFlags.isUniform() &&
271 !permitBindingAndSet)) {
272 permittedLayoutFlags &= ~LayoutFlag::kBinding;
273 permittedLayoutFlags &= ~LayoutFlag::kSet;
274 permittedLayoutFlags &= ~LayoutFlag::kAllBackends;
275 }
276 if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
277 // Disallow all layout flags except 'color' in runtime effects
278 permittedLayoutFlags &= LayoutFlag::kColor;
279 }
280
281 // The `push_constant` flag isn't allowed on in-variables, out-variables, bindings or sets.
282 if ((layout.fFlags & (LayoutFlag::kSet | LayoutFlag::kBinding)) ||
283 (modifierFlags & (ModifierFlag::kIn | ModifierFlag::kOut))) {
284 permittedLayoutFlags &= ~LayoutFlag::kPushConstant;
285 }
286 // The `builtin` layout flag is only allowed in modules.
287 if (!context.fConfig->fIsBuiltinCode) {
288 permittedLayoutFlags &= ~LayoutFlag::kBuiltin;
289 }
290
291 modifierFlags.checkPermittedFlags(context, modifiersPosition, permitted);
292 layout.checkPermittedLayout(context, modifiersPosition, permittedLayoutFlags);
293}
SkPoint pos
constexpr int SkToInt(S x)
Definition: SkTo.h:29
bool isEffectChild() const
Definition: SkSLType.h:550
bool isAtomic() const
Definition: SkSLType.h:508
virtual bool isInterfaceBlock() const
Definition: SkSLType.h:544
bool isOpaque() const
Definition: SkSLType.h:353
virtual SkSpan< const Field > fields() const
Definition: SkSLType.h:469
virtual bool isMatrix() const
Definition: SkSLType.h:528
virtual bool isOrContainsAtomic() const
Definition: SkSLType.h:586
bool isStorageTexture() const
Definition: SkSLType.h:371
std::string displayName() const
Definition: SkSLType.h:234
TypeKind typeKind() const
Definition: SkSLType.h:283
virtual bool isStruct() const
Definition: SkSLType.h:540
SkEnumBitMask< SkSL::LayoutFlag > LayoutFlags
Definition: SkSLLayout.h:68
static bool IsRuntimeEffect(ProgramKind kind)
static bool IsFragment(ProgramKind kind)
static bool IsCompute(ProgramKind kind)

◆ Make()

std::unique_ptr< VarDeclaration > SkSL::VarDeclaration::Make ( const Context context,
Variable var,
const Type baseType,
int  arraySize,
std::unique_ptr< Expression value 
)
static

Definition at line 435 of file SkSLVarDeclarations.cpp.

439 {
441 // function parameters cannot have variable declarations
442 SkASSERT(var->storage() != Variable::Storage::kParameter);
443 // 'const' variables must be initialized
445 // 'const' variable initializer must be a constant expression
447 // global variable initializer must be a constant expression
450 // opaque type not permitted on an interface block
451 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && var->type().isOpaque()));
452 // initializers are not permitted on interface block fields
453 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && value));
454 // opaque type cannot use initializer expressions
455 SkASSERT(!(value && var->type().isOpaque()));
456 // 'in' variables cannot use initializer expressions
458 // 'uniform' variables cannot use initializer expressions
460 // in strict-ES2 mode, is-or-contains-array types cannot use initializer expressions
461 SkASSERT(!(value && var->type().isOrContainsArray() && context.fConfig->strictES2Mode()));
462
463 auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
465 return result;
466}
virtual bool isOrContainsArray() const
Definition: SkSLType.h:578
void setVarDeclaration(VarDeclaration *declaration)
bool IsConstantExpression(const Expression &expr)

◆ value() [1/2]

std::unique_ptr< Expression > & SkSL::VarDeclaration::value ( )
inline

Definition at line 108 of file SkSLVarDeclarations.h.

108 {
109 return fValue;
110 }

◆ value() [2/2]

const std::unique_ptr< Expression > & SkSL::VarDeclaration::value ( ) const
inline

Definition at line 112 of file SkSLVarDeclarations.h.

112 {
113 return fValue;
114 }

◆ var()

Variable * SkSL::VarDeclaration::var ( ) const
inline

Definition at line 96 of file SkSLVarDeclarations.h.

96 {
97 return fVar;
98 }

Member Data Documentation

◆ kIRNodeKind

constexpr Kind SkSL::VarDeclaration::kIRNodeKind = Kind::kVarDeclaration
inlinestaticconstexpr

Definition at line 39 of file SkSLVarDeclarations.h.


The documentation for this class was generated from the following files: