Unverified Commit 7c753a72 by greg-lunarg Committed by GitHub

Flatten all interface variables (#2217)

Specifically, add flattening of arrayed io for geometry and tesselation shaders. Previously some interface structs just had builtins split out which caused some interfaces to not be exactly the same as that of flattened adjacent stages, affecting validation and correctness. This obviates builtin splitting. That will be removed in a followup commit. It was left in for this commit to better exhibit the functional changes that were made. Fixes #1660.
parent 1a906168
...@@ -42,9 +42,34 @@ output primitive = triangle_strip ...@@ -42,9 +42,34 @@ output primitive = triangle_strip
0:14 Function Definition: main( ( temp void) 0:14 Function Definition: main( ( temp void)
0:14 Function Parameters: 0:14 Function Parameters:
0:? Sequence 0:? Sequence
0:14 move second child to first child ( temp 3-element array of structure{}) 0:14 Sequence
0:? 'input' ( temp 3-element array of structure{}) 0:14 move second child to first child ( temp structure{})
0:? 'input' ( in 3-element array of structure{}) 0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 0 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 0 (const int)
0:14 move second child to first child ( temp structure{})
0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 1 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 1 (const int)
0:14 move second child to first child ( temp structure{})
0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 2 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 2 (const int)
0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void) 0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
0:? 'input' ( temp 3-element array of structure{}) 0:? 'input' ( temp 3-element array of structure{})
0:? 'TriStream' ( temp structure{}) 0:? 'TriStream' ( temp structure{})
...@@ -97,9 +122,34 @@ output primitive = triangle_strip ...@@ -97,9 +122,34 @@ output primitive = triangle_strip
0:14 Function Definition: main( ( temp void) 0:14 Function Definition: main( ( temp void)
0:14 Function Parameters: 0:14 Function Parameters:
0:? Sequence 0:? Sequence
0:14 move second child to first child ( temp 3-element array of structure{}) 0:14 Sequence
0:? 'input' ( temp 3-element array of structure{}) 0:14 move second child to first child ( temp structure{})
0:? 'input' ( in 3-element array of structure{}) 0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 0 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 0 (const int)
0:14 move second child to first child ( temp structure{})
0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 1 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 1 (const int)
0:14 move second child to first child ( temp structure{})
0:14 direct index ( temp structure{})
0:? 'input' ( temp 3-element array of structure{})
0:14 Constant:
0:14 2 (const int)
0:14 direct index ( in structure{})
0:? 'input' ( in 3-element array of structure{})
0:14 Constant:
0:14 2 (const int)
0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void) 0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
0:? 'input' ( temp 3-element array of structure{}) 0:? 'input' ( temp 3-element array of structure{})
0:? 'TriStream' ( temp structure{}) 0:? 'TriStream' ( temp structure{})
...@@ -108,7 +158,7 @@ output primitive = triangle_strip ...@@ -108,7 +158,7 @@ output primitive = triangle_strip
Validation failed Validation failed
// Module Version 10000 // Module Version 10000
// Generated by (magic number): 80008 // Generated by (magic number): 80008
// Id's are bound by 57 // Id's are bound by 66
Capability Geometry Capability Geometry
1: ExtInstImport "GLSL.std.450" 1: ExtInstImport "GLSL.std.450"
...@@ -136,9 +186,9 @@ Validation failed ...@@ -136,9 +186,9 @@ Validation failed
Name 44 "param" Name 44 "param"
Name 47 "input" Name 47 "input"
Name 49 "input" Name 49 "input"
Name 51 "TriStream" Name 60 "TriStream"
Name 52 "param" Name 61 "param"
Name 54 "param" Name 63 "param"
2: TypeVoid 2: TypeVoid
3: TypeFunction 2 3: TypeFunction 2
6(GSPS_INPUT): TypeStruct 6(GSPS_INPUT): TypeStruct
...@@ -157,19 +207,30 @@ Validation failed ...@@ -157,19 +207,30 @@ Validation failed
40: 25(int) Constant 2 40: 25(int) Constant 2
48: TypePointer Input 15 48: TypePointer Input 15
49(input): 48(ptr) Variable Input 49(input): 48(ptr) Variable Input
50: TypePointer Input 6(GSPS_INPUT)
4(main): 2 Function None 3 4(main): 2 Function None 3
5: Label 5: Label
47(input): 16(ptr) Variable Function 47(input): 16(ptr) Variable Function
51(TriStream): 7(ptr) Variable Function 60(TriStream): 7(ptr) Variable Function
52(param): 16(ptr) Variable Function 61(param): 16(ptr) Variable Function
54(param): 7(ptr) Variable Function 63(param): 7(ptr) Variable Function
50: 15 Load 49(input) 51: 50(ptr) AccessChain 49(input) 26
Store 47(input) 50 52:6(GSPS_INPUT) Load 51
53: 15 Load 47(input) 53: 7(ptr) AccessChain 47(input) 26
Store 52(param) 53 Store 53 52
55: 2 FunctionCall 20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;) 52(param) 54(param) 54: 50(ptr) AccessChain 49(input) 33
56:6(GSPS_INPUT) Load 54(param) 55:6(GSPS_INPUT) Load 54
Store 51(TriStream) 56 56: 7(ptr) AccessChain 47(input) 33
Store 56 55
57: 50(ptr) AccessChain 49(input) 40
58:6(GSPS_INPUT) Load 57
59: 7(ptr) AccessChain 47(input) 40
Store 59 58
62: 15 Load 47(input)
Store 61(param) 62
64: 2 FunctionCall 20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;) 61(param) 63(param)
65:6(GSPS_INPUT) Load 63(param)
Store 60(TriStream) 65
Return Return
FunctionEnd FunctionEnd
11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;): 2 Function None 8 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;): 2 Function None 8
......
...@@ -1169,7 +1169,7 @@ bool HlslParseContext::shouldFlatten(const TType& type, TStorageQualifier qualif ...@@ -1169,7 +1169,7 @@ bool HlslParseContext::shouldFlatten(const TType& type, TStorageQualifier qualif
} }
// Top level variable flattening: construct data // Top level variable flattening: construct data
void HlslParseContext::flatten(const TVariable& variable, bool linkage) void HlslParseContext::flatten(const TVariable& variable, bool linkage, bool arrayed)
{ {
const TType& type = variable.getType(); const TType& type = variable.getType();
...@@ -1181,8 +1181,15 @@ void HlslParseContext::flatten(const TVariable& variable, bool linkage) ...@@ -1181,8 +1181,15 @@ void HlslParseContext::flatten(const TVariable& variable, bool linkage)
TFlattenData(type.getQualifier().layoutBinding, TFlattenData(type.getQualifier().layoutBinding,
type.getQualifier().layoutLocation))); type.getQualifier().layoutLocation)));
// the item is a map pair, so first->second is the TFlattenData itself. // if flattening arrayed io struct, array each member of dereferenced type
flatten(variable, type, entry.first->second, variable.getName(), linkage, type.getQualifier(), nullptr); if (arrayed) {
const TType dereferencedType(type, 0);
flatten(variable, dereferencedType, entry.first->second, variable.getName(), linkage,
type.getQualifier(), type.getArraySizes());
} else {
flatten(variable, type, entry.first->second, variable.getName(), linkage,
type.getQualifier(), nullptr);
}
} }
// Recursively flatten the given variable at the provided type, building the flattenData as we go. // Recursively flatten the given variable at the provided type, building the flattenData as we go.
...@@ -1256,6 +1263,10 @@ int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType& ...@@ -1256,6 +1263,10 @@ int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType&
} }
} }
// Only propagate arraysizes here for arrayed io
if (variable.getType().getQualifier().isArrayedIo(language) && builtInArraySizes != nullptr)
memberVariable->getWritableType().copyArraySizes(*builtInArraySizes);
flattenData.offsets.push_back(static_cast<int>(flattenData.members.size())); flattenData.offsets.push_back(static_cast<int>(flattenData.members.size()));
flattenData.members.push_back(memberVariable); flattenData.members.push_back(memberVariable);
...@@ -2068,11 +2079,8 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct ...@@ -2068,11 +2079,8 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
// Further this return/in/out transform by flattening, splitting, and assigning locations // Further this return/in/out transform by flattening, splitting, and assigning locations
const auto makeVariableInOut = [&](TVariable& variable) { const auto makeVariableInOut = [&](TVariable& variable) {
if (variable.getType().isStruct()) { if (variable.getType().isStruct()) {
if (variable.getType().getQualifier().isArrayedIo(language)) { bool arrayed = variable.getType().getQualifier().isArrayedIo(language);
if (variable.getType().containsBuiltIn()) flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */, arrayed);
split(variable);
} else if (shouldFlatten(variable.getType(), EvqVaryingIn /* not assigned yet, but close enough */, true))
flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */);
} }
// TODO: flatten arrays too // TODO: flatten arrays too
// TODO: flatten everything in I/O // TODO: flatten everything in I/O
...@@ -2733,17 +2741,33 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2733,17 +2741,33 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
wasSplit(binaryNode->getLeft()); wasSplit(binaryNode->getLeft());
}; };
// Return symbol if node is symbol or index ref
const auto getSymbol = [](const TIntermTyped* node) -> const TIntermSymbol* {
const TIntermSymbol* symbolNode = node->getAsSymbolNode();
if (symbolNode != nullptr)
return symbolNode;
const TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode != nullptr && (binaryNode->getOp() == EOpIndexDirect || binaryNode->getOp() == EOpIndexIndirect))
return binaryNode->getLeft()->getAsSymbolNode();
return nullptr;
};
// Return true if this stage assigns clip position with potentially inverted Y // Return true if this stage assigns clip position with potentially inverted Y
const auto assignsClipPos = [this](const TIntermTyped* node) -> bool { const auto assignsClipPos = [this](const TIntermTyped* node) -> bool {
return node->getType().getQualifier().builtIn == EbvPosition && return node->getType().getQualifier().builtIn == EbvPosition &&
(language == EShLangVertex || language == EShLangGeometry || language == EShLangTessEvaluation); (language == EShLangVertex || language == EShLangGeometry || language == EShLangTessEvaluation);
}; };
const TIntermSymbol* leftSymbol = getSymbol(left);
const TIntermSymbol* rightSymbol = getSymbol(right);
const bool isSplitLeft = wasSplit(left) || indexesSplit(left); const bool isSplitLeft = wasSplit(left) || indexesSplit(left);
const bool isSplitRight = wasSplit(right) || indexesSplit(right); const bool isSplitRight = wasSplit(right) || indexesSplit(right);
const bool isFlattenLeft = wasFlattened(left); const bool isFlattenLeft = wasFlattened(leftSymbol);
const bool isFlattenRight = wasFlattened(right); const bool isFlattenRight = wasFlattened(rightSymbol);
// OK to do a single assign if neither side is split or flattened. Otherwise, // OK to do a single assign if neither side is split or flattened. Otherwise,
// fall through to a member-wise copy. // fall through to a member-wise copy.
...@@ -2791,10 +2815,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2791,10 +2815,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
memberCount = left->getType().getCumulativeArraySize(); memberCount = left->getType().getCumulativeArraySize();
if (isFlattenLeft) if (isFlattenLeft)
leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second.members; leftVariables = &flattenMap.find(leftSymbol->getId())->second.members;
if (isFlattenRight) { if (isFlattenRight) {
rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second.members; rightVariables = &flattenMap.find(rightSymbol->getId())->second.members;
} else { } else {
// The RHS is not flattened. There are several cases: // The RHS is not flattened. There are several cases:
// 1. 1 item to copy: Use the RHS directly. // 1. 1 item to copy: Use the RHS directly.
...@@ -2828,8 +2852,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2828,8 +2852,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
TStorageQualifier leftStorage = left->getType().getQualifier().storage; TStorageQualifier leftStorage = left->getType().getQualifier().storage;
TStorageQualifier rightStorage = right->getType().getQualifier().storage; TStorageQualifier rightStorage = right->getType().getQualifier().storage;
int leftOffset = findSubtreeOffset(*left); int leftOffsetStart = findSubtreeOffset(*left);
int rightOffset = findSubtreeOffset(*right); int rightOffsetStart = findSubtreeOffset(*right);
int leftOffset = leftOffsetStart;
int rightOffset = rightOffsetStart;
const auto getMember = [&](bool isLeft, const TType& type, int member, TIntermTyped* splitNode, int splitMember, const auto getMember = [&](bool isLeft, const TType& type, int member, TIntermTyped* splitNode, int splitMember,
bool flattened) bool flattened)
...@@ -2869,10 +2895,35 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op ...@@ -2869,10 +2895,35 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
} }
} }
} else if (flattened && !shouldFlatten(derefType, isLeft ? leftStorage : rightStorage, false)) { } else if (flattened && !shouldFlatten(derefType, isLeft ? leftStorage : rightStorage, false)) {
if (isLeft) if (isLeft) {
// offset will cycle through variables for arrayed io
if (leftOffset >= static_cast<int>(leftVariables->size()))
leftOffset = leftOffsetStart;
subTree = intermediate.addSymbol(*(*leftVariables)[leftOffset++]); subTree = intermediate.addSymbol(*(*leftVariables)[leftOffset++]);
else } else {
// offset will cycle through variables for arrayed io
if (rightOffset >= static_cast<int>(rightVariables->size()))
rightOffset = rightOffsetStart;
subTree = intermediate.addSymbol(*(*rightVariables)[rightOffset++]); subTree = intermediate.addSymbol(*(*rightVariables)[rightOffset++]);
}
// arrayed io
if (subTree->getType().isArray()) {
if (!arrayElement.empty()) {
const TType derefType(subTree->getType(), arrayElement.front());
subTree = intermediate.addIndex(EOpIndexDirect, subTree,
intermediate.addConstantUnion(arrayElement.front(), loc), loc);
subTree->setType(derefType);
} else {
// There's an index operation we should transfer to the output builtin.
assert(splitNode->getAsOperator() != nullptr &&
splitNode->getAsOperator()->getOp() == EOpIndexIndirect);
const TType splitDerefType(subTree->getType(), 0);
subTree = intermediate.addIndex(splitNode->getAsOperator()->getOp(), subTree,
splitNode->getAsBinaryNode()->getRight(), loc);
subTree->setType(splitDerefType);
}
}
} else { } else {
// Index operator if it's an aggregate, else EOpNull // Index operator if it's an aggregate, else EOpNull
const TOperator accessOp = type.isArray() ? EOpIndexDirect const TOperator accessOp = type.isArray() ? EOpIndexDirect
...@@ -9911,8 +9962,8 @@ void HlslParseContext::addPatchConstantInvocation() ...@@ -9911,8 +9962,8 @@ void HlslParseContext::addPatchConstantInvocation()
TVariable* pcfOutput = makeInternalVariable("@patchConstantOutput", outType); TVariable* pcfOutput = makeInternalVariable("@patchConstantOutput", outType);
pcfOutput->getWritableType().getQualifier().storage = EvqVaryingOut; pcfOutput->getWritableType().getQualifier().storage = EvqVaryingOut;
if (pcfOutput->getType().containsBuiltIn()) if (pcfOutput->getType().isStruct())
split(*pcfOutput); flatten(*pcfOutput, false);
assignToInterface(*pcfOutput); assignToInterface(*pcfOutput);
......
...@@ -276,7 +276,7 @@ protected: ...@@ -276,7 +276,7 @@ protected:
void fixBuiltInIoType(TType&); void fixBuiltInIoType(TType&);
void flatten(const TVariable& variable, bool linkage); void flatten(const TVariable& variable, bool linkage, bool arrayed = false);
int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage,
const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes); const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes);
int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment