8. io mapping refine & qualifier member check & resolver expand (#2396)

* Code refine and adding missing features

1. Add new level for built in symbols.
2. Fix issues for structure members' qualifiers.
3. Global qualifier fix.
4. IO Mapper refine. Add support for checking with mangle names.

* Additional missing features

* Invariant member. (Only check non-interface).

* Split block nesting level and struct nesting level. To fix issues of checking 'invariant' qualifier.

Current grammar would check block/struct member without its parent class's information.
So we split nesting level, and 'invariant' would only be checked within a struct.

* Format anonymous block names. Refine codes for symbols from all kinds of resouces.

* Fix writeonly check.

* Use LValueBase to find operator.

* Fix random null ptr issue.

* invariant check, stage in io mapping, reference parameter should be used and remove wrong codes introduced with ordering vector.

* Remained: to be fixed with double check link.vk.multiblocksValid

* Fix version error.

invariant

* Revert loc modification.
This commit is contained in:
Chow 2020-11-04 04:34:19 +08:00 committed by GitHub
parent d550bebee9
commit 478b232952
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 565 additions and 149 deletions

View File

@ -3959,6 +3959,8 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
// Name and decorate the non-hidden members // Name and decorate the non-hidden members
int offset = -1; int offset = -1;
int locationOffset = 0; // for use within the members of this struct int locationOffset = 0; // for use within the members of this struct
bool memberLocationInvalid = type.isArrayOfArrays() ||
(type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false));
for (int i = 0; i < (int)glslangMembers->size(); i++) { for (int i = 0; i < (int)glslangMembers->size(); i++) {
glslang::TType& glslangMember = *(*glslangMembers)[i].type; glslang::TType& glslangMember = *(*glslangMembers)[i].type;
int member = i; int member = i;
@ -4011,7 +4013,7 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
// just track whether a member needs to be decorated. // just track whether a member needs to be decorated.
// Ignore member locations if the container is an array, as that's // Ignore member locations if the container is an array, as that's
// ill-specified and decisions have been made to not allow this. // ill-specified and decisions have been made to not allow this.
if (! type.isArray() && memberQualifier.hasLocation()) if (!memberLocationInvalid && memberQualifier.hasLocation())
builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation); builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation);
if (qualifier.hasLocation()) // track for upcoming inheritance if (qualifier.hasLocation()) // track for upcoming inheritance

View File

@ -1,6 +1,7 @@
300layout.vert 300layout.vert
ERROR: 0:7: 'vertex input arrays' : not supported with this profile: es ERROR: 0:7: 'vertex input arrays' : not supported with this profile: es
ERROR: 0:8: 'in' : cannot be a structure or array ERROR: 0:8: 'in' : cannot be a structure or array
ERROR: 0:8: 's' : A structure containing an array is not allowed as input in ES
ERROR: 0:8: 'vertex input arrays' : not supported with this profile: es ERROR: 0:8: 'vertex input arrays' : not supported with this profile: es
ERROR: 0:8: 'location' : overlapping use of location 10 ERROR: 0:8: 'location' : overlapping use of location 10
ERROR: 0:12: 'layout' : cannot specify matrix layout on a variable declaration ERROR: 0:12: 'layout' : cannot specify matrix layout on a variable declaration
@ -18,7 +19,7 @@ ERROR: 0:50: 'shared' : not supported for this version or the enabled extensions
ERROR: 0:50: 'shared' : not supported in this stage: vertex ERROR: 0:50: 'shared' : not supported in this stage: vertex
ERROR: 0:54: 'layout' : cannot specify packing on a variable declaration ERROR: 0:54: 'layout' : cannot specify packing on a variable declaration
ERROR: 0:57: 'location' : overlapping use of location 40 ERROR: 0:57: 'location' : overlapping use of location 40
ERROR: 19 compilation errors. No code generated. ERROR: 20 compilation errors. No code generated.
Shader version: 300 Shader version: 300

View File

@ -40,10 +40,14 @@ ERROR: 0:112: 'out' : cannot be a matrix
ERROR: 0:114: 'in' : cannot be bool ERROR: 0:114: 'in' : cannot be bool
ERROR: 0:115: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: ino ERROR: 0:115: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: ino
ERROR: 0:117: 'fragment-shader array-of-array input' : not supported with this profile: es ERROR: 0:117: 'fragment-shader array-of-array input' : not supported with this profile: es
ERROR: 0:120: 'S' : A structure containing an array is not allowed as input in ES
ERROR: 0:120: 'fragment-shader array-of-struct input' : not supported with this profile: es ERROR: 0:120: 'fragment-shader array-of-struct input' : not supported with this profile: es
ERROR: 0:121: 'S' : A structure containing an array is not allowed as input in ES
ERROR: 0:121: 'fragment-shader array-of-struct input' : not supported with this profile: es ERROR: 0:121: 'fragment-shader array-of-struct input' : not supported with this profile: es
ERROR: 0:123: 'fragment-shader struct input containing an array' : not supported with this profile: es ERROR: 0:123: 'fragment-shader struct input containing an array' : not supported with this profile: es
ERROR: 0:123: 'SA' : A structure containing an array is not allowed as input in ES
ERROR: 0:125: 'fragment-shader struct input containing structure' : not supported with this profile: es ERROR: 0:125: 'fragment-shader struct input containing structure' : not supported with this profile: es
ERROR: 0:125: 'SS' : A structure containing an struct is not allowed as input in ES
ERROR: 0:133: 'output block' : not supported in this stage: fragment ERROR: 0:133: 'output block' : not supported in this stage: fragment
ERROR: 0:138: '' : cannot nest a structure definition inside a structure or block ERROR: 0:138: '' : cannot nest a structure definition inside a structure or block
ERROR: 0:146: 'location' : overlapping use of location 13 ERROR: 0:146: 'location' : overlapping use of location 13
@ -139,7 +143,7 @@ ERROR: 0:461: 'func' : function already has a body
ERROR: 0:463: 'return' : void function cannot return a value ERROR: 0:463: 'return' : void function cannot return a value
ERROR: 0:472: '=' : cannot convert from ' temp mediump uint' to ' temp mediump int' ERROR: 0:472: '=' : cannot convert from ' temp mediump uint' to ' temp mediump int'
ERROR: 0:485: '=' : cannot convert from ' global mediump int' to ' temp mediump uint' ERROR: 0:485: '=' : cannot convert from ' global mediump int' to ' temp mediump uint'
ERROR: 132 compilation errors. No code generated. ERROR: 136 compilation errors. No code generated.
Shader version: 310 Shader version: 310

View File

