Implement GL_EXT_null_initializer
Adds null initializer syntax (empty braces) Allows null initialization of shared variables
This commit is contained in:
parent
6abdde3ce5
commit
c739e03748
@ -3652,13 +3652,14 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
|||||||
|
|
||||||
spv::Id initializer = spv::NoResult;
|
spv::Id initializer = spv::NoResult;
|
||||||
|
|
||||||
if (node->getType().getQualifier().storage == glslang::EvqUniform &&
|
if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) {
|
||||||
!node->getConstArray().empty()) {
|
int nextConst = 0;
|
||||||
int nextConst = 0;
|
initializer = createSpvConstantFromConstUnionArray(node->getType(),
|
||||||
initializer = createSpvConstantFromConstUnionArray(node->getType(),
|
node->getConstArray(),
|
||||||
node->getConstArray(),
|
nextConst,
|
||||||
nextConst,
|
false /* specConst */);
|
||||||
false /* specConst */);
|
} else if (node->getType().getQualifier().isNullInit()) {
|
||||||
|
initializer = builder.makeNullConstant(spvType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer);
|
return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer);
|
||||||
|
@ -869,6 +869,30 @@ bool Builder::isSpecConstantOpCode(Op opcode) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id Builder::makeNullConstant(Id typeId)
|
||||||
|
{
|
||||||
|
Instruction* constant;
|
||||||
|
|
||||||
|
// See if we already made it.
|
||||||
|
Id existing = NoResult;
|
||||||
|
for (int i = 0; i < (int)nullConstants.size(); ++i) {
|
||||||
|
constant = nullConstants[i];
|
||||||
|
if (constant->getTypeId() == typeId)
|
||||||
|
existing = constant->getResultId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing != NoResult)
|
||||||
|
return existing;
|
||||||
|
|
||||||
|
// Make it
|
||||||
|
Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantNull);
|
||||||
|
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
|
||||||
|
nullConstants.push_back(c);
|
||||||
|
module.mapInstruction(c);
|
||||||
|
|
||||||
|
return c->getResultId();
|
||||||
|
}
|
||||||
|
|
||||||
Id Builder::makeBoolConstant(bool b, bool specConstant)
|
Id Builder::makeBoolConstant(bool b, bool specConstant)
|
||||||
{
|
{
|
||||||
Id typeId = makeBoolType();
|
Id typeId = makeBoolType();
|
||||||
|
@ -293,6 +293,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For making new constants (will return old constant if the requested one was already made).
|
// For making new constants (will return old constant if the requested one was already made).
|
||||||
|
Id makeNullConstant(Id typeId);
|
||||||
Id makeBoolConstant(bool b, bool specConstant = false);
|
Id makeBoolConstant(bool b, bool specConstant = false);
|
||||||
Id makeInt8Constant(int i, bool specConstant = false)
|
Id makeInt8Constant(int i, bool specConstant = false)
|
||||||
{ return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
|
{ return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
|
||||||
@ -838,6 +839,8 @@ public:
|
|||||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
|
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
|
||||||
// map type opcodes to type instructions
|
// map type opcodes to type instructions
|
||||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
|
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
|
||||||
|
// list of OpConstantNull instructions
|
||||||
|
std::vector<Instruction*> nullConstants;
|
||||||
|
|
||||||
// stack of switches
|
// stack of switches
|
||||||
std::stack<Block*> switchMerges;
|
std::stack<Block*> switchMerges;
|
||||||
|
@ -9,7 +9,7 @@ ERROR: 0:40: 'in' : global storage input qualifier cannot be used in a compute s
|
|||||||
ERROR: 0:41: 'out' : global storage output qualifier cannot be used in a compute shader
|
ERROR: 0:41: 'out' : global storage output qualifier cannot be used in a compute shader
|
||||||
ERROR: 0:44: 'shared' : cannot apply layout qualifiers to a shared variable
|
ERROR: 0:44: 'shared' : cannot apply layout qualifiers to a shared variable
|
||||||
ERROR: 0:44: 'location' : can only apply to uniform, buffer, in, or out storage qualifiers
|
ERROR: 0:44: 'location' : can only apply to uniform, buffer, in, or out storage qualifiers
|
||||||
ERROR: 0:45: 'shared' : cannot initialize this type of qualifier
|
ERROR: 0:45: 'shared' : initializer can only be a null initializer ('{}')
|
||||||
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
||||||
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
||||||
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
ERROR: 0:47: 'local_size' : can only apply to 'in'
|
||||||
@ -115,6 +115,11 @@ ERROR: node is still EOpNull!
|
|||||||
0:36 Constant:
|
0:36 Constant:
|
||||||
0:36 1 (const uint)
|
0:36 1 (const uint)
|
||||||
0:36 'gl_LocalInvocationIndex' ( in highp uint LocalInvocationIndex)
|
0:36 'gl_LocalInvocationIndex' ( in highp uint LocalInvocationIndex)
|
||||||
|
0:45 Sequence
|
||||||
|
0:45 move second child to first child ( temp highp float)
|
||||||
|
0:45 'fs' ( shared highp float)
|
||||||
|
0:45 Constant:
|
||||||
|
0:45 4.200000
|
||||||
0:59 Function Definition: foo( ( global void)
|
0:59 Function Definition: foo( ( global void)
|
||||||
0:59 Function Parameters:
|
0:59 Function Parameters:
|
||||||
0:61 Sequence
|
0:61 Sequence
|
||||||
@ -553,6 +558,11 @@ ERROR: node is still EOpNull!
|
|||||||
0:36 Constant:
|
0:36 Constant:
|
||||||
0:36 1 (const uint)
|
0:36 1 (const uint)
|
||||||
0:36 'gl_LocalInvocationIndex' ( in highp uint LocalInvocationIndex)
|
0:36 'gl_LocalInvocationIndex' ( in highp uint LocalInvocationIndex)
|
||||||
|
0:45 Sequence
|
||||||
|
0:45 move second child to first child ( temp highp float)
|
||||||
|
0:45 'fs' ( shared highp float)
|
||||||
|
0:45 Constant:
|
||||||
|
0:45 4.200000
|
||||||
0:? Linker Objects
|
0:? Linker Objects
|
||||||
0:? 'gl_WorkGroupSize' ( const highp 3-component vector of uint WorkGroupSize)
|
0:? 'gl_WorkGroupSize' ( const highp 3-component vector of uint WorkGroupSize)
|
||||||
0:? 2 (const uint)
|
0:? 2 (const uint)
|
||||||
|
@ -7,7 +7,7 @@ ERROR: 0:44: 'in' : global storage input qualifier cannot be used in a compute s
|
|||||||
ERROR: 0:45: 'out' : global storage output qualifier cannot be used in a compute shader
|
ERROR: 0:45: 'out' : global storage output qualifier cannot be used in a compute shader
|
||||||
ERROR: 0:48: 'shared' : cannot apply layout qualifiers to a shared variable
|
ERROR: 0:48: 'shared' : cannot apply layout qualifiers to a shared variable
|
||||||
ERROR: 0:48: 'location' : can only apply to uniform, buffer, in, or out storage qualifiers
|
ERROR: 0:48: 'location' : can only apply to uniform, buffer, in, or out storage qualifiers
|
||||||
ERROR: 0:49: 'shared' : cannot initialize this type of qualifier
|
ERROR: 0:49: 'shared' : initializer can only be a null initializer ('{}')
|
||||||
ERROR: 0:52: 'local_size' : cannot change previously set size
|
ERROR: 0:52: 'local_size' : cannot change previously set size
|
||||||
ERROR: 0:54: 'local_size' : can only apply to 'in'
|
ERROR: 0:54: 'local_size' : can only apply to 'in'
|
||||||
ERROR: 0:54: 'local_size' : can only apply to 'in'
|
ERROR: 0:54: 'local_size' : can only apply to 'in'
|
||||||
@ -52,6 +52,11 @@ ERROR: node is still EOpNull!
|
|||||||
0:39 10 (const int)
|
0:39 10 (const int)
|
||||||
0:39 true case
|
0:39 true case
|
||||||
0:40 Barrier ( global void)
|
0:40 Barrier ( global void)
|
||||||
|
0:49 Sequence
|
||||||
|
0:49 move second child to first child ( temp float)
|
||||||
|
0:49 'fs' ( shared float)
|
||||||
|
0:49 Constant:
|
||||||
|
0:49 4.200000
|
||||||
0:66 Function Definition: foo( ( global void)
|
0:66 Function Definition: foo( ( global void)
|
||||||
0:66 Function Parameters:
|
0:66 Function Parameters:
|
||||||
0:68 Sequence
|
0:68 Sequence
|
||||||
@ -184,6 +189,11 @@ ERROR: node is still EOpNull!
|
|||||||
0:39 10 (const int)
|
0:39 10 (const int)
|
||||||
0:39 true case
|
0:39 true case
|
||||||
0:40 Barrier ( global void)
|
0:40 Barrier ( global void)
|
||||||
|
0:49 Sequence
|
||||||
|
0:49 move second child to first child ( temp float)
|
||||||
|
0:49 'fs' ( shared float)
|
||||||
|
0:49 Constant:
|
||||||
|
0:49 4.200000
|
||||||
0:? Linker Objects
|
0:? Linker Objects
|
||||||
0:? 'gl_WorkGroupSize' ( const 3-component vector of uint WorkGroupSize)
|
0:? 'gl_WorkGroupSize' ( const 3-component vector of uint WorkGroupSize)
|
||||||
0:? 2 (const uint)
|
0:? 2 (const uint)
|
||||||
|
66
Test/baseResults/spv.nullInit.comp.out
Executable file
66
Test/baseResults/spv.nullInit.comp.out
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
spv.nullInit.comp
|
||||||
|
Validation failed
|
||||||
|
// Module Version 10000
|
||||||
|
// Generated by (magic number): 8000a
|
||||||
|
// Id's are bound by 37
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint GLCompute 4 "main"
|
||||||
|
ExecutionMode 4 LocalSize 1 1 1
|
||||||
|
Source GLSL 460
|
||||||
|
SourceExtension "GL_EXT_null_initializer"
|
||||||
|
Name 4 "main"
|
||||||
|
Name 12 "S"
|
||||||
|
MemberName 12(S) 0 "v"
|
||||||
|
MemberName 12(S) 1 "a"
|
||||||
|
Name 15 "local"
|
||||||
|
Name 23 "f"
|
||||||
|
Name 24 "T"
|
||||||
|
MemberName 24(T) 0 "b"
|
||||||
|
MemberName 24(T) 1 "s"
|
||||||
|
Name 27 "t1"
|
||||||
|
Name 28 "t2"
|
||||||
|
Name 30 "s"
|
||||||
|
Name 31 "g"
|
||||||
|
Name 34 "i"
|
||||||
|
Name 36 "global"
|
||||||
|
2: TypeVoid
|
||||||
|
3: TypeFunction 2
|
||||||
|
6: TypeFloat 32
|
||||||
|
7: TypeVector 6(float) 3
|
||||||
|
8: TypeInt 32 0
|
||||||
|
9: 8(int) Constant 4
|
||||||
|
10: TypeArray 7(fvec3) 9
|
||||||
|
11: TypeInt 32 1
|
||||||
|
12(S): TypeStruct 10 11(int)
|
||||||
|
13: 12(S) ConstantNull
|
||||||
|
14: TypePointer Function 12(S)
|
||||||
|
16: 11(int) Constant 1
|
||||||
|
17: TypePointer Function 11(int)
|
||||||
|
21: 6(float) ConstantNull
|
||||||
|
22: TypePointer Workgroup 6(float)
|
||||||
|
23(f): 22(ptr) Variable Workgroup 21
|
||||||
|
24(T): TypeStruct 11(int) 12(S)
|
||||||
|
25: 24(T) ConstantNull
|
||||||
|
26: TypePointer Workgroup 24(T)
|
||||||
|
27(t1): 26(ptr) Variable Workgroup 25
|
||||||
|
28(t2): 26(ptr) Variable Workgroup 25
|
||||||
|
29: TypePointer Workgroup 12(S)
|
||||||
|
30(s): 29(ptr) Variable Workgroup 13
|
||||||
|
31(g): 22(ptr) Variable Workgroup 21
|
||||||
|
32: 11(int) ConstantNull
|
||||||
|
33: TypePointer Workgroup 11(int)
|
||||||
|
34(i): 33(ptr) Variable Workgroup 32
|
||||||
|
35: TypePointer Private 12(S)
|
||||||
|
36(global): 35(ptr) Variable Private 13
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
15(local): 14(ptr) Variable Function 13
|
||||||
|
18: 17(ptr) AccessChain 15(local) 16
|
||||||
|
19: 11(int) Load 18
|
||||||
|
20: 11(int) IAdd 19 16
|
||||||
|
Store 18 20
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
@ -1,6 +1,17 @@
|
|||||||
vulkan.comp
|
vulkan.comp
|
||||||
ERROR: 0:5: 'local_size' : cannot change previously set size
|
ERROR: 0:5: 'local_size' : cannot change previously set size
|
||||||
ERROR: 1 compilation errors. No code generated.
|
ERROR: 0:10: 'empty { } initializer' : not supported for this version or the enabled extensions
|
||||||
|
ERROR: 0:15: 'empty { } initializer' : not supported for this version or the enabled extensions
|
||||||
|
ERROR: 0:15: 'initialization with shared qualifier' : not supported for this version or the enabled extensions
|
||||||
|
ERROR: 0:16: 'empty { } initializer' : not supported for this version or the enabled extensions
|
||||||
|
ERROR: 0:26: '{}' : null initializers can't size unsized arrays
|
||||||
|
ERROR: 0:31: 'structure' : non-uniform struct contains a sampler or image: sampVar
|
||||||
|
ERROR: 0:31: '{}' : null initializers can't be used on opaque values
|
||||||
|
ERROR: 0:33: 'atomic counter types' : not allowed when using GLSL for Vulkan
|
||||||
|
ERROR: 0:33: 'atomic_uint' : atomic_uints can only be used in uniform variables or function parameters: a
|
||||||
|
ERROR: 0:33: '{}' : null initializers can't be used on opaque values
|
||||||
|
ERROR: 0:33: 'atomic_uint' : layout(binding=X) is required
|
||||||
|
ERROR: 12 compilation errors. No code generated.
|
||||||
|
|
||||||
|
|
||||||
SPIR-V is not generated for failed compile or link
|
SPIR-V is not generated for failed compile or link
|
||||||
|
32
Test/spv.nullInit.comp
Normal file
32
Test/spv.nullInit.comp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
#extension GL_EXT_null_initializer : enable
|
||||||
|
|
||||||
|
#ifdef GL_EXT_null_initializer
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
vec3[4] v;
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct T {
|
||||||
|
int b;
|
||||||
|
S s;
|
||||||
|
};
|
||||||
|
|
||||||
|
shared float f = { };
|
||||||
|
shared T t1 = { };
|
||||||
|
shared T t2 = { };
|
||||||
|
shared S s = { };
|
||||||
|
shared float g = { };
|
||||||
|
shared int i = { };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
S local = { };
|
||||||
|
++local.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
S global = { };
|
||||||
|
|
||||||
|
#endif
|
@ -7,6 +7,27 @@ layout(local_size_z_id = 14) in; // ERROR, can't change this
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_WorkGroupSize;
|
gl_WorkGroupSize;
|
||||||
|
int i = { }; // ERROR, need an extension
|
||||||
}
|
}
|
||||||
|
|
||||||
layout(local_size_y_id = 19) in; // ERROR, already used: TODO not yet reported
|
layout(local_size_y_id = 19) in; // ERROR, already used: TODO not yet reported
|
||||||
|
|
||||||
|
shared float f = { }; // ERROR, need an extension
|
||||||
|
float g = { }; // ERROR, need an extension
|
||||||
|
|
||||||
|
#extension GL_EXT_null_initializer : enable
|
||||||
|
|
||||||
|
shared float f2 = { };
|
||||||
|
float g2 = { };
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
int i = { };
|
||||||
|
float fa[] = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct samp {
|
||||||
|
sampler2D s2D;
|
||||||
|
} sampVar = { };
|
||||||
|
|
||||||
|
atomic_uint a = { };
|
||||||
|
@ -499,6 +499,7 @@ public:
|
|||||||
declaredBuiltIn = EbvNone;
|
declaredBuiltIn = EbvNone;
|
||||||
#ifndef GLSLANG_WEB
|
#ifndef GLSLANG_WEB
|
||||||
noContraction = false;
|
noContraction = false;
|
||||||
|
nullInit = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,6 +513,7 @@ public:
|
|||||||
clearMemory();
|
clearMemory();
|
||||||
specConstant = false;
|
specConstant = false;
|
||||||
nonUniform = false;
|
nonUniform = false;
|
||||||
|
nullInit = false;
|
||||||
clearLayout();
|
clearLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,6 +590,8 @@ public:
|
|||||||
bool isNoContraction() const { return false; }
|
bool isNoContraction() const { return false; }
|
||||||
void setNoContraction() { }
|
void setNoContraction() { }
|
||||||
bool isPervertexNV() const { return false; }
|
bool isPervertexNV() const { return false; }
|
||||||
|
void setNullInit() { }
|
||||||
|
bool isNullInit() const { return false; }
|
||||||
#else
|
#else
|
||||||
bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
|
bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
|
||||||
bool nopersp : 1;
|
bool nopersp : 1;
|
||||||
@ -609,6 +613,7 @@ public:
|
|||||||
bool subgroupcoherent : 1;
|
bool subgroupcoherent : 1;
|
||||||
bool shadercallcoherent : 1;
|
bool shadercallcoherent : 1;
|
||||||
bool nonprivate : 1;
|
bool nonprivate : 1;
|
||||||
|
bool nullInit : 1;
|
||||||
bool isWriteOnly() const { return writeonly; }
|
bool isWriteOnly() const { return writeonly; }
|
||||||
bool isReadOnly() const { return readonly; }
|
bool isReadOnly() const { return readonly; }
|
||||||
bool isRestrict() const { return restrict; }
|
bool isRestrict() const { return restrict; }
|
||||||
@ -644,6 +649,8 @@ public:
|
|||||||
bool isNoContraction() const { return noContraction; }
|
bool isNoContraction() const { return noContraction; }
|
||||||
void setNoContraction() { noContraction = true; }
|
void setNoContraction() { noContraction = true; }
|
||||||
bool isPervertexNV() const { return pervertexNV; }
|
bool isPervertexNV() const { return pervertexNV; }
|
||||||
|
void setNullInit() { nullInit = true; }
|
||||||
|
bool isNullInit() const { return nullInit; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool isPipeInput() const
|
bool isPipeInput() const
|
||||||
@ -2164,6 +2171,8 @@ public:
|
|||||||
appendStr(" specialization-constant");
|
appendStr(" specialization-constant");
|
||||||
if (qualifier.nonUniform)
|
if (qualifier.nonUniform)
|
||||||
appendStr(" nonuniform");
|
appendStr(" nonuniform");
|
||||||
|
if (qualifier.isNullInit())
|
||||||
|
appendStr(" null-init");
|
||||||
appendStr(" ");
|
appendStr(" ");
|
||||||
appendStr(getStorageQualifierString());
|
appendStr(getStorageQualifierString());
|
||||||
if (isArray()) {
|
if (isArray()) {
|
||||||
|
@ -6815,6 +6815,11 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString&
|
|||||||
//
|
//
|
||||||
TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
|
TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
|
||||||
{
|
{
|
||||||
|
// A null initializer is an aggregate that hasn't had an op assigned yet
|
||||||
|
// (still EOpNull, no relation to nullInit), and has no children.
|
||||||
|
bool nullInit = initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull &&
|
||||||
|
initializer->getAsAggregate()->getSequence().size() == 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Identifier must be of type constant, a global, or a temporary, and
|
// Identifier must be of type constant, a global, or a temporary, and
|
||||||
// starting at version 120, desktop allows uniforms to have initializers.
|
// starting at version 120, desktop allows uniforms to have initializers.
|
||||||
@ -6822,9 +6827,36 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
|
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
|
||||||
if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
|
if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
|
||||||
(qualifier == EvqUniform && !isEsProfile() && version >= 120))) {
|
(qualifier == EvqUniform && !isEsProfile() && version >= 120))) {
|
||||||
error(loc, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
|
if (qualifier == EvqShared) {
|
||||||
|
// GL_EXT_null_initializer allows this for shared, if it's a null initializer
|
||||||
|
if (nullInit) {
|
||||||
|
const char* feature = "initialization with shared qualifier";
|
||||||
|
profileRequires(loc, EEsProfile, 0, E_GL_EXT_null_initializer, feature);
|
||||||
|
profileRequires(loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, feature);
|
||||||
|
} else {
|
||||||
|
error(loc, "initializer can only be a null initializer ('{}')", "shared", "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(loc, " cannot initialize this type of qualifier ",
|
||||||
|
variable->getType().getStorageQualifierString(), "");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullInit) {
|
||||||
|
// only some types can be null initialized
|
||||||
|
if (variable->getType().containsUnsizedArray()) {
|
||||||
|
error(loc, "null initializers can't size unsized arrays", "{}", "");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (variable->getType().containsOpaque()) {
|
||||||
|
error(loc, "null initializers can't be used on opaque values", "{}", "");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
variable->getWritableType().getQualifier().setNullInit();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayObjectCheck(loc, variable->getType(), "array initializer");
|
arrayObjectCheck(loc, variable->getType(), "array initializer");
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -6868,13 +6900,15 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
|
|
||||||
// Uniforms require a compile-time constant initializer
|
// Uniforms require a compile-time constant initializer
|
||||||
if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
|
if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
|
||||||
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, "uniform initializers must be constant", "=", "'%s'",
|
||||||
|
variable->getType().getCompleteString().c_str());
|
||||||
variable->getWritableType().getQualifier().makeTemporary();
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// Global consts require a constant initializer (specialization constant is okay)
|
// Global consts require a constant initializer (specialization constant is okay)
|
||||||
if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
||||||
error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, "global const initializers must be constant", "=", "'%s'",
|
||||||
|
variable->getType().getCompleteString().c_str());
|
||||||
variable->getWritableType().getQualifier().makeTemporary();
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -6894,7 +6928,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
// "In declarations of global variables with no storage qualifier or with a const
|
// "In declarations of global variables with no storage qualifier or with a const
|
||||||
// qualifier any initializer must be a constant expression."
|
// qualifier any initializer must be a constant expression."
|
||||||
if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
||||||
const char* initFeature = "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
|
const char* initFeature =
|
||||||
|
"non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
|
||||||
if (isEsProfile()) {
|
if (isEsProfile()) {
|
||||||
if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
|
if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
|
||||||
warn(loc, "not allowed in this version", initFeature, "");
|
warn(loc, "not allowed in this version", initFeature, "");
|
||||||
@ -6908,7 +6943,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
// Compile-time tagging of the variable with its constant value...
|
// Compile-time tagging of the variable with its constant value...
|
||||||
|
|
||||||
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
||||||
if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) {
|
if (! initializer || ! initializer->getType().getQualifier().isConstant() ||
|
||||||
|
variable->getType() != initializer->getType()) {
|
||||||
error(loc, "non-matching or non-convertible constant type for const initializer",
|
error(loc, "non-matching or non-convertible constant type for const initializer",
|
||||||
variable->getType().getStorageQualifierString(), "");
|
variable->getType().getStorageQualifierString(), "");
|
||||||
variable->getWritableType().getQualifier().makeTemporary();
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
|
@ -305,6 +305,7 @@ void TParseVersions::initializeExtensionBehavior()
|
|||||||
extensionBehavior[E_GL_EXT_tessellation_point_size] = EBhDisable;
|
extensionBehavior[E_GL_EXT_tessellation_point_size] = EBhDisable;
|
||||||
extensionBehavior[E_GL_EXT_texture_buffer] = EBhDisable;
|
extensionBehavior[E_GL_EXT_texture_buffer] = EBhDisable;
|
||||||
extensionBehavior[E_GL_EXT_texture_cube_map_array] = EBhDisable;
|
extensionBehavior[E_GL_EXT_texture_cube_map_array] = EBhDisable;
|
||||||
|
extensionBehavior[E_GL_EXT_null_initializer] = EBhDisable;
|
||||||
|
|
||||||
// OES matching AEP
|
// OES matching AEP
|
||||||
extensionBehavior[E_GL_OES_geometry_shader] = EBhDisable;
|
extensionBehavior[E_GL_OES_geometry_shader] = EBhDisable;
|
||||||
@ -408,9 +409,12 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||||||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
if (isEsProfile() && version >= 300) {
|
if (version >= 300) {
|
||||||
preamble += "#define GL_NV_shader_noperspective_interpolation 1\n";
|
preamble += "#define GL_NV_shader_noperspective_interpolation 1\n";
|
||||||
}
|
}
|
||||||
|
if (version >= 310) {
|
||||||
|
preamble += "#define GL_EXT_null_initializer 1\n";
|
||||||
|
}
|
||||||
|
|
||||||
} else { // !isEsProfile()
|
} else { // !isEsProfile()
|
||||||
preamble =
|
preamble =
|
||||||
@ -538,6 +542,9 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||||||
if (profile == ECompatibilityProfile)
|
if (profile == ECompatibilityProfile)
|
||||||
preamble += "#define GL_compatibility_profile 1\n";
|
preamble += "#define GL_compatibility_profile 1\n";
|
||||||
}
|
}
|
||||||
|
if (version >= 140) {
|
||||||
|
preamble += "#define GL_EXT_null_initializer 1\n";
|
||||||
|
}
|
||||||
#endif // GLSLANG_WEB
|
#endif // GLSLANG_WEB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +201,7 @@ const char* const E_GL_EXT_blend_func_extended = "GL_EXT_blend_func
|
|||||||
const char* const E_GL_EXT_shader_implicit_conversions = "GL_EXT_shader_implicit_conversions";
|
const char* const E_GL_EXT_shader_implicit_conversions = "GL_EXT_shader_implicit_conversions";
|
||||||
const char* const E_GL_EXT_fragment_shading_rate = "GL_EXT_fragment_shading_rate";
|
const char* const E_GL_EXT_fragment_shading_rate = "GL_EXT_fragment_shading_rate";
|
||||||
const char* const E_GL_EXT_shader_image_int64 = "GL_EXT_shader_image_int64";
|
const char* const E_GL_EXT_shader_image_int64 = "GL_EXT_shader_image_int64";
|
||||||
|
const char* const E_GL_EXT_null_initializer = "GL_EXT_null_initializer";
|
||||||
|
|
||||||
// Arrays of extensions for the above viewportEXTs duplications
|
// Arrays of extensions for the above viewportEXTs duplications
|
||||||
|
|
||||||
|
@ -3575,6 +3575,12 @@ GLSLANG_WEB_EXCLUDE_ON
|
|||||||
parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
|
| LEFT_BRACE RIGHT_BRACE {
|
||||||
|
const char* initFeature = "empty { } initializer";
|
||||||
|
parseContext.profileRequires($1.loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature);
|
||||||
|
parseContext.profileRequires($1.loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature);
|
||||||
|
$$ = parseContext.intermediate.makeAggregate($1.loc);
|
||||||
|
}
|
||||||
GLSLANG_WEB_EXCLUDE_OFF
|
GLSLANG_WEB_EXCLUDE_OFF
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -3575,6 +3575,12 @@ initializer
|
|||||||
parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
|
| LEFT_BRACE RIGHT_BRACE {
|
||||||
|
const char* initFeature = "empty { } initializer";
|
||||||
|
parseContext.profileRequires($1.loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature);
|
||||||
|
parseContext.profileRequires($1.loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature);
|
||||||
|
$$ = parseContext.intermediate.makeAggregate($1.loc);
|
||||||
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -376,6 +376,7 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
"spv.nonuniform4.frag",
|
"spv.nonuniform4.frag",
|
||||||
"spv.nonuniform5.frag",
|
"spv.nonuniform5.frag",
|
||||||
"spv.noWorkgroup.comp",
|
"spv.noWorkgroup.comp",
|
||||||
|
"spv.nullInit.comp",
|
||||||
"spv.offsets.frag",
|
"spv.offsets.frag",
|
||||||
"spv.Operations.frag",
|
"spv.Operations.frag",
|
||||||
"spv.paramMemory.frag",
|
"spv.paramMemory.frag",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user