mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
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:
parent
d550bebee9
commit
478b232952
@ -3959,6 +3959,8 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
|
||||
// Name and decorate the non-hidden members
|
||||
int offset = -1;
|
||||
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++) {
|
||||
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
|
||||
int member = i;
|
||||
@ -4011,7 +4013,7 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
|
||||
// just track whether a member needs to be decorated.
|
||||
// Ignore member locations if the container is an array, as that's
|
||||
// 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);
|
||||
|
||||
if (qualifier.hasLocation()) // track for upcoming inheritance
|
||||
|
@ -1,6 +1,7 @@
|
||||
300layout.vert
|
||||
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: '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: 'location' : overlapping use of location 10
|
||||
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:54: 'layout' : cannot specify packing on a variable declaration
|
||||
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
|
||||
|
@ -40,10 +40,14 @@ ERROR: 0:112: 'out' : cannot be a matrix
|
||||
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: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: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: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: '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:138: '' : cannot nest a structure definition inside a structure or block
|
||||
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: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: 132 compilation errors. No code generated.
|
||||
ERROR: 136 compilation errors. No code generated.
|
||||
|
||||
|
||||
Shader version: 310
|
||||
|
@ -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:109: 'gl_PerVertex' : block redeclaration has extra members
|
||||
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: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
|
||||
@ -96,7 +97,7 @@ ERROR: 0:389: 'sample' : Reserved word.
|
||||
ERROR: 0:400: 'interpolateAtCentroid' : no matching overloaded function found
|
||||
ERROR: 0:401: 'interpolateAtSample' : 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
|
||||
|
@ -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:18: 'gl_PerVertex' : block redeclaration has extra members
|
||||
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: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
|
||||
@ -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:253: 'interpolateAtSample' : 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
|
||||
|
@ -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: '=' : 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: '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'
|
||||
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
|
||||
|
@ -190,13 +190,13 @@ Validation failed
|
||||
Decorate 9 BufferBlock
|
||||
Decorate 12 BufferBlock
|
||||
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) Binding 6
|
||||
Decorate 50(sbuf_a@count) Binding 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) Binding 7
|
||||
Decorate 52(sbuf_c@count) Binding 0
|
||||
Decorate 58(pos) Flat
|
||||
Decorate 58(pos) Location 0
|
||||
Decorate 61(@entryPointOutput) Location 0
|
||||
|
@ -191,9 +191,9 @@ Validation failed
|
||||
Decorate 18 BufferBlock
|
||||
Decorate 20 BufferBlock
|
||||
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) Binding 3
|
||||
Decorate 48(sbuf2@count) Binding 0
|
||||
Decorate 50(sbuf) DescriptorSet 0
|
||||
Decorate 50(sbuf) Binding 10
|
||||
Decorate 63(pos) Flat
|
||||
|
@ -211,7 +211,7 @@ Shader version: 430
|
||||
Name 70 "BufferBlock"
|
||||
MemberName 70(BufferBlock) 0 "p"
|
||||
Name 72 "uBuf"
|
||||
Decorate 14(oColor) Location 4
|
||||
Decorate 14(oColor) Location 2
|
||||
MemberDecorate 16(ColorBlock) 0 Offset 0
|
||||
MemberDecorate 16(ColorBlock) 1 Offset 16
|
||||
MemberDecorate 16(ColorBlock) 2 Offset 32
|
||||
@ -224,7 +224,7 @@ Shader version: 430
|
||||
Decorate 28(uColorBuf) DescriptorSet 0
|
||||
Decorate 28(uColorBuf) Binding 0
|
||||
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) 1 BuiltIn PointSize
|
||||
MemberDecorate 40(gl_PerVertex) 2 BuiltIn ClipDistance
|
||||
|
@ -304,7 +304,7 @@ output primitive = triangle_strip
|
||||
MemberName 95(BufferBlock) 0 "p"
|
||||
Name 97 "uBuf"
|
||||
Name 100 "P"
|
||||
Decorate 18(oColor) Location 2
|
||||
Decorate 18(oColor) Location 1
|
||||
MemberDecorate 20(ColorBlock) 0 Offset 0
|
||||
MemberDecorate 20(ColorBlock) 1 Offset 16
|
||||
MemberDecorate 20(ColorBlock) 2 Offset 32
|
||||
@ -326,16 +326,16 @@ output primitive = triangle_strip
|
||||
Decorate 50(uM) DescriptorSet 0
|
||||
Decorate 50(uM) Binding 0
|
||||
Decorate 59(Vertex) Block
|
||||
Decorate 61(oV) Location 1
|
||||
Decorate 61(oV) Location 0
|
||||
Decorate 64(Vertex) Block
|
||||
Decorate 68(iV) Location 0
|
||||
Decorate 68(iV) Location 1
|
||||
MemberDecorate 95(BufferBlock) 0 ColMajor
|
||||
MemberDecorate 95(BufferBlock) 0 Offset 0
|
||||
MemberDecorate 95(BufferBlock) 0 MatrixStride 16
|
||||
Decorate 95(BufferBlock) BufferBlock
|
||||
Decorate 97(uBuf) DescriptorSet 0
|
||||
Decorate 97(uBuf) Binding 1
|
||||
Decorate 100(P) Location 4
|
||||
Decorate 100(P) Location 0
|
||||
2: TypeVoid
|
||||
3: TypeFunction 2
|
||||
6: TypeFloat 32
|
||||
|
@ -11,7 +11,7 @@ spv.specConstant.vert
|
||||
Source GLSL 400
|
||||
Name 4 "main"
|
||||
Name 9 "arraySize"
|
||||
Name 14 "foo(vf4[s4546];"
|
||||
Name 14 "foo(vf4[s805310914];"
|
||||
Name 13 "p"
|
||||
Name 17 "builtin_spec_constant("
|
||||
Name 20 "color"
|
||||
@ -106,10 +106,10 @@ spv.specConstant.vert
|
||||
Store 20(color) 46
|
||||
48: 10 Load 22(ucol)
|
||||
Store 47(param) 48
|
||||
49: 2 FunctionCall 14(foo(vf4[s4546];) 47(param)
|
||||
49: 2 FunctionCall 14(foo(vf4[s805310914];) 47(param)
|
||||
Return
|
||||
FunctionEnd
|
||||
14(foo(vf4[s4546];): 2 Function None 12
|
||||
14(foo(vf4[s805310914];): 2 Function None 12
|
||||
13(p): 11(ptr) FunctionParameter
|
||||
15: Label
|
||||
54: 24(ptr) AccessChain 53(dupUcol) 23
|
||||
|
@ -1282,6 +1282,8 @@ public:
|
||||
TIntermTyped* getConstSubtree() const { return constSubtree; }
|
||||
#ifndef GLSLANG_WEB
|
||||
void setFlattenSubset(int subset) { flattenSubset = subset; }
|
||||
virtual const TString& getAccessName() const;
|
||||
|
||||
int getFlattenSubset() const { return flattenSubset; } // -1 means full object
|
||||
#endif
|
||||
|
||||
|
@ -71,6 +71,13 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it)
|
||||
it->visitConstantUnion(this);
|
||||
}
|
||||
|
||||
const TString& TIntermSymbol::getAccessName() const {
|
||||
if (getBasicType() == EbtBlock)
|
||||
return getType().getTypeName();
|
||||
else
|
||||
return getName();
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a binary node.
|
||||
//
|
||||
|
@ -127,22 +127,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
|
||||
{
|
||||
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;
|
||||
TIntermSymbol* symNode = node->getAsSymbolNode();
|
||||
if (symNode != nullptr)
|
||||
@ -203,15 +187,40 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
|
||||
// Everything else is okay, no error.
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// If we get here, we have an error and a message.
|
||||
//
|
||||
const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
|
||||
|
||||
if (symNode)
|
||||
error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
|
||||
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;
|
||||
}
|
||||
@ -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.
|
||||
void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
|
||||
{
|
||||
TIntermBinary* binaryNode = node->getAsBinaryNode();
|
||||
const TIntermSymbol* symNode = node->getAsSymbolNode();
|
||||
|
||||
if (! node)
|
||||
return;
|
||||
|
||||
TIntermBinary* binaryNode = node->getAsBinaryNode();
|
||||
if (binaryNode) {
|
||||
switch(binaryNode->getOp()) {
|
||||
case EOpIndexDirect:
|
||||
case EOpIndexIndirect:
|
||||
case EOpIndexDirectStruct:
|
||||
case EOpVectorSwizzle:
|
||||
case EOpMatrixSwizzle:
|
||||
rValueErrorCheck(loc, op, binaryNode->getLeft());
|
||||
default:
|
||||
break;
|
||||
if (node->getQualifier().isWriteOnly()) {
|
||||
const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
|
||||
|
||||
if (symNode != nullptr)
|
||||
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
|
||||
else if (binaryNode &&
|
||||
(binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct ||
|
||||
binaryNode->getAsOperator()->getOp() == EOpIndexDirect))
|
||||
if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
|
||||
error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str());
|
||||
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
|
||||
|
@ -3368,7 +3368,7 @@ void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& t
|
||||
//
|
||||
void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
|
||||
{
|
||||
globalQualifierFixCheck(publicType.loc, publicType.qualifier);
|
||||
globalQualifierFixCheck(publicType.loc, publicType.qualifier, true);
|
||||
checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers);
|
||||
if (publicType.qualifier.isNonUniform()) {
|
||||
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.
|
||||
//
|
||||
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier)
|
||||
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck)
|
||||
{
|
||||
bool nonuniformOkay = false;
|
||||
|
||||
@ -3404,6 +3404,16 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
|
||||
case EvqTemporary:
|
||||
nonuniformOkay = true;
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@ -3411,7 +3421,9 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
|
||||
if (!nonuniformOkay && qualifier.isNonUniform())
|
||||
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))
|
||||
return;
|
||||
|
||||
if (base.getType().getQualifier().builtIn == EbvSampleMask)
|
||||
return;
|
||||
|
||||
// Check for last member of a bufferreference type, which is runtime sizeable
|
||||
// but doesn't support runtime length
|
||||
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)
|
||||
{
|
||||
if (structNestingLevel > 0)
|
||||
if (structNestingLevel > 0 || blockNestingLevel > 0)
|
||||
error(loc, "cannot nest a block definition inside a structure or block", "", "");
|
||||
++structNestingLevel;
|
||||
++blockNestingLevel;
|
||||
}
|
||||
|
||||
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", "", "");
|
||||
++structNestingLevel;
|
||||
}
|
||||
@ -6537,13 +6552,15 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType
|
||||
error(loc, "atomic_uint binding is too large", "binding", "");
|
||||
return;
|
||||
}
|
||||
|
||||
if(publicType.qualifier.hasOffset()) {
|
||||
if (publicType.qualifier.hasOffset())
|
||||
atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (publicType.arraySizes) {
|
||||
error(loc, "expect an array name", "", "");
|
||||
}
|
||||
|
||||
if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference())
|
||||
warn(loc, "useless application of layout qualifier", "layout", "");
|
||||
#endif
|
||||
@ -6634,6 +6651,22 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
||||
if (type.getQualifier().storage == EvqShared && type.containsCoopMat())
|
||||
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))
|
||||
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)
|
||||
@ -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());
|
||||
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 {
|
||||
error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str());
|
||||
return nullptr;
|
||||
@ -7492,10 +7534,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
||||
TType& memberType = *typeList[member].type;
|
||||
TQualifier& memberQualifier = memberType.getQualifier();
|
||||
const TSourceLoc& memberLoc = typeList[member].loc;
|
||||
globalQualifierFixCheck(memberLoc, memberQualifier);
|
||||
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(), "");
|
||||
memberQualifier.storage = currentBlockQualifier.storage;
|
||||
globalQualifierFixCheck(memberLoc, memberQualifier);
|
||||
#ifndef GLSLANG_WEB
|
||||
inheritMemoryQualifiers(currentBlockQualifier, memberQualifier);
|
||||
if (currentBlockQualifier.perPrimitiveNV)
|
||||
@ -8193,7 +8235,7 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
|
||||
|
||||
bool pipeOut = qualifier.isPipeOutput();
|
||||
bool pipeIn = qualifier.isPipeInput();
|
||||
if (version >= 300 || (!isEsProfile() && version >= 420)) {
|
||||
if ((version >= 300 && isEsProfile()) || (!isEsProfile() && version >= 420)) {
|
||||
if (! pipeOut)
|
||||
error(loc, "can only apply to an output", "invariant", "");
|
||||
} else {
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
||||
scopeMangler("::"),
|
||||
symbolTable(symbolTable),
|
||||
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0),
|
||||
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), blockNestingLevel(0), controlFlowNestingLevel(0),
|
||||
currentFunctionType(nullptr),
|
||||
postEntryPointReturn(false),
|
||||
contextPragma(true, false),
|
||||
@ -178,7 +178,8 @@ public:
|
||||
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 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
|
||||
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
|
||||
@ -365,7 +366,7 @@ public:
|
||||
void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
|
||||
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
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&);
|
||||
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
|
||||
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);
|
||||
|
@ -982,7 +982,7 @@ int TScanContext::tokenizeIdentifier()
|
||||
return keyword;
|
||||
case PACKED:
|
||||
if ((parseContext.isEsProfile() && parseContext.version < 300) ||
|
||||
(!parseContext.isEsProfile() && parseContext.version < 330))
|
||||
(!parseContext.isEsProfile() && parseContext.version < 140))
|
||||
return reservedWord();
|
||||
return identifierOrType();
|
||||
|
||||
|
@ -146,6 +146,8 @@ void TType::buildMangledName(TString& mangledName) const
|
||||
if (typeName)
|
||||
mangledName += *typeName;
|
||||
for (unsigned int i = 0; i < structure->size(); ++i) {
|
||||
if ((*structure)[i].type->getBasicType() == EbtVoid)
|
||||
continue;
|
||||
mangledName += '-';
|
||||
(*structure)[i].type->buildMangledName(mangledName);
|
||||
}
|
||||
|
@ -613,20 +613,24 @@ public:
|
||||
//
|
||||
protected:
|
||||
static const int globalLevel = 3;
|
||||
bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
|
||||
bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
|
||||
bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
|
||||
static bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
|
||||
static bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
|
||||
static bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
|
||||
public:
|
||||
bool isEmpty() { return table.size() == 0; }
|
||||
bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
|
||||
bool atGlobalLevel() { return isGlobalLevel(currentLevel()); }
|
||||
|
||||
static bool isBuiltInSymbol(int uniqueId) {
|
||||
int level = uniqueId >> LevelFlagBitOffset;
|
||||
return isBuiltInLevel(level);
|
||||
}
|
||||
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
||||
void setSeparateNameSpaces() { separateNameSpaces = true; }
|
||||
|
||||
void push()
|
||||
{
|
||||
table.push_back(new TSymbolTableLevel);
|
||||
updateUniqueIdLevelFlag();
|
||||
}
|
||||
|
||||
// Make a new symbol-table level to represent the scope introduced by a structure
|
||||
@ -639,6 +643,7 @@ public:
|
||||
{
|
||||
assert(thisSymbol.getName().size() == 0);
|
||||
table.push_back(new TSymbolTableLevel);
|
||||
updateUniqueIdLevelFlag();
|
||||
table.back()->setThisLevel();
|
||||
insert(thisSymbol);
|
||||
}
|
||||
@ -648,6 +653,7 @@ public:
|
||||
table[currentLevel()]->getPreviousDefaultPrecisions(p);
|
||||
delete table.back();
|
||||
table.pop_back();
|
||||
updateUniqueIdLevelFlag();
|
||||
}
|
||||
|
||||
//
|
||||
@ -867,12 +873,20 @@ public:
|
||||
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:
|
||||
TSymbolTable(TSymbolTable&);
|
||||
TSymbolTable& operator=(TSymbolTableLevel&);
|
||||
|
||||
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
|
||||
|
||||
static const uint32_t LevelFlagBitOffset = 28;
|
||||
std::vector<TSymbolTableLevel*> table;
|
||||
int uniqueId; // for unique identification in code generation
|
||||
bool noBuiltInRedeclarations;
|
||||
|
@ -905,7 +905,7 @@ declaration
|
||||
|
||||
block_structure
|
||||
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
|
||||
--parseContext.structNestingLevel;
|
||||
--parseContext.blockNestingLevel;
|
||||
parseContext.blockName = $2.string;
|
||||
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
|
||||
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
|
||||
|
@ -905,7 +905,7 @@ declaration
|
||||
|
||||
block_structure
|
||||
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
|
||||
--parseContext.structNestingLevel;
|
||||
--parseContext.blockNestingLevel;
|
||||
parseContext.blockName = $2.string;
|
||||
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
|
||||
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);
|
||||
|
@ -5186,7 +5186,7 @@ yyreduce:
|
||||
case 104:
|
||||
#line 907 "MachineIndependent/glslang.y" /* yacc.c:1646 */
|
||||
{
|
||||
--parseContext.structNestingLevel;
|
||||
--parseContext.blockNestingLevel;
|
||||
parseContext.blockName = (yyvsp[-4].lex).string;
|
||||
parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier);
|
||||
parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers);
|
||||
|
@ -37,9 +37,11 @@
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/InfoSink.h"
|
||||
#include "../Include/Types.h"
|
||||
|
||||
#include "gl_types.h"
|
||||
#include "iomapper.h"
|
||||
#include "SymbolTable.h"
|
||||
|
||||
//
|
||||
// Map IO bindings.
|
||||
@ -82,17 +84,17 @@ public:
|
||||
// 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
|
||||
else if (base->getQualifier().storage == EvqGlobal)
|
||||
addGlobalReference(base->getName());
|
||||
addGlobalReference(base->getAccessName());
|
||||
|
||||
if (target) {
|
||||
TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
|
||||
ent.stage = intermediate.getStage();
|
||||
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)
|
||||
at->second.live = at->second.live || ! traverseAll; // update live state
|
||||
else
|
||||
(*target)[ent.symbol->getName()] = ent;
|
||||
(*target)[ent.symbol->getAccessName()] = ent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +127,8 @@ public:
|
||||
return;
|
||||
|
||||
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())
|
||||
return;
|
||||
|
||||
@ -181,7 +184,7 @@ struct TNotifyInOutAdaptor
|
||||
|
||||
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
|
||||
{
|
||||
resolver.notifyInOut(stage, entKey.second);
|
||||
resolver.notifyInOut(entKey.second.stage, entKey.second);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -189,12 +192,13 @@ private:
|
||||
};
|
||||
|
||||
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)
|
||||
, resolver(r)
|
||||
, infoSink(i)
|
||||
, error(e)
|
||||
{
|
||||
memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
|
||||
}
|
||||
|
||||
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
|
||||
@ -206,9 +210,9 @@ struct TResolverUniformAdaptor {
|
||||
ent.newIndex = -1;
|
||||
const bool isValid = resolver.validateBinding(stage, ent);
|
||||
if (isValid) {
|
||||
resolver.resolveBinding(stage, ent);
|
||||
resolver.resolveSet(stage, ent);
|
||||
resolver.resolveUniformLocation(stage, ent);
|
||||
resolver.resolveBinding(ent.stage, ent);
|
||||
resolver.resolveSet(ent.stage, ent);
|
||||
resolver.resolveUniformLocation(ent.stage, ent);
|
||||
|
||||
if (ent.newBinding != -1) {
|
||||
if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
|
||||
@ -217,6 +221,17 @@ struct TResolverUniformAdaptor {
|
||||
infoSink.info.message(EPrefixInternalError, err.c_str());
|
||||
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 >= int(TQualifier::layoutSetEnd)) {
|
||||
@ -225,6 +240,16 @@ struct TResolverUniformAdaptor {
|
||||
infoSink.info.message(EPrefixInternalError, err.c_str());
|
||||
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 {
|
||||
TString errorMsg = "Invalid binding: " + entKey.first;
|
||||
@ -239,7 +264,7 @@ struct TResolverUniformAdaptor {
|
||||
TIoMapResolver& resolver;
|
||||
TInfoSink& infoSink;
|
||||
bool& error;
|
||||
|
||||
TVarLiveMap* uniformVarMap[EShLangCount];
|
||||
private:
|
||||
TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
|
||||
};
|
||||
@ -261,7 +286,7 @@ struct TResolverInOutAdaptor {
|
||||
ent.newBinding = -1;
|
||||
ent.newSet = -1;
|
||||
ent.newIndex = -1;
|
||||
const bool isValid = resolver.validateInOut(stage, ent);
|
||||
const bool isValid = resolver.validateInOut(ent.stage, ent);
|
||||
if (isValid) {
|
||||
resolver.resolveInOutLocation(stage, ent);
|
||||
resolver.resolveInOutComponent(stage, ent);
|
||||
@ -296,17 +321,116 @@ private:
|
||||
struct TSymbolValidater
|
||||
{
|
||||
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)
|
||||
, currentStage(EShLangCount)
|
||||
, nextStage(EShLangCount)
|
||||
, resolver(r)
|
||||
, infoSink(i)
|
||||
, hadError(hadError)
|
||||
, profile(profile)
|
||||
, version(version)
|
||||
{
|
||||
memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
|
||||
memcpy(outVarMaps, out, 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) {
|
||||
@ -339,11 +463,24 @@ struct TSymbolValidater
|
||||
// validate stage in;
|
||||
if (preStage == EShLangCount)
|
||||
return;
|
||||
if (name == "gl_PerVertex")
|
||||
if (TSymbolTable::isBuiltInSymbol(base->getId()))
|
||||
return;
|
||||
if (outVarMaps[preStage] != nullptr) {
|
||||
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()) {
|
||||
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)) {
|
||||
TType subType(ent2->second.symbol->getType(), 0);
|
||||
subType.appendMangledName(mangleName2);
|
||||
@ -351,23 +488,49 @@ struct TSymbolValidater
|
||||
else {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
TString err = "Invalid In/Out variable type : " + entKey.first;
|
||||
infoSink.info.message(EPrefixInternalError, err.c_str());
|
||||
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;
|
||||
}
|
||||
} else if (base->getQualifier().storage == EvqVaryingOut) {
|
||||
// validate stage out;
|
||||
if (nextStage == EShLangCount)
|
||||
return;
|
||||
if (name == "gl_PerVertex")
|
||||
if (TSymbolTable::isBuiltInSymbol(base->getId()))
|
||||
return;
|
||||
if (outVarMaps[nextStage] != nullptr) {
|
||||
if (inVarMaps[nextStage] != nullptr) {
|
||||
auto ent2 = inVarMaps[nextStage]->find(name);
|
||||
if (ent2 != inVarMaps[nextStage]->end()) {
|
||||
if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) {
|
||||
@ -400,11 +563,50 @@ struct TSymbolValidater
|
||||
hadError = true;
|
||||
}
|
||||
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];
|
||||
// Use for mark pre stage, to get more interface symbol information.
|
||||
EShLanguage preStage, currentStage, nextStage;
|
||||
@ -412,9 +614,118 @@ struct TSymbolValidater
|
||||
TIoMapResolver& resolver;
|
||||
TInfoSink& infoSink;
|
||||
bool& hadError;
|
||||
EProfile profile;
|
||||
int version;
|
||||
|
||||
private:
|
||||
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 {
|
||||
@ -500,7 +811,7 @@ int TDefaultIoResolverBase::resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent
|
||||
|
||||
int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
|
||||
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
|
||||
if (! doAutoLocationMapping()) {
|
||||
return ent.newLocation = -1;
|
||||
@ -609,7 +920,7 @@ TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate
|
||||
|
||||
int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
|
||||
const TType& type = ent.symbol->getType();
|
||||
const TString& name = getAccessName(ent.symbol);
|
||||
const TString& name = ent.symbol->getAccessName();
|
||||
if (currentStage != stage) {
|
||||
preStage = currentStage;
|
||||
currentStage = stage;
|
||||
@ -693,7 +1004,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf
|
||||
|
||||
int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
|
||||
const TType& type = ent.symbol->getType();
|
||||
const TString& name = getAccessName(ent.symbol);
|
||||
const TString& name = ent.symbol->getAccessName();
|
||||
// kick out of not doing this
|
||||
if (! doAutoLocationMapping()) {
|
||||
return ent.newLocation = -1;
|
||||
@ -764,7 +1075,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn
|
||||
|
||||
int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) {
|
||||
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
|
||||
int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
|
||||
TResourceType resource = getResourceType(type);
|
||||
@ -839,7 +1150,7 @@ void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
|
||||
|
||||
void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
|
||||
const TType& type = ent.symbol->getType();
|
||||
const TString& name = getAccessName(ent.symbol);
|
||||
const TString& name = ent.symbol->getAccessName();
|
||||
TStorageQualifier storage = type.getQualifier().storage;
|
||||
EShLanguage stage(EShLangCount);
|
||||
switch (storage) {
|
||||
@ -899,7 +1210,7 @@ void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink&
|
||||
|
||||
void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
|
||||
const TType& type = ent.symbol->getType();
|
||||
const TString& name = getAccessName(ent.symbol);
|
||||
const TString& name = ent.symbol->getAccessName();
|
||||
int resource = getResourceType(type);
|
||||
if (type.getQualifier().hasBinding()) {
|
||||
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
|
||||
|
||||
/*
|
||||
@ -1117,25 +1421,23 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
|
||||
}
|
||||
|
||||
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
|
||||
std::for_each(inVarMap.begin(), inVarMap.end(),
|
||||
[&inVector](TVarLivePair p) { inVector.push_back(p); });
|
||||
for (auto& var : inVarMap) { inVector.push_back(var); }
|
||||
std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
|
||||
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
|
||||
});
|
||||
std::for_each(outVarMap.begin(), outVarMap.end(),
|
||||
[&outVector](TVarLivePair p) { outVector.push_back(p); });
|
||||
for (auto& var : outVarMap) { outVector.push_back(var); }
|
||||
std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
|
||||
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
|
||||
});
|
||||
std::for_each(uniformVarMap.begin(), uniformVarMap.end(),
|
||||
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
|
||||
for (auto& var : uniformVarMap) { uniformVector.push_back(var); }
|
||||
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
|
||||
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
|
||||
});
|
||||
bool hadError = false;
|
||||
TVarLiveMap* dummyUniformVarMap[EShLangCount] = {};
|
||||
TNotifyInOutAdaptor inOutNotify(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);
|
||||
resolver->beginNotifications(stage);
|
||||
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);
|
||||
resolver->endNotifications(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) {
|
||||
auto at = inVarMap.find(p.second.symbol->getName());
|
||||
if (at != inVarMap.end())
|
||||
auto at = inVarMap.find(p.second.symbol->getAccessName());
|
||||
if (at != inVarMap.end() && p.second.id == at->second.id)
|
||||
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) {
|
||||
auto at = outVarMap.find(p.second.symbol->getName());
|
||||
if (at != outVarMap.end())
|
||||
auto at = outVarMap.find(p.second.symbol->getAccessName());
|
||||
if (at != outVarMap.end() && p.second.id == at->second.id)
|
||||
at->second = p.second;
|
||||
});
|
||||
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
|
||||
std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
|
||||
auto at = uniformVarMap.find(p.second.symbol->getName());
|
||||
if (at != uniformVarMap.end())
|
||||
auto at = uniformVarMap.find(p.second.symbol->getAccessName());
|
||||
if (at != uniformVarMap.end() && p.second.id == at->second.id)
|
||||
at->second = p.second;
|
||||
});
|
||||
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.
|
||||
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
|
||||
// unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
|
||||
for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
|
||||
@ -1236,31 +1543,30 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
|
||||
resolver->endResolve(EShLangCount);
|
||||
if (!hadError) {
|
||||
//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);
|
||||
TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, outVarMaps, uniformVarMap, hadError);
|
||||
TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps,
|
||||
outVarMaps, uniformVarMap, hadError, profile, version);
|
||||
TVarLiveVector uniformVector;
|
||||
resolver->beginResolve(EShLangCount);
|
||||
for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
|
||||
if (inVarMaps[stage] != nullptr) {
|
||||
inOutResolve.setStage(EShLanguage(stage));
|
||||
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), symbolValidater);
|
||||
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutResolve);
|
||||
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), symbolValidater);
|
||||
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutResolve);
|
||||
for (auto& var : *(inVarMaps[stage])) { symbolValidater(var); }
|
||||
for (auto& var : *(inVarMaps[stage])) { inOutResolve(var); }
|
||||
for (auto& var : *(outVarMaps[stage])) { symbolValidater(var); }
|
||||
for (auto& var : *(outVarMaps[stage])) { inOutResolve(var); }
|
||||
}
|
||||
if (uniformVarMap[stage] != nullptr) {
|
||||
uniformResolve.setStage(EShLanguage(stage));
|
||||
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
|
||||
std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(),
|
||||
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
|
||||
for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); }
|
||||
}
|
||||
}
|
||||
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
|
||||
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
|
||||
});
|
||||
std::for_each(uniformVector.begin(), uniformVector.end(), symbolValidater);
|
||||
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
|
||||
for (auto& var : uniformVector) { symbolValidater(var); }
|
||||
for (auto& var : uniformVector) { uniformResolve(var); }
|
||||
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
|
||||
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
|
||||
});
|
||||
@ -1269,14 +1575,18 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
|
||||
if (intermediates[stage] != nullptr) {
|
||||
// traverse each stage, set new location to each input/output and unifom symbol, set new binding to
|
||||
// ubo, ssbo and opaque symbols
|
||||
TVarLiveMap** pUniformVarMap = uniformVarMap;
|
||||
TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
|
||||
std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
|
||||
auto at = pUniformVarMap[stage]->find(p.second.symbol->getName());
|
||||
if (at != pUniformVarMap[stage]->end())
|
||||
auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
|
||||
if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
|
||||
int resolvedBinding = at->second.newBinding;
|
||||
at->second = p.second;
|
||||
if (resolvedBinding > 0)
|
||||
at->second.newBinding = resolvedBinding;
|
||||
}
|
||||
});
|
||||
TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
|
||||
*uniformVarMap[stage]);
|
||||
*uniformResolve.uniformVarMap[stage]);
|
||||
intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,6 @@ public:
|
||||
void endCollect(EShLanguage) override;
|
||||
void reserverStorageSlot(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.
|
||||
// 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.
|
||||
@ -263,10 +262,12 @@ public:
|
||||
class TGlslIoMapper : public TIoMapper {
|
||||
public:
|
||||
TGlslIoMapper() {
|
||||
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
|
||||
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
|
||||
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * EShLangCount);
|
||||
memset(intermediates, 0, sizeof(TIntermediate*) * EShLangCount);
|
||||
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
|
||||
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
|
||||
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
|
||||
memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
|
||||
profile = ENoProfile;
|
||||
version = 0;
|
||||
}
|
||||
virtual ~TGlslIoMapper() {
|
||||
for (size_t stage = 0; stage < EShLangCount; stage++) {
|
||||
@ -293,6 +294,8 @@ public:
|
||||
*uniformVarMap[EShLangCount];
|
||||
TIntermediate* intermediates[EShLangCount];
|
||||
bool hadError = false;
|
||||
EProfile profile;
|
||||
int version;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
@ -658,14 +658,17 @@ public:
|
||||
|
||||
blocks.back().numMembers = countAggregateMembers(type);
|
||||
|
||||
EShLanguageMask& stages = blocks.back().stages;
|
||||
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
|
||||
if (updateStageMasks) {
|
||||
EShLanguageMask& stages = blocks.back().stages;
|
||||
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
blockIndex = it->second;
|
||||
|
||||
EShLanguageMask& stages = blocks[blockIndex].stages;
|
||||
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
|
||||
if (updateStageMasks) {
|
||||
EShLanguageMask& stages = blocks[blockIndex].stages;
|
||||
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user