@ -21,6 +21,7 @@ ERROR: 0:105: 'location' : overlapping use of location 12
ERROR: 0:107: 'input block' : not supported in this stage: vertex ERROR: 0:107: 'input block' : not supported in this stage: vertex
ERROR: 0:109: 'gl_PerVertex' : block redeclaration has extra members ERROR: 0:109: 'gl_PerVertex' : block redeclaration has extra members
ERROR: 0:119: 'gl_PointSize' : member of nameless block was not redeclared ERROR: 0:119: 'gl_PointSize' : member of nameless block was not redeclared
ERROR: 0:119: 'assign' : l-value required "gl_PerVertex" (can't modify void)
ERROR: 0:119: 'assign' : cannot convert from ' const float' to ' gl_PointSize highp void PointSize' ERROR: 0:119: 'assign' : cannot convert from ' const float' to ' gl_PointSize highp void PointSize'
ERROR: 0:122: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use ERROR: 0:122: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use
ERROR: 0:127: 'flat/smooth/noperspective' : cannot use interpolation qualifiers on an interface block ERROR: 0:127: 'flat/smooth/noperspective' : cannot use interpolation qualifiers on an interface block
@ -96,7 +97,7 @@ ERROR: 0:389: 'sample' : Reserved word.
ERROR: 0:400: 'interpolateAtCentroid' : no matching overloaded function found ERROR: 0:400: 'interpolateAtCentroid' : no matching overloaded function found
ERROR: 0:401: 'interpolateAtSample' : no matching overloaded function found ERROR: 0:401: 'interpolateAtSample' : no matching overloaded function found
ERROR: 0:402: 'interpolateAtOffset' : no matching overloaded function found ERROR: 0:402: 'interpolateAtOffset' : no matching overloaded function found
ERROR: 93 compilation errors. No code generated. ERROR: 94 compilation errors. No code generated.
Shader version: 310 Shader version: 310

View File

@ -4,6 +4,7 @@ ERROR: 0:14: 'location' : overlapping use of location 12
ERROR: 0:16: 'input block' : not supported in this stage: vertex ERROR: 0:16: 'input block' : not supported in this stage: vertex
ERROR: 0:18: 'gl_PerVertex' : block redeclaration has extra members ERROR: 0:18: 'gl_PerVertex' : block redeclaration has extra members
ERROR: 0:28: 'gl_PointSize' : member of nameless block was not redeclared ERROR: 0:28: 'gl_PointSize' : member of nameless block was not redeclared
ERROR: 0:28: 'assign' : l-value required "gl_PerVertex" (can't modify void)
ERROR: 0:28: 'assign' : cannot convert from ' const float' to ' gl_PointSize highp void PointSize' ERROR: 0:28: 'assign' : cannot convert from ' const float' to ' gl_PointSize highp void PointSize'
ERROR: 0:31: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use ERROR: 0:31: 'gl_PerVertex' : can only redeclare a built-in block once, and before any use
ERROR: 0:36: 'flat/smooth/noperspective' : cannot use interpolation qualifiers on an interface block ERROR: 0:36: 'flat/smooth/noperspective' : cannot use interpolation qualifiers on an interface block
@ -33,7 +34,7 @@ ERROR: 0:211: '=' : cannot convert from ' const float' to ' temp highp 3-compon
ERROR: 0:252: 'interpolateAtCentroid' : no matching overloaded function found ERROR: 0:252: 'interpolateAtCentroid' : no matching overloaded function found
ERROR: 0:253: 'interpolateAtSample' : no matching overloaded function found ERROR: 0:253: 'interpolateAtSample' : no matching overloaded function found
ERROR: 0:254: 'interpolateAtOffset' : no matching overloaded function found ERROR: 0:254: 'interpolateAtOffset' : no matching overloaded function found
ERROR: 34 compilation errors. No code generated. ERROR: 35 compilation errors. No code generated.
Shader version: 320 Shader version: 320

View File

@ -5,9 +5,10 @@ ERROR: 0:20: 'gl_PerVertex' : can only redeclare a built-in block once, and befo
ERROR: 0:32: 'gl_Position' : no such field in structure ERROR: 0:32: 'gl_Position' : no such field in structure
ERROR: 0:32: '=' : cannot convert from ' temp block{ in float PointSize gl_PointSize}' to ' temp 4-component vector of float' ERROR: 0:32: '=' : cannot convert from ' temp block{ in float PointSize gl_PointSize}' to ' temp 4-component vector of float'
ERROR: 0:33: 'gl_Position' : member of nameless block was not redeclared ERROR: 0:33: 'gl_Position' : member of nameless block was not redeclared
ERROR: 0:33: 'assign' : l-value required "gl_PerVertex" (can't modify void)
ERROR: 0:33: 'assign' : cannot convert from ' const 4-component vector of float' to 'layout( stream=0) gl_Position void Position' ERROR: 0:33: 'assign' : cannot convert from ' const 4-component vector of float' to 'layout( stream=0) gl_Position void Position'
WARNING: 0:38: 'return' : type conversion on return values was not explicitly allowed until version 420 WARNING: 0:38: 'return' : type conversion on return values was not explicitly allowed until version 420
ERROR: 7 compilation errors. No code generated. ERROR: 8 compilation errors. No code generated.
Shader version: 410 Shader version: 410

View File

@ -190,13 +190,13 @@ Validation failed
Decorate 9 BufferBlock Decorate 9 BufferBlock
Decorate 12 BufferBlock Decorate 12 BufferBlock
Decorate 49(sbuf_a) DescriptorSet 0 Decorate 49(sbuf_a) DescriptorSet 0
Decorate 49(sbuf_a) Binding 4 Decorate 49(sbuf_a) Binding 0
Decorate 50(sbuf_a@count) DescriptorSet 0 Decorate 50(sbuf_a@count) DescriptorSet 0
Decorate 50(sbuf_a@count) Binding 6 Decorate 50(sbuf_a@count) Binding 0
Decorate 51(sbuf_c) DescriptorSet 0 Decorate 51(sbuf_c) DescriptorSet 0
Decorate 51(sbuf_c) Binding 5 Decorate 51(sbuf_c) Binding 1
Decorate 52(sbuf_c@count) DescriptorSet 0 Decorate 52(sbuf_c@count) DescriptorSet 0
Decorate 52(sbuf_c@count) Binding 7 Decorate 52(sbuf_c@count) Binding 0
Decorate 58(pos) Flat Decorate 58(pos) Flat
Decorate 58(pos) Location 0 Decorate 58(pos) Location 0
Decorate 61(@entryPointOutput) Location 0 Decorate 61(@entryPointOutput) Location 0

View File

@ -191,9 +191,9 @@ Validation failed
Decorate 18 BufferBlock Decorate 18 BufferBlock
Decorate 20 BufferBlock Decorate 20 BufferBlock
Decorate 47(sbuf2) DescriptorSet 0 Decorate 47(sbuf2) DescriptorSet 0
Decorate 47(sbuf2) Binding 2 Decorate 47(sbuf2) Binding 0
Decorate 48(sbuf2@count) DescriptorSet 0 Decorate 48(sbuf2@count) DescriptorSet 0
Decorate 48(sbuf2@count) Binding 3 Decorate 48(sbuf2@count) Binding 0
Decorate 50(sbuf) DescriptorSet 0 Decorate 50(sbuf) DescriptorSet 0
Decorate 50(sbuf) Binding 10 Decorate 50(sbuf) Binding 10
Decorate 63(pos) Flat Decorate 63(pos) Flat

View File

@ -211,7 +211,7 @@ Shader version: 430
Name 70 "BufferBlock" Name 70 "BufferBlock"
MemberName 70(BufferBlock) 0 "p" MemberName 70(BufferBlock) 0 "p"
Name 72 "uBuf" Name 72 "uBuf"
Decorate 14(oColor) Location 4 Decorate 14(oColor) Location 2
MemberDecorate 16(ColorBlock) 0 Offset 0 MemberDecorate 16(ColorBlock) 0 Offset 0
MemberDecorate 16(ColorBlock) 1 Offset 16 MemberDecorate 16(ColorBlock) 1 Offset 16
MemberDecorate 16(ColorBlock) 2 Offset 32 MemberDecorate 16(ColorBlock) 2 Offset 32
@ -224,7 +224,7 @@ Shader version: 430
Decorate 28(uColorBuf) DescriptorSet 0 Decorate 28(uColorBuf) DescriptorSet 0
Decorate 28(uColorBuf) Binding 0 Decorate 28(uColorBuf) Binding 0
Decorate 32(Vertex) Block Decorate 32(Vertex) Block
Decorate 34(oV) Location 2 Decorate 34(oV) Location 0
MemberDecorate 40(gl_PerVertex) 0 BuiltIn Position MemberDecorate 40(gl_PerVertex) 0 BuiltIn Position
MemberDecorate 40(gl_PerVertex) 1 BuiltIn PointSize MemberDecorate 40(gl_PerVertex) 1 BuiltIn PointSize
MemberDecorate 40(gl_PerVertex) 2 BuiltIn ClipDistance MemberDecorate 40(gl_PerVertex) 2 BuiltIn ClipDistance

View File

@ -304,7 +304,7 @@ output primitive = triangle_strip
MemberName 95(BufferBlock) 0 "p" MemberName 95(BufferBlock) 0 "p"
Name 97 "uBuf" Name 97 "uBuf"
Name 100 "P" Name 100 "P"
Decorate 18(oColor) Location 2 Decorate 18(oColor) Location 1
MemberDecorate 20(ColorBlock) 0 Offset 0 MemberDecorate 20(ColorBlock) 0 Offset 0
MemberDecorate 20(ColorBlock) 1 Offset 16 MemberDecorate 20(ColorBlock) 1 Offset 16
MemberDecorate 20(ColorBlock) 2 Offset 32 MemberDecorate 20(ColorBlock) 2 Offset 32
@ -326,16 +326,16 @@ output primitive = triangle_strip
Decorate 50(uM) DescriptorSet 0 Decorate 50(uM) DescriptorSet 0
Decorate 50(uM) Binding 0 Decorate 50(uM) Binding 0
Decorate 59(Vertex) Block Decorate 59(Vertex) Block
Decorate 61(oV) Location 1 Decorate 61(oV) Location 0
Decorate 64(Vertex) Block Decorate 64(Vertex) Block
Decorate 68(iV) Location 0 Decorate 68(iV) Location 1
MemberDecorate 95(BufferBlock) 0 ColMajor MemberDecorate 95(BufferBlock) 0 ColMajor
MemberDecorate 95(BufferBlock) 0 Offset 0 MemberDecorate 95(BufferBlock) 0 Offset 0
MemberDecorate 95(BufferBlock) 0 MatrixStride 16 MemberDecorate 95(BufferBlock) 0 MatrixStride 16
Decorate 95(BufferBlock) BufferBlock Decorate 95(BufferBlock) BufferBlock
Decorate 97(uBuf) DescriptorSet 0 Decorate 97(uBuf) DescriptorSet 0
Decorate 97(uBuf) Binding 1 Decorate 97(uBuf) Binding 1
Decorate 100(P) Location 4 Decorate 100(P) Location 0
2: TypeVoid 2: TypeVoid
3: TypeFunction 2 3: TypeFunction 2
6: TypeFloat 32 6: TypeFloat 32

View File

@ -11,7 +11,7 @@ spv.specConstant.vert
Source GLSL 400 Source GLSL 400
Name 4 "main" Name 4 "main"
Name 9 "arraySize" Name 9 "arraySize"
Name 14 "foo(vf4[s4546];" Name 14 "foo(vf4[s805310914];"
Name 13 "p" Name 13 "p"
Name 17 "builtin_spec_constant(" Name 17 "builtin_spec_constant("
Name 20 "color" Name 20 "color"
@ -106,10 +106,10 @@ spv.specConstant.vert
Store 20(color) 46 Store 20(color) 46
48: 10 Load 22(ucol) 48: 10 Load 22(ucol)
Store 47(param) 48 Store 47(param) 48
49: 2 FunctionCall 14(foo(vf4[s4546];) 47(param) 49: 2 FunctionCall 14(foo(vf4[s805310914];) 47(param)
Return Return
FunctionEnd FunctionEnd
14(foo(vf4[s4546];): 2 Function None 12 14(foo(vf4[s805310914];): 2 Function None 12
13(p): 11(ptr) FunctionParameter 13(p): 11(ptr) FunctionParameter
15: Label 15: Label
54: 24(ptr) AccessChain 53(dupUcol) 23 54: 24(ptr) AccessChain 53(dupUcol) 23

View File

@ -1282,6 +1282,8 @@ public:
TIntermTyped* getConstSubtree() const { return constSubtree; } TIntermTyped* getConstSubtree() const { return constSubtree; }
#ifndef GLSLANG_WEB #ifndef GLSLANG_WEB
void setFlattenSubset(int subset) { flattenSubset = subset; } void setFlattenSubset(int subset) { flattenSubset = subset; }
virtual const TString& getAccessName() const;
int getFlattenSubset() const { return flattenSubset; } // -1 means full object int getFlattenSubset() const { return flattenSubset; } // -1 means full object
#endif #endif

View File

@ -71,6 +71,13 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it)
it->visitConstantUnion(this); it->visitConstantUnion(this);
} }
const TString& TIntermSymbol::getAccessName() const {
if (getBasicType() == EbtBlock)
return getType().getTypeName();
else
return getName();
}
// //
// Traverse a binary node. // Traverse a binary node.
// //

View File

@ -127,22 +127,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
{ {
TIntermBinary* binaryNode = node->getAsBinaryNode(); TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
}
const char* symbol = nullptr; const char* symbol = nullptr;
TIntermSymbol* symNode = node->getAsSymbolNode(); TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode != nullptr) if (symNode != nullptr)
@ -203,15 +187,40 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
// Everything else is okay, no error. // Everything else is okay, no error.
// //
if (message == nullptr) if (message == nullptr)
{
if (binaryNode) {
switch (binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
}
return false; return false;
}
// //
// If we get here, we have an error and a message. // If we get here, we have an error and a message.
// //
const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
if (symNode) if (symNode)
error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
else else
error(loc, " l-value required", op, "(%s)", message); if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct)
if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message);
else
error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message);
else
error(loc, " l-value required", op, "(%s)", message);
return true; return true;
} }
@ -219,28 +228,41 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
// Test for and give an error if the node can't be read from. // Test for and give an error if the node can't be read from.
void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{ {
TIntermBinary* binaryNode = node->getAsBinaryNode();
const TIntermSymbol* symNode = node->getAsSymbolNode();
if (! node) if (! node)
return; return;
TIntermBinary* binaryNode = node->getAsBinaryNode(); if (node->getQualifier().isWriteOnly()) {
if (binaryNode) { const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
switch(binaryNode->getOp()) {
case EOpIndexDirect: if (symNode != nullptr)
case EOpIndexIndirect: error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
case EOpIndexDirectStruct: else if (binaryNode &&
case EOpVectorSwizzle: (binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct ||
case EOpMatrixSwizzle: binaryNode->getAsOperator()->getOp() == EOpIndexDirect))
rValueErrorCheck(loc, op, binaryNode->getLeft()); if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
default: error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str());
break; else
error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str());
else
error(loc, "can't read from writeonly object: ", op, "");
} else {
if (binaryNode) {
switch (binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
} }
return;
} }
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode && symNode->getQualifier().isWriteOnly())
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
} }
// Add 'symbol' to the list of deferred linkage symbols, which // Add 'symbol' to the list of deferred linkage symbols, which

View File

@ -3368,7 +3368,7 @@ void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& t
// //
void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
{ {
globalQualifierFixCheck(publicType.loc, publicType.qualifier); globalQualifierFixCheck(publicType.loc, publicType.qualifier, true);
checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers); checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers);
if (publicType.qualifier.isNonUniform()) { if (publicType.qualifier.isNonUniform()) {
error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", ""); error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", "");
@ -3379,7 +3379,7 @@ void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
// //
// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
// //
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier) void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck)
{ {
bool nonuniformOkay = false; bool nonuniformOkay = false;
@ -3404,6 +3404,16 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
case EvqTemporary: case EvqTemporary:
nonuniformOkay = true; nonuniformOkay = true;
break; break;
case EvqUniform:
// According to GLSL spec: The std430 qualifier is supported only for shader storage blocks; a shader using
// the std430 qualifier on a uniform block will fail to compile.
// Only check the global declaration: layout(std430) uniform;
if (blockName == nullptr &&
qualifier.layoutPacking == ElpStd430)
{
error(loc, "it is invalid to declare std430 qualifier on uniform", "", "");
}
break;
default: default:
break; break;
} }
@ -3411,7 +3421,9 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
if (!nonuniformOkay && qualifier.isNonUniform()) if (!nonuniformOkay && qualifier.isNonUniform())
error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", ""); error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", "");
invariantCheck(loc, qualifier); // Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it.
if (!isMemberCheck || structNestingLevel > 0)
invariantCheck(loc, qualifier);
} }
// //
@ -4083,6 +4095,9 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType
if (isRuntimeLength(base)) if (isRuntimeLength(base))
return; return;
if (base.getType().getQualifier().builtIn == EbvSampleMask)
return;
// Check for last member of a bufferreference type, which is runtime sizeable // Check for last member of a bufferreference type, which is runtime sizeable
// but doesn't support runtime length // but doesn't support runtime length
if (base.getType().getQualifier().storage == EvqBuffer) { if (base.getType().getQualifier().storage == EvqBuffer) {
@ -4634,14 +4649,14 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali
void TParseContext::nestedBlockCheck(const TSourceLoc& loc) void TParseContext::nestedBlockCheck(const TSourceLoc& loc)
{ {
if (structNestingLevel > 0) if (structNestingLevel > 0 || blockNestingLevel > 0)
error(loc, "cannot nest a block definition inside a structure or block", "", ""); error(loc, "cannot nest a block definition inside a structure or block", "", "");
++structNestingLevel; ++blockNestingLevel;
} }
void TParseContext::nestedStructCheck(const TSourceLoc& loc) void TParseContext::nestedStructCheck(const TSourceLoc& loc)
{ {
if (structNestingLevel > 0) if (structNestingLevel > 0 || blockNestingLevel > 0)
error(loc, "cannot nest a structure definition inside a structure or block", "", ""); error(loc, "cannot nest a structure definition inside a structure or block", "", "");
++structNestingLevel; ++structNestingLevel;
} }
@ -6537,13 +6552,15 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType
error(loc, "atomic_uint binding is too large", "binding", ""); error(loc, "atomic_uint binding is too large", "binding", "");
return; return;
} }
if (publicType.qualifier.hasOffset())
if(publicType.qualifier.hasOffset()) {
atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset; atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
}
return; return;
} }
if (publicType.arraySizes) {
error(loc, "expect an array name", "", "");
}
if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference()) if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference())
warn(loc, "useless application of layout qualifier", "layout", ""); warn(loc, "useless application of layout qualifier", "layout", "");
#endif #endif
@ -6634,6 +6651,22 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
if (type.getQualifier().storage == EvqShared && type.containsCoopMat()) if (type.getQualifier().storage == EvqShared && type.containsCoopMat())
error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", ""); error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", "");
if (profile == EEsProfile) {
if (type.getQualifier().isPipeInput() && type.getBasicType() == EbtStruct) {
if (type.getQualifier().isArrayedIo(language)) {
TType perVertexType(type, 0);
if (perVertexType.containsArray() && perVertexType.containsBuiltIn() == false) {
error(loc, "A per vertex structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
}
}
else if (type.containsArray() && type.containsBuiltIn() == false) {
error(loc, "A structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
}
if (type.containsStructure())
error(loc, "A structure containing an struct is not allowed as input in ES", type.getTypeName().c_str(), "");
}
}
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger)) if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", ""); error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone) if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone)
@ -6956,6 +6989,15 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const
error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str()); error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str());
return nullptr; return nullptr;
} }
TBasicType destType = type.getBasicType();
for (int i = 0; i < type.getVectorSize(); ++i) {
TBasicType initType = initList->getSequence()[i]->getAsTyped()->getBasicType();
if (destType != initType && !intermediate.canImplicitlyPromote(initType, destType)) {
error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString().c_str());
return nullptr;
}
}
} else { } else {
error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str()); error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str());
return nullptr; return nullptr;
@ -7492,10 +7534,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
TType& memberType = *typeList[member].type; TType& memberType = *typeList[member].type;
TQualifier& memberQualifier = memberType.getQualifier(); TQualifier& memberQualifier = memberType.getQualifier();
const TSourceLoc& memberLoc = typeList[member].loc; const TSourceLoc& memberLoc = typeList[member].loc;
globalQualifierFixCheck(memberLoc, memberQualifier);
if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage) if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), ""); error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
memberQualifier.storage = currentBlockQualifier.storage; memberQualifier.storage = currentBlockQualifier.storage;
globalQualifierFixCheck(memberLoc, memberQualifier);
#ifndef GLSLANG_WEB #ifndef GLSLANG_WEB
inheritMemoryQualifiers(currentBlockQualifier, memberQualifier); inheritMemoryQualifiers(currentBlockQualifier, memberQualifier);
if (currentBlockQualifier.perPrimitiveNV) if (currentBlockQualifier.perPrimitiveNV)
@ -8193,7 +8235,7 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
bool pipeOut = qualifier.isPipeOutput(); bool pipeOut = qualifier.isPipeOutput();
bool pipeIn = qualifier.isPipeInput(); bool pipeIn = qualifier.isPipeInput();
if (version >= 300 || (!isEsProfile() && version >= 420)) { if ((version >= 300 && isEsProfile()) || (!isEsProfile() && version >= 420)) {
if (! pipeOut) if (! pipeOut)
error(loc, "can only apply to an output", "invariant", ""); error(loc, "can only apply to an output", "invariant", "");
} else { } else {

View File

@ -83,7 +83,7 @@ public:
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), : TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
scopeMangler("::"), scopeMangler("::"),
symbolTable(symbolTable), symbolTable(symbolTable),
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), blockNestingLevel(0), controlFlowNestingLevel(0),
currentFunctionType(nullptr), currentFunctionType(nullptr),
postEntryPointReturn(false), postEntryPointReturn(false),
contextPragma(true, false), contextPragma(true, false),
@ -178,7 +178,8 @@ public:
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
int statementNestingLevel; // 0 if outside all flow control or compound statements int statementNestingLevel; // 0 if outside all flow control or compound statements
int loopNestingLevel; // 0 if outside all loops int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures int structNestingLevel; // 0 if outside structures
int blockNestingLevel; // 0 if outside blocks
int controlFlowNestingLevel; // 0 if outside all flow control int controlFlowNestingLevel; // 0 if outside all flow control
const TType* currentFunctionType; // the return type of the function that's currently being parsed const TType* currentFunctionType; // the return type of the function that's currently being parsed
bool functionReturnsValue; // true if a non-void function has a return bool functionReturnsValue; // true if a non-void function has a return
@ -365,7 +366,7 @@ public:
void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier); void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier); void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
void memberQualifierCheck(glslang::TPublicType&); void memberQualifierCheck(glslang::TPublicType&);
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&); void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false);
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&); void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);

View File

@ -982,7 +982,7 @@ int TScanContext::tokenizeIdentifier()
return keyword; return keyword;
case PACKED: case PACKED:
if ((parseContext.isEsProfile() && parseContext.version < 300) || if ((parseContext.isEsProfile() && parseContext.version < 300) ||
(!parseContext.isEsProfile() && parseContext.version < 330)) (!parseContext.isEsProfile() && parseContext.version < 140))
return reservedWord(); return reservedWord();
return identifierOrType(); return identifierOrType();

View File

@ -146,6 +146,8 @@ void TType::buildMangledName(TString& mangledName) const
if (typeName) if (typeName)
mangledName += *typeName; mangledName += *typeName;
for (unsigned int i = 0; i < structure->size(); ++i) { for (unsigned int i = 0; i < structure->size(); ++i) {
if ((*structure)[i].type->getBasicType() == EbtVoid)
continue;
mangledName += '-'; mangledName += '-';
(*structure)[i].type->buildMangledName(mangledName); (*structure)[i].type->buildMangledName(mangledName);
} }

View File

@ -613,20 +613,24 @@ public:
// //
protected: protected:
static const int globalLevel = 3; static const int globalLevel = 3;
bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels static bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals static bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals static bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
public: public:
bool isEmpty() { return table.size() == 0; } bool isEmpty() { return table.size() == 0; }
bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); } bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
bool atGlobalLevel() { return isGlobalLevel(currentLevel()); } bool atGlobalLevel() { return isGlobalLevel(currentLevel()); }
static bool isBuiltInSymbol(int uniqueId) {
int level = uniqueId >> LevelFlagBitOffset;
return isBuiltInLevel(level);
}
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; } void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
void setSeparateNameSpaces() { separateNameSpaces = true; } void setSeparateNameSpaces() { separateNameSpaces = true; }
void push() void push()
{ {
table.push_back(new TSymbolTableLevel); table.push_back(new TSymbolTableLevel);
updateUniqueIdLevelFlag();
} }
// Make a new symbol-table level to represent the scope introduced by a structure // Make a new symbol-table level to represent the scope introduced by a structure
@ -639,6 +643,7 @@ public:
{ {
assert(thisSymbol.getName().size() == 0); assert(thisSymbol.getName().size() == 0);
table.push_back(new TSymbolTableLevel); table.push_back(new TSymbolTableLevel);
updateUniqueIdLevelFlag();
table.back()->setThisLevel(); table.back()->setThisLevel();
insert(thisSymbol); insert(thisSymbol);
} }
@ -648,6 +653,7 @@ public:
table[currentLevel()]->getPreviousDefaultPrecisions(p); table[currentLevel()]->getPreviousDefaultPrecisions(p);
delete table.back(); delete table.back();
table.pop_back(); table.pop_back();
updateUniqueIdLevelFlag();
} }
// //
@ -867,12 +873,20 @@ public:
table[level]->readOnly(); table[level]->readOnly();
} }
// Add current level in the high-bits of unique id
void updateUniqueIdLevelFlag() {
// clamp level to avoid overflow
uint32_t level = currentLevel() > 7 ? 7 : currentLevel();
uniqueId &= ((1 << LevelFlagBitOffset) - 1);
uniqueId |= (level << LevelFlagBitOffset);
}
protected: protected:
TSymbolTable(TSymbolTable&); TSymbolTable(TSymbolTable&);
TSymbolTable& operator=(TSymbolTableLevel&); TSymbolTable& operator=(TSymbolTableLevel&);
int currentLevel() const { return static_cast<int>(table.size()) - 1; } int currentLevel() const { return static_cast<int>(table.size()) - 1; }
static const uint32_t LevelFlagBitOffset = 28;
std::vector<TSymbolTableLevel*> table; std::vector<TSymbolTableLevel*> table;
int uniqueId; // for unique identification in code generation int uniqueId; // for unique identification in code generation
bool noBuiltInRedeclarations; bool noBuiltInRedeclarations;

View File

@ -905,7 +905,7 @@ declaration
block_structure block_structure
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE { : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
--parseContext.structNestingLevel; --parseContext.blockNestingLevel;
parseContext.blockName = $2.string; parseContext.blockName = $2.string;
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier); parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

View File

@ -905,7 +905,7 @@ declaration
block_structure block_structure
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE { : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
--parseContext.structNestingLevel; --parseContext.blockNestingLevel;
parseContext.blockName = $2.string; parseContext.blockName = $2.string;
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier); parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

View File

@ -5186,7 +5186,7 @@ yyreduce:
case 104: case 104:
#line 907 "MachineIndependent/glslang.y" /* yacc.c:1646 */ #line 907 "MachineIndependent/glslang.y" /* yacc.c:1646 */
{ {
--parseContext.structNestingLevel; --parseContext.blockNestingLevel;
parseContext.blockName = (yyvsp[-4].lex).string; parseContext.blockName = (yyvsp[-4].lex).string;
parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier); parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier);
parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers); parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers);

View File

@ -37,9 +37,11 @@
#include "../Include/Common.h" #include "../Include/Common.h"
#include "../Include/InfoSink.h" #include "../Include/InfoSink.h"
#include "../Include/Types.h"
#include "gl_types.h" #include "gl_types.h"
#include "iomapper.h" #include "iomapper.h"
#include "SymbolTable.h"
// //
// Map IO bindings. // Map IO bindings.
@ -82,17 +84,17 @@ public:
// If a global is being visited, then we should also traverse it incase it's evaluation // If a global is being visited, then we should also traverse it incase it's evaluation
// ends up visiting inputs we want to tag as live // ends up visiting inputs we want to tag as live
else if (base->getQualifier().storage == EvqGlobal) else if (base->getQualifier().storage == EvqGlobal)
addGlobalReference(base->getName()); addGlobalReference(base->getAccessName());
if (target) { if (target) {
TVarEntryInfo ent = {base->getId(), base, ! traverseAll}; TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
ent.stage = intermediate.getStage(); ent.stage = intermediate.getStage();
TVarLiveMap::iterator at = target->find( TVarLiveMap::iterator at = target->find(
ent.symbol->getName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
if (at != target->end() && at->second.id == ent.id) if (at != target->end() && at->second.id == ent.id)
at->second.live = at->second.live || ! traverseAll; // update live state at->second.live = at->second.live || ! traverseAll; // update live state
else else
(*target)[ent.symbol->getName()] = ent; (*target)[ent.symbol->getAccessName()] = ent;
} }
} }
@ -125,7 +127,8 @@ public:
return; return;
TVarEntryInfo ent = { base->getId() }; TVarEntryInfo ent = { base->getId() };
TVarLiveMap::const_iterator at = source->find(base->getName()); // Fix a defect, when block has no instance name, we need to find its block name
TVarLiveMap::const_iterator at = source->find(base->getAccessName());
if (at == source->end()) if (at == source->end())
return; return;
@ -181,7 +184,7 @@ struct TNotifyInOutAdaptor
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
{ {
resolver.notifyInOut(stage, entKey.second); resolver.notifyInOut(entKey.second.stage, entKey.second);
} }
private: private:
@ -189,12 +192,13 @@ private:
}; };
struct TResolverUniformAdaptor { struct TResolverUniformAdaptor {
TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e) TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TVarLiveMap* uniform[EShLangCount], TInfoSink& i, bool& e)
: stage(s) : stage(s)
, resolver(r) , resolver(r)
, infoSink(i) , infoSink(i)
, error(e) , error(e)
{ {
memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
} }
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) { inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
@ -206,9 +210,9 @@ struct TResolverUniformAdaptor {
ent.newIndex = -1; ent.newIndex = -1;
const bool isValid = resolver.validateBinding(stage, ent); const bool isValid = resolver.validateBinding(stage, ent);
if (isValid) { if (isValid) {
resolver.resolveBinding(stage, ent); resolver.resolveBinding(ent.stage, ent);
resolver.resolveSet(stage, ent); resolver.resolveSet(ent.stage, ent);
resolver.resolveUniformLocation(stage, ent); resolver.resolveUniformLocation(ent.stage, ent);
if (ent.newBinding != -1) { if (ent.newBinding != -1) {
if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) { if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
@ -217,6 +221,17 @@ struct TResolverUniformAdaptor {
infoSink.info.message(EPrefixInternalError, err.c_str()); infoSink.info.message(EPrefixInternalError, err.c_str());
error = true; error = true;
} }
if (ent.symbol->getQualifier().hasBinding()) {
for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
if (idx == ent.stage || uniformVarMap[idx] == nullptr)
continue;
auto entKey2 = uniformVarMap[idx]->find(entKey.first);
if (entKey2 != uniformVarMap[idx]->end()) {
entKey2->second.newBinding = ent.newBinding;
}
}
}
} }
if (ent.newSet != -1) { if (ent.newSet != -1) {
if (ent.newSet >= int(TQualifier::layoutSetEnd)) { if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
@ -225,6 +240,16 @@ struct TResolverUniformAdaptor {
infoSink.info.message(EPrefixInternalError, err.c_str()); infoSink.info.message(EPrefixInternalError, err.c_str());
error = true; error = true;
} }
if (ent.symbol->getQualifier().hasSet()) {
for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
if ((idx == stage) || (uniformVarMap[idx] == nullptr))
continue;
auto entKey2 = uniformVarMap[idx]->find(entKey.first);
if (entKey2 != uniformVarMap[idx]->end()) {
entKey2->second.newSet = ent.newSet;
}
}
}
} }
} else { } else {
TString errorMsg = "Invalid binding: " + entKey.first; TString errorMsg = "Invalid binding: " + entKey.first;
@ -239,7 +264,7 @@ struct TResolverUniformAdaptor {
TIoMapResolver& resolver; TIoMapResolver& resolver;
TInfoSink& infoSink; TInfoSink& infoSink;
bool& error; bool& error;
TVarLiveMap* uniformVarMap[EShLangCount];
private: private:
TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete; TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
}; };
@ -261,7 +286,7 @@ struct TResolverInOutAdaptor {
ent.newBinding = -1; ent.newBinding = -1;
ent.newSet = -1; ent.newSet = -1;
ent.newIndex = -1; ent.newIndex = -1;
const bool isValid = resolver.validateInOut(stage, ent); const bool isValid = resolver.validateInOut(ent.stage, ent);
if (isValid) { if (isValid) {
resolver.resolveInOutLocation(stage, ent); resolver.resolveInOutLocation(stage, ent);
resolver.resolveInOutComponent(stage, ent); resolver.resolveInOutComponent(stage, ent);
@ -296,17 +321,116 @@ private:
struct TSymbolValidater struct TSymbolValidater
{ {
TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount], TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount],
TVarLiveMap* uniform[EShLangCount], bool& hadError) TVarLiveMap* uniform[EShLangCount], bool& hadError, EProfile profile, int version)
: preStage(EShLangCount) : preStage(EShLangCount)
, currentStage(EShLangCount) , currentStage(EShLangCount)
, nextStage(EShLangCount) , nextStage(EShLangCount)
, resolver(r) , resolver(r)
, infoSink(i) , infoSink(i)
, hadError(hadError) , hadError(hadError)
, profile(profile)
, version(version)
{ {
memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*))); memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*))); memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*)));
memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*))); memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
std::map<TString, TString> anonymousMemberMap;
std::vector<TRange> usedUniformLocation;
std::vector<TString> usedUniformName;
usedUniformLocation.clear();
usedUniformName.clear();
for (int i = 0; i < EShLangCount; i++) {
if (uniformVarMap[i]) {
for (auto uniformVar : *uniformVarMap[i])
{
TIntermSymbol* pSymbol = uniformVar.second.symbol;
TQualifier qualifier = uniformVar.second.symbol->getQualifier();
TString symbolName = pSymbol->getAccessName();
// All the uniform needs multi-stage location check (block/default)
int uniformLocation = qualifier.layoutLocation;
if (uniformLocation != TQualifier::layoutLocationEnd) {
// Total size of current uniform, could be block, struct or other types.
int size = TIntermediate::computeTypeUniformLocationSize(pSymbol->getType());
TRange locationRange(uniformLocation, uniformLocation + size - 1);
// Combine location and component ranges
int overlapLocation = -1;
bool diffLocation = false;
// Check for collisions, except for vertex inputs on desktop targeting OpenGL
overlapLocation = checkLocationOverlap(locationRange, usedUniformLocation, symbolName, usedUniformName, diffLocation);
// Overlap locations of uniforms, regardless of components (multi stages)
if (overlapLocation == -1) {
usedUniformLocation.push_back(locationRange);
usedUniformName.push_back(symbolName);
}
else if (overlapLocation >= 0) {
if (diffLocation == true) {
TString err = "Uniform location should be equal for same uniforms: " + overlapLocation;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
else {
TString err = "Uniform location overlaps across stages: " + overlapLocation;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
}
if ((uniformVar.second.symbol->getBasicType() == EbtBlock) &&
IsAnonymous(uniformVar.second.symbol->getName()))
{
auto blockType = uniformVar.second.symbol->getType().getStruct();
for (size_t memberIdx = 0; memberIdx < blockType->size(); ++memberIdx) {
auto memberName = (*blockType)[memberIdx].type->getFieldName();
if (anonymousMemberMap.find(memberName) != anonymousMemberMap.end())
{
if (anonymousMemberMap[memberName] != uniformVar.second.symbol->getType().getTypeName())
{
TString err = "Invalid block member name: " + memberName;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
else
{
anonymousMemberMap[memberName] = uniformVar.second.symbol->getType().getTypeName();
}
}
}
if (hadError)
break;
}
}
}
}
// In case we need to new an intermediate, which costs too much
int checkLocationOverlap(const TRange& locationRange, std::vector<TRange>& usedUniformLocation, const TString symbolName, std::vector<TString>& usedUniformName, bool& diffLocation)
{
for (size_t r = 0; r < usedUniformLocation.size(); ++r) {
if (usedUniformName[r] == symbolName) {
diffLocation = true;
return (usedUniformLocation[r].start == locationRange.start &&
usedUniformLocation[r].last == locationRange.last)
? -2 : std::max(locationRange.start, usedUniformLocation[r].start);
}
if (locationRange.overlap(usedUniformLocation[r])) {
// there is a collision; pick one
return std::max(locationRange.start, usedUniformLocation[r].start);
}
}
return -1; // no collision
} }
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) { inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
@ -339,11 +463,24 @@ struct TSymbolValidater
// validate stage in; // validate stage in;
if (preStage == EShLangCount) if (preStage == EShLangCount)
return; return;
if (name == "gl_PerVertex") if (TSymbolTable::isBuiltInSymbol(base->getId()))
return; return;
if (outVarMaps[preStage] != nullptr) { if (outVarMaps[preStage] != nullptr) {
auto ent2 = outVarMaps[preStage]->find(name); auto ent2 = outVarMaps[preStage]->find(name);
uint32_t location = base->getType().getQualifier().layoutLocation;
if (ent2 == outVarMaps[preStage]->end() &&
location != glslang::TQualifier::layoutLocationEnd) {
for (auto var = outVarMaps[preStage]->begin(); var != ent2; var++) {
if (var->second.symbol->getType().getQualifier().layoutLocation == location) {
ent2 = var;
break;
}
}
}
if (ent2 != outVarMaps[preStage]->end()) { if (ent2 != outVarMaps[preStage]->end()) {
auto& type1 = base->getType();
auto& type2 = ent2->second.symbol->getType();
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) { if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) {
TType subType(ent2->second.symbol->getType(), 0); TType subType(ent2->second.symbol->getType(), 0);
subType.appendMangledName(mangleName2); subType.appendMangledName(mangleName2);
@ -351,23 +488,49 @@ struct TSymbolValidater
else { else {
ent2->second.symbol->getType().appendMangledName(mangleName2); ent2->second.symbol->getType().appendMangledName(mangleName2);
} }
if (mangleName1 == mangleName2)
if (mangleName1 == mangleName2) {
// For ES 3.0 only, other versions have no such restrictions
// According to ES 3.0 spec: The type and presence of the interpolation qualifiers and
// storage qualifiers of variables with the same name declared in all linked shaders must
// match, otherwise the link command will fail.
if (profile == EEsProfile && version == 300) {
// Don't need to check smooth qualifier, as it uses the default interpolation mode
if (ent1.stage == EShLangFragment && type1.isBuiltIn() == false) {
if (type1.getQualifier().flat != type2.getQualifier().flat ||
type1.getQualifier().nopersp != type2.getQualifier().nopersp) {
TString err = "Interpolation qualifier mismatch : " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
}
}
}
return; return;
}
else { else {
TString err = "Invalid In/Out variable type : " + entKey.first; TString err = "Invalid In/Out variable type : " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str()); infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true; hadError = true;
} }
} }
else if (!base->getType().isBuiltIn()) {
// According to spec: A link error is generated if any statically referenced input variable
// or block does not have a matching output
if (profile == EEsProfile && ent1.live) {
hadError = true;
TString errorStr = name + ": not been declare as a output variable in pre shader stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
return; return;
} }
} else if (base->getQualifier().storage == EvqVaryingOut) { } else if (base->getQualifier().storage == EvqVaryingOut) {
// validate stage out; // validate stage out;
if (nextStage == EShLangCount) if (nextStage == EShLangCount)
return; return;
if (name == "gl_PerVertex") if (TSymbolTable::isBuiltInSymbol(base->getId()))
return; return;
if (outVarMaps[nextStage] != nullptr) { if (inVarMaps[nextStage] != nullptr) {
auto ent2 = inVarMaps[nextStage]->find(name); auto ent2 = inVarMaps[nextStage]->find(name);
if (ent2 != inVarMaps[nextStage]->end()) { if (ent2 != inVarMaps[nextStage]->end()) {
if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) { if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) {
@ -400,11 +563,50 @@ struct TSymbolValidater
hadError = true; hadError = true;
} }
mangleName2.clear(); mangleName2.clear();
// validate instance name of blocks
if (hadError == false &&
base->getType().getBasicType() == EbtBlock &&
IsAnonymous(base->getName()) != IsAnonymous(ent2->second.symbol->getName())) {
TString err = "Matched uniform block names must also either all be lacking "
"an instance name or all having an instance name: " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
}
// validate uniform block member qualifier and member names
auto& type1 = base->getType();
auto& type2 = ent2->second.symbol->getType();
if (hadError == false && base->getType().getBasicType() == EbtBlock) {
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), true);
}
else {
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
}
}
else if (base->getBasicType() == EbtBlock)
{
if (IsAnonymous(base->getName()))
{
// The name of anonymous block member can't same with default uniform variable.
auto blockType1 = base->getType().getStruct();
for (size_t memberIdx = 0; memberIdx < blockType1->size(); ++memberIdx) {
auto memberName = (*blockType1)[memberIdx].type->getFieldName();
if (uniformVarMap[i]->find(memberName) != uniformVarMap[i]->end())
{
TString err = "Invalid Uniform variable name : " + memberName;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
}
} }
} }
} }
} }
} }
TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount]; TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount];
// Use for mark pre stage, to get more interface symbol information. // Use for mark pre stage, to get more interface symbol information.
EShLanguage preStage, currentStage, nextStage; EShLanguage preStage, currentStage, nextStage;
@ -412,9 +614,118 @@ struct TSymbolValidater
TIoMapResolver& resolver; TIoMapResolver& resolver;
TInfoSink& infoSink; TInfoSink& infoSink;
bool& hadError; bool& hadError;
EProfile profile;
int version;
private: private:
TSymbolValidater& operator=(TSymbolValidater&) = delete; TSymbolValidater& operator=(TSymbolValidater&) = delete;
bool qualifierCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
{
bool hasError = false;
const TQualifier& qualifier1 = type1->getQualifier();
const TQualifier& qualifier2 = type2->getQualifier();
if (isBlock == false &&
(type1->getQualifier().storage == EvqUniform && type2->getQualifier().storage == EvqUniform) ||
(type1->getQualifier().storage == EvqGlobal && type2->getQualifier().storage == EvqGlobal)) {
if (qualifier1.precision != qualifier2.precision) {
hasError = true;
std::string errorStr = name + ": have precision conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.hasFormat() && qualifier2.hasFormat()) {
if (qualifier1.layoutFormat != qualifier2.layoutFormat) {
hasError = true;
std::string errorStr = name + ": have layout format conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
}
if (isBlock == true) {
if (qualifier1.layoutPacking != qualifier2.layoutPacking) {
hasError = true;
std::string errorStr = name + ": have layoutPacking conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutMatrix != qualifier2.layoutMatrix) {
hasError = true;
std::string errorStr = name + ": have layoutMatrix conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutOffset != qualifier2.layoutOffset) {
hasError = true;
std::string errorStr = name + ": have layoutOffset conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutAlign != qualifier2.layoutAlign) {
hasError = true;
std::string errorStr = name + ": have layoutAlign conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
return hasError;
}
bool typeCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
{
bool hasError = false;
if (!(type1->isStruct() && type2->isStruct())) {
hasError = hasError || qualifierCheck(type1, type2, name, isBlock);
}
else {
if (type1->getBasicType() == EbtBlock && type2->getBasicType() == EbtBlock)
isBlock = true;
const TTypeList* typeList1 = type1->getStruct();
const TTypeList* typeList2 = type2->getStruct();
std::string newName = name;
size_t memberCount = typeList1->size();
size_t index2 = 0;
for (size_t index = 0; index < memberCount; index++, index2++) {
// Skip inactive member
if (typeList1->at(index).type->getBasicType() == EbtVoid)
continue;
while (index2 < typeList2->size() && typeList2->at(index2).type->getBasicType() == EbtVoid) {
++index2;
}
// TypeList1 has more members in list
if (index2 == typeList2->size()) {
std::string errorStr = name + ": struct mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
break;
}
if (typeList1->at(index).type->getFieldName() != typeList2->at(index2).type->getFieldName()) {
std::string errorStr = name + ": member name mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
}
else {
newName = typeList1->at(index).type->getFieldName().c_str();
}
hasError = hasError || typeCheck(typeList1->at(index).type, typeList2->at(index2).type, newName, isBlock);
}
while (index2 < typeList2->size())
{
// TypeList2 has more members
if (typeList2->at(index2).type->getBasicType() != EbtVoid) {
std::string errorStr = name + ": struct mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
break;
}
++index2;
}
}
return hasError;
}
}; };
struct TSlotCollector { struct TSlotCollector {
@ -500,7 +811,7 @@ int TDefaultIoResolverBase::resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent
int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const char* name = ent.symbol->getName().c_str(); const char* name = ent.symbol->getAccessName().c_str();
// kick out of not doing this // kick out of not doing this
if (! doAutoLocationMapping()) { if (! doAutoLocationMapping()) {
return ent.newLocation = -1; return ent.newLocation = -1;
@ -609,7 +920,7 @@ TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate
int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol); const TString& name = ent.symbol->getAccessName();
if (currentStage != stage) { if (currentStage != stage) {
preStage = currentStage; preStage = currentStage;
currentStage = stage; currentStage = stage;
@ -693,7 +1004,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf
int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol); const TString& name = ent.symbol->getAccessName();
// kick out of not doing this // kick out of not doing this
if (! doAutoLocationMapping()) { if (! doAutoLocationMapping()) {
return ent.newLocation = -1; return ent.newLocation = -1;
@ -764,7 +1075,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn
int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) { int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol); const TString& name = ent.symbol->getAccessName();
// On OpenGL arrays of opaque types take a separate binding for each element // On OpenGL arrays of opaque types take a separate binding for each element
int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
TResourceType resource = getResourceType(type); TResourceType resource = getResourceType(type);
@ -839,7 +1150,7 @@ void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol); const TString& name = ent.symbol->getAccessName();
TStorageQualifier storage = type.getQualifier().storage; TStorageQualifier storage = type.getQualifier().storage;
EShLanguage stage(EShLangCount); EShLanguage stage(EShLangCount);
switch (storage) { switch (storage) {
@ -899,7 +1210,7 @@ void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink&
void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
const TType& type = ent.symbol->getType(); const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol); const TString& name = ent.symbol->getAccessName();
int resource = getResourceType(type); int resource = getResourceType(type);
if (type.getQualifier().hasBinding()) { if (type.getQualifier().hasBinding()) {
TVarSlotMap& varSlotMap = resourceSlotMap[resource]; TVarSlotMap& varSlotMap = resourceSlotMap[resource];
@ -922,13 +1233,6 @@ void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink&
} }
} }
const TString& TDefaultGlslIoResolver::getAccessName(const TIntermSymbol* symbol)
{
return symbol->getBasicType() == EbtBlock ?
symbol->getType().getTypeName() :
symbol->getName();
}
//TDefaultGlslIoResolver end //TDefaultGlslIoResolver end
/* /*
@ -1117,25 +1421,23 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
} }
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
std::for_each(inVarMap.begin(), inVarMap.end(), for (auto& var : inVarMap) { inVector.push_back(var); }
[&inVector](TVarLivePair p) { inVector.push_back(p); });
std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
}); });
std::for_each(outVarMap.begin(), outVarMap.end(), for (auto& var : outVarMap) { outVector.push_back(var); }
[&outVector](TVarLivePair p) { outVector.push_back(p); });
std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
}); });
std::for_each(uniformVarMap.begin(), uniformVarMap.end(), for (auto& var : uniformVarMap) { uniformVector.push_back(var); }
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
}); });
bool hadError = false; bool hadError = false;
TVarLiveMap* dummyUniformVarMap[EShLangCount] = {};
TNotifyInOutAdaptor inOutNotify(stage, *resolver); TNotifyInOutAdaptor inOutNotify(stage, *resolver);
TNotifyUniformAdaptor uniformNotify(stage, *resolver); TNotifyUniformAdaptor uniformNotify(stage, *resolver);
TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError); TResolverUniformAdaptor uniformResolve(stage, *resolver, dummyUniformVarMap, infoSink, hadError);
TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError); TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError);
resolver->beginNotifications(stage); resolver->beginNotifications(stage);
std::for_each(inVector.begin(), inVector.end(), inOutNotify); std::for_each(inVector.begin(), inVector.end(), inOutNotify);
@ -1143,22 +1445,22 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify); std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify);
resolver->endNotifications(stage); resolver->endNotifications(stage);
resolver->beginResolve(stage); resolver->beginResolve(stage);
std::for_each(inVector.begin(), inVector.end(), inOutResolve); for (auto& var : inVector) { inOutResolve(var); }
std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) { std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) {
auto at = inVarMap.find(p.second.symbol->getName()); auto at = inVarMap.find(p.second.symbol->getAccessName());
if (at != inVarMap.end()) if (at != inVarMap.end() && p.second.id == at->second.id)
at->second = p.second; at->second = p.second;
}); });
std::for_each(outVector.begin(), outVector.end(), inOutResolve); for (auto& var : outVector) { inOutResolve(var); }
std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) { std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) {
auto at = outVarMap.find(p.second.symbol->getName()); auto at = outVarMap.find(p.second.symbol->getAccessName());
if (at != outVarMap.end()) if (at != outVarMap.end() && p.second.id == at->second.id)
at->second = p.second; at->second = p.second;
}); });
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve); std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) { std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
auto at = uniformVarMap.find(p.second.symbol->getName()); auto at = uniformVarMap.find(p.second.symbol->getAccessName());
if (at != uniformVarMap.end()) if (at != uniformVarMap.end() && p.second.id == at->second.id)
at->second = p.second; at->second = p.second;
}); });
resolver->endResolve(stage); resolver->endResolve(stage);
@ -1174,9 +1476,14 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
// //
// Returns false if the input is too malformed to do this. // Returns false if the input is too malformed to do this.
bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) { bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
intermediate.getAutoMapBindings() ||
intermediate.getAutoMapLocations();
// Profile and version are use for symbol validate.
profile = intermediate.getProfile();
version = intermediate.getVersion();
bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
intermediate.getAutoMapLocations();
// Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
// unnecessary or insignificant for-loop operation after 'somethingToDo' have been true. // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
for (int res = 0; (res < EResCount && !somethingToDo); ++res) { for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
@ -1236,31 +1543,30 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
resolver->endResolve(EShLangCount); resolver->endResolve(EShLangCount);
if (!hadError) { if (!hadError) {
//Resolve uniform location, ubo/ssbo/opaque bindings across stages //Resolve uniform location, ubo/ssbo/opaque bindings across stages
TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, infoSink, hadError); TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, uniformVarMap, infoSink, hadError);
TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError); TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError);
TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, outVarMaps, uniformVarMap, hadError); TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps,
outVarMaps, uniformVarMap, hadError, profile, version);
TVarLiveVector uniformVector; TVarLiveVector uniformVector;
resolver->beginResolve(EShLangCount); resolver->beginResolve(EShLangCount);
for (int stage = EShLangVertex; stage < EShLangCount; stage++) { for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
if (inVarMaps[stage] != nullptr) { if (inVarMaps[stage] != nullptr) {
inOutResolve.setStage(EShLanguage(stage)); inOutResolve.setStage(EShLanguage(stage));
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), symbolValidater); for (auto& var : *(inVarMaps[stage])) { symbolValidater(var); }
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutResolve); for (auto& var : *(inVarMaps[stage])) { inOutResolve(var); }
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), symbolValidater); for (auto& var : *(outVarMaps[stage])) { symbolValidater(var); }
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutResolve); for (auto& var : *(outVarMaps[stage])) { inOutResolve(var); }
} }
if (uniformVarMap[stage] != nullptr) { if (uniformVarMap[stage] != nullptr) {
uniformResolve.setStage(EShLanguage(stage)); uniformResolve.setStage(EShLanguage(stage));
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); }
std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(),
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
} }
} }
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
}); });
std::for_each(uniformVector.begin(), uniformVector.end(), symbolValidater); for (auto& var : uniformVector) { symbolValidater(var); }
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve); for (auto& var : uniformVector) { uniformResolve(var); }
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
}); });
@ -1269,14 +1575,18 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
if (intermediates[stage] != nullptr) { if (intermediates[stage] != nullptr) {
// traverse each stage, set new location to each input/output and unifom symbol, set new binding to // traverse each stage, set new location to each input/output and unifom symbol, set new binding to
// ubo, ssbo and opaque symbols // ubo, ssbo and opaque symbols
TVarLiveMap** pUniformVarMap = uniformVarMap; TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) { std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
auto at = pUniformVarMap[stage]->find(p.second.symbol->getName()); auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
if (at != pUniformVarMap[stage]->end()) if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
int resolvedBinding = at->second.newBinding;
at->second = p.second; at->second = p.second;
if (resolvedBinding > 0)
at->second.newBinding = resolvedBinding;
}
}); });
TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage], TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
*uniformVarMap[stage]); *uniformResolve.uniformVarMap[stage]);
intermediates[stage]->getTreeRoot()->traverse(&iter_iomap); intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
} }
} }

View File

@ -203,7 +203,6 @@ public:
void endCollect(EShLanguage) override; void endCollect(EShLanguage) override;
void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
const TString& getAccessName(const TIntermSymbol*);
// in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol. // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
// We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage. // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
// if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key. // if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key.
@ -263,10 +262,12 @@ public:
class TGlslIoMapper : public TIoMapper { class TGlslIoMapper : public TIoMapper {
public: public:
TGlslIoMapper() { TGlslIoMapper() {
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount); memset(inVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount); memset(outVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * EShLangCount); memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(intermediates, 0, sizeof(TIntermediate*) * EShLangCount); memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
profile = ENoProfile;
version = 0;
} }
virtual ~TGlslIoMapper() { virtual ~TGlslIoMapper() {
for (size_t stage = 0; stage < EShLangCount; stage++) { for (size_t stage = 0; stage < EShLangCount; stage++) {
@ -293,6 +294,8 @@ public:
*uniformVarMap[EShLangCount]; *uniformVarMap[EShLangCount];
TIntermediate* intermediates[EShLangCount]; TIntermediate* intermediates[EShLangCount];
bool hadError = false; bool hadError = false;
EProfile profile;
int version;
}; };
} // end namespace glslang } // end namespace glslang

View File

@ -658,14 +658,17 @@ public:
blocks.back().numMembers = countAggregateMembers(type); blocks.back().numMembers = countAggregateMembers(type);
EShLanguageMask& stages = blocks.back().stages; if (updateStageMasks) {
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage()); EShLanguageMask& stages = blocks.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
} }
else { else {
blockIndex = it->second; blockIndex = it->second;
if (updateStageMasks) {
EShLanguageMask& stages = blocks[blockIndex].stages; EShLanguageMask& stages = blocks[blockIndex].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage()); stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
} }
} }