HLSL: Fix #954: Track/access subsets of flattened multi-level aggregates.

Works in conjuction with d1be754 to represent and modify a partially
dereferenced multi-level flattened aggregate.
This commit is contained in:
John Kessenich 2017-10-04 13:27:43 -06:00
parent 86a82bb955
commit 700bdeb742
7 changed files with 513 additions and 23 deletions

View File

@ -0,0 +1,187 @@
hlsl.flattenSubset.frag
WARNING: AST will form illegal SPIR-V; need to transform to legalize
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:27 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:27 Function Parameters:
0:27 'vpos' ( in 4-component vector of float)
0:? Sequence
0:30 Sequence
0:30 move second child to first child ( temp float)
0:? 's2.resources.b' ( temp float)
0:? 's1.b' ( temp float)
0:30 move second child to first child ( temp sampler)
0:? 's2.resources.samplerState' ( temp sampler)
0:? 's1.samplerState' ( temp sampler)
0:30 move second child to first child ( temp int)
0:? 's2.resources.s0.x' ( temp int)
0:? 's1.s0.x' ( temp int)
0:30 move second child to first child ( temp int)
0:? 's2.resources.s0.y' ( temp int)
0:? 's1.s0.y' ( temp int)
0:30 move second child to first child ( temp sampler)
0:? 's2.resources.s0.ss' ( temp sampler)
0:? 's1.s0.ss' ( temp sampler)
0:30 move second child to first child ( temp int)
0:? 's2.resources.a' ( temp int)
0:? 's1.a' ( temp int)
0:31 Branch: Return with expression
0:? Constant:
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:27 Function Definition: main( ( temp void)
0:27 Function Parameters:
0:? Sequence
0:27 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
0:27 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:27 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
Linked fragment stage:
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:27 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:27 Function Parameters:
0:27 'vpos' ( in 4-component vector of float)
0:? Sequence
0:30 Sequence
0:30 move second child to first child ( temp float)
0:? 's2.resources.b' ( temp float)
0:? 's1.b' ( temp float)
0:30 move second child to first child ( temp sampler)
0:? 's2.resources.samplerState' ( temp sampler)
0:? 's1.samplerState' ( temp sampler)
0:30 move second child to first child ( temp int)
0:? 's2.resources.s0.x' ( temp int)
0:? 's1.s0.x' ( temp int)
0:30 move second child to first child ( temp int)
0:? 's2.resources.s0.y' ( temp int)
0:? 's1.s0.y' ( temp int)
0:30 move second child to first child ( temp sampler)
0:? 's2.resources.s0.ss' ( temp sampler)
0:? 's1.s0.ss' ( temp sampler)
0:30 move second child to first child ( temp int)
0:? 's2.resources.a' ( temp int)
0:? 's1.a' ( temp int)
0:31 Branch: Return with expression
0:? Constant:
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:27 Function Definition: main( ( temp void)
0:27 Function Parameters:
0:? Sequence
0:27 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
0:27 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:27 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 49
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 42 45
ExecutionMode 4 OriginUpperLeft
Source HLSL 500
Name 4 "main"
Name 11 "@main(vf4;"
Name 10 "vpos"
Name 14 "s2.resources.b"
Name 15 "s1.b"
Name 19 "s2.resources.samplerState"
Name 20 "s1.samplerState"
Name 24 "s2.resources.s0.x"
Name 25 "s1.s0.x"
Name 27 "s2.resources.s0.y"
Name 28 "s1.s0.y"
Name 30 "s2.resources.s0.ss"
Name 31 "s1.s0.ss"
Name 33 "s2.resources.a"
Name 34 "s1.a"
Name 40 "vpos"
Name 42 "vpos"
Name 45 "@entryPointOutput"
Name 46 "param"
Decorate 42(vpos) Location 0
Decorate 45(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Function 7(fvec4)
9: TypeFunction 7(fvec4) 8(ptr)
13: TypePointer Function 6(float)
17: TypeSampler
18: TypePointer Function 17
22: TypeInt 32 1
23: TypePointer Function 22(int)
36: 6(float) Constant 0
37: 7(fvec4) ConstantComposite 36 36 36 36
41: TypePointer Input 7(fvec4)
42(vpos): 41(ptr) Variable Input
44: TypePointer Output 7(fvec4)
45(@entryPointOutput): 44(ptr) Variable Output
4(main): 2 Function None 3
5: Label
40(vpos): 8(ptr) Variable Function
46(param): 8(ptr) Variable Function
43: 7(fvec4) Load 42(vpos)
Store 40(vpos) 43
47: 7(fvec4) Load 40(vpos)
Store 46(param) 47
48: 7(fvec4) FunctionCall 11(@main(vf4;) 46(param)
Store 45(@entryPointOutput) 48
Return
FunctionEnd
11(@main(vf4;): 7(fvec4) Function None 9
10(vpos): 8(ptr) FunctionParameter
12: Label
14(s2.resources.b): 13(ptr) Variable Function
15(s1.b): 13(ptr) Variable Function
19(s2.resources.samplerState): 18(ptr) Variable Function
20(s1.samplerState): 18(ptr) Variable Function
24(s2.resources.s0.x): 23(ptr) Variable Function
25(s1.s0.x): 23(ptr) Variable Function
27(s2.resources.s0.y): 23(ptr) Variable Function
28(s1.s0.y): 23(ptr) Variable Function
30(s2.resources.s0.ss): 18(ptr) Variable Function
31(s1.s0.ss): 18(ptr) Variable Function
33(s2.resources.a): 23(ptr) Variable Function
34(s1.a): 23(ptr) Variable Function
16: 6(float) Load 15(s1.b)
Store 14(s2.resources.b) 16
21: 17 Load 20(s1.samplerState)
Store 19(s2.resources.samplerState) 21
26: 22(int) Load 25(s1.s0.x)
Store 24(s2.resources.s0.x) 26
29: 22(int) Load 28(s1.s0.y)
Store 27(s2.resources.s0.y) 29
32: 17 Load 31(s1.s0.ss)
Store 30(s2.resources.s0.ss) 32
35: 22(int) Load 34(s1.a)
Store 33(s2.resources.a) 35
ReturnValue 37
FunctionEnd

View File

@ -0,0 +1,207 @@
hlsl.flattenSubset2.frag
WARNING: AST will form illegal SPIR-V; need to transform to legalize
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:8 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:8 Function Parameters:
0:8 'vpos' ( in 4-component vector of float)
0:? Sequence
0:13 Sequence
0:13 move second child to first child ( temp float)
0:? 'a1.n.y' ( temp float)
0:? 'a2.n.y' ( temp float)
0:13 move second child to first child ( temp texture2D)
0:? 'a1.n.texNested' ( temp texture2D)
0:? 'a2.n.texNested' ( temp texture2D)
0:14 Sequence
0:14 move second child to first child ( temp float)
0:? 'b.n.y' ( temp float)
0:? 'a1.n.y' ( temp float)
0:14 move second child to first child ( temp texture2D)
0:? 'b.n.texNested' ( temp texture2D)
0:? 'a1.n.texNested' ( temp texture2D)
0:17 Sequence
0:17 Sequence
0:17 move second child to first child ( temp float)
0:? 'n.y' ( temp float)
0:? 'b.n.y' ( temp float)
0:17 move second child to first child ( temp texture2D)
0:? 'n.texNested' ( temp texture2D)
0:? 'b.n.texNested' ( temp texture2D)
0:20 move second child to first child ( temp texture2D)
0:? 'a2.n.texNested' ( temp texture2D)
0:20 'someTex' ( uniform texture2D)
0:21 move second child to first child ( temp float)
0:? 'a1.n.y' ( temp float)
0:21 Constant:
0:21 1.000000
0:23 Branch: Return with expression
0:? Constant:
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:8 Function Definition: main( ( temp void)
0:8 Function Parameters:
0:? Sequence
0:8 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
0:8 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:8 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? 'someTex' ( uniform texture2D)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
Linked fragment stage:
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:8 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:8 Function Parameters:
0:8 'vpos' ( in 4-component vector of float)
0:? Sequence
0:13 Sequence
0:13 move second child to first child ( temp float)
0:? 'a1.n.y' ( temp float)
0:? 'a2.n.y' ( temp float)
0:13 move second child to first child ( temp texture2D)
0:? 'a1.n.texNested' ( temp texture2D)
0:? 'a2.n.texNested' ( temp texture2D)
0:14 Sequence
0:14 move second child to first child ( temp float)
0:? 'b.n.y' ( temp float)
0:? 'a1.n.y' ( temp float)
0:14 move second child to first child ( temp texture2D)
0:? 'b.n.texNested' ( temp texture2D)
0:? 'a1.n.texNested' ( temp texture2D)
0:17 Sequence
0:17 Sequence
0:17 move second child to first child ( temp float)
0:? 'n.y' ( temp float)
0:? 'b.n.y' ( temp float)
0:17 move second child to first child ( temp texture2D)
0:? 'n.texNested' ( temp texture2D)
0:? 'b.n.texNested' ( temp texture2D)
0:20 move second child to first child ( temp texture2D)
0:? 'a2.n.texNested' ( temp texture2D)
0:20 'someTex' ( uniform texture2D)
0:21 move second child to first child ( temp float)
0:? 'a1.n.y' ( temp float)
0:21 Constant:
0:21 1.000000
0:23 Branch: Return with expression
0:? Constant:
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:? 0.000000
0:8 Function Definition: main( ( temp void)
0:8 Function Parameters:
0:? Sequence
0:8 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
0:8 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:8 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? 'someTex' ( uniform texture2D)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' (layout( location=0) in 4-component vector of float)
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 47
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 40 43
ExecutionMode 4 OriginUpperLeft
Source HLSL 500
Name 4 "main"
Name 11 "@main(vf4;"
Name 10 "vpos"
Name 14 "a1.n.y"
Name 15 "a2.n.y"
Name 19 "a1.n.texNested"
Name 20 "a2.n.texNested"
Name 22 "b.n.y"
Name 24 "b.n.texNested"
Name 26 "n.y"
Name 28 "n.texNested"
Name 31 "someTex"
Name 38 "vpos"
Name 40 "vpos"
Name 43 "@entryPointOutput"
Name 44 "param"
Decorate 31(someTex) DescriptorSet 0
Decorate 40(vpos) Location 0
Decorate 43(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Function 7(fvec4)
9: TypeFunction 7(fvec4) 8(ptr)
13: TypePointer Function 6(float)
17: TypeImage 6(float) 2D sampled format:Unknown
18: TypePointer Function 17
30: TypePointer UniformConstant 17
31(someTex): 30(ptr) Variable UniformConstant
33: 6(float) Constant 1065353216
34: 6(float) Constant 0
35: 7(fvec4) ConstantComposite 34 34 34 34
39: TypePointer Input 7(fvec4)
40(vpos): 39(ptr) Variable Input
42: TypePointer Output 7(fvec4)
43(@entryPointOutput): 42(ptr) Variable Output
4(main): 2 Function None 3
5: Label
38(vpos): 8(ptr) Variable Function
44(param): 8(ptr) Variable Function
41: 7(fvec4) Load 40(vpos)
Store 38(vpos) 41
45: 7(fvec4) Load 38(vpos)
Store 44(param) 45
46: 7(fvec4) FunctionCall 11(@main(vf4;) 44(param)
Store 43(@entryPointOutput) 46
Return
FunctionEnd
11(@main(vf4;): 7(fvec4) Function None 9
10(vpos): 8(ptr) FunctionParameter
12: Label
14(a1.n.y): 13(ptr) Variable Function
15(a2.n.y): 13(ptr) Variable Function
19(a1.n.texNested): 18(ptr) Variable Function
20(a2.n.texNested): 18(ptr) Variable Function
22(b.n.y): 13(ptr) Variable Function
24(b.n.texNested): 18(ptr) Variable Function
26(n.y): 13(ptr) Variable Function
28(n.texNested): 18(ptr) Variable Function
16: 6(float) Load 15(a2.n.y)
Store 14(a1.n.y) 16
21: 17 Load 20(a2.n.texNested)
Store 19(a1.n.texNested) 21
23: 6(float) Load 14(a1.n.y)
Store 22(b.n.y) 23
25: 17 Load 19(a1.n.texNested)
Store 24(b.n.texNested) 25
27: 6(float) Load 22(b.n.y)
Store 26(n.y) 27
29: 17 Load 24(b.n.texNested)
Store 28(n.texNested) 29
32: 17 Load 31(someTex)
Store 20(a2.n.texNested) 32
Store 14(a1.n.y) 33
ReturnValue 35
FunctionEnd

32
Test/hlsl.flattenSubset.frag Executable file
View File

@ -0,0 +1,32 @@
struct S0
{
int x;
int y;
SamplerState ss;
};
struct S1
{
float b;
SamplerState samplerState;
S0 s0;
int a;
};
struct S2
{
int a1;
int a2;
int a3;
int a4;
int a5;
S1 resources;
};
float4 main(float4 vpos : VPOS) : COLOR0
{
S1 s1;
S2 s2;
s2.resources = s1;
return float4(0,0,0,0);
}

24
Test/hlsl.flattenSubset2.frag Executable file
View File

@ -0,0 +1,24 @@
struct Nested { float y; Texture2D texNested; };
struct A { Nested n; float x; };
struct B { Nested n; Texture2D tex; };
Texture2D someTex;
float4 main(float4 vpos : VPOS) : COLOR0
{
A a1, a2;
B b;
// Assignment of nested structs to nested structs
a1.n = a2.n;
b .n = a1.n;
// Assignment of nested struct to standalone
Nested n = b.n;
// Assignment to nestested struct members
a2.n.texNested = someTex;
a1.n.y = 1.0;
return float4(0,0,0,0);
}

View File

@ -153,6 +153,8 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.flattenOpaque.frag", "main"},
{"hlsl.flattenOpaqueInit.vert", "main"},
{"hlsl.flattenOpaqueInitMix.vert", "main"},
{"hlsl.flattenSubset.frag", "main"},
{"hlsl.flattenSubset2.frag", "main"},
{"hlsl.forLoop.frag", "PixelShaderFunction"},
{"hlsl.gather.array.dx10.frag", "main"},
{"hlsl.gather.basic.dx10.frag", "main"},

View File

@ -1379,6 +1379,44 @@ TIntermTyped* HlslParseContext::flattenAccess(int uniqueId, int member, const TT
return subsetSymbol;
}
// For finding where the first leaf is in a subtree of a multi-level aggregate
// that is just getting a subset assigned. Follows the same logic as flattenAccess,
// but logically going down the "left-most" tree branch each step of the way.
//
// Returns the offset into the first leaf of the subset.
int HlslParseContext::findSubtreeOffset(const TIntermNode& node) const
{
const TIntermSymbol* sym = node.getAsSymbolNode();
if (sym == nullptr)
return 0;
if (!sym->isArray() && !sym->isStruct())
return 0;
int subset = sym->getFlattenSubset();
if (subset == -1)
return 0;
// Getting this far means a partial aggregate is identified by the flatten subset.
// Find the first leaf of the subset.
const auto flattenData = flattenMap.find(sym->getId());
if (flattenData == flattenMap.end())
return 0;
return findSubtreeOffset(sym->getType(), subset, flattenData->second.offsets);
do {
subset = flattenData->second.offsets[subset];
} while (true);
}
// Recursively do the desent
int HlslParseContext::findSubtreeOffset(const TType& type, int subset, const TVector<int>& offsets) const
{
if (!type.isArray() && !type.isStruct())
return offsets[subset];
TType derefType(type, 0);
return findSubtreeOffset(derefType, offsets[subset], offsets);
};
// Find and return the split IO TVariable for id, or nullptr if none.
TVariable* HlslParseContext::getSplitNonIoVar(int id) const
{
@ -1823,7 +1861,7 @@ void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, T
const TIntermAggregate* attrAgg = attributes[attr];
if (attrAgg == nullptr)
return false;
if (argNum >= attrAgg->getSequence().size())
if (argNum >= (int)attrAgg->getSequence().size())
return false;
const TConstUnion& intConst = attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
if (intConst.getType() != EbtInt)
@ -2595,31 +2633,29 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
}
}
int memberIdxLeft = 0;
int memberIdxRight = 0;
// When dealing with split arrayed structures of built-ins, the arrayness is moved to the extracted built-in
// variables, which is awkward when copying between split and unsplit structures. This variable tracks
// array indirections so they can be percolated from outer structs to inner variables.
std::vector <int> arrayElement;
// We track the outer-most aggregate, so that we can use its storage class later.
const TIntermTyped* outerLeft = left;
const TIntermTyped* outerRight = right;
TStorageQualifier leftStorage = left->getType().getQualifier().storage;
TStorageQualifier rightStorage = right->getType().getQualifier().storage;
const auto getMember = [&](bool isLeft, TIntermTyped* node, int member, TIntermTyped* splitNode, int splitMember)
int leftOffset = findSubtreeOffset(*left);
int rightOffset = findSubtreeOffset(*right);
const auto getMember = [&](bool isLeft, const TType& type, int member, TIntermTyped* splitNode, int splitMember)
-> TIntermTyped * {
const bool flattened = isLeft ? isFlattenLeft : isFlattenRight;
const bool split = isLeft ? isSplitLeft : isSplitRight;
TIntermTyped* subTree;
const TType derefType(node->getType(), member);
const TType derefType(type, member);
const TVariable* builtInVar = nullptr;
if ((flattened || split) && derefType.isBuiltIn()) {
const TIntermTyped* outer = isLeft ? outerLeft : outerRight;
auto splitPair = splitBuiltIns.find(HlslParseContext::tInterstageIoData(
derefType.getQualifier().builtIn,
outer->getType().getQualifier().storage));
isLeft ? leftStorage : rightStorage));
if (splitPair != splitBuiltIns.end())
builtInVar = splitPair->second;
}
@ -2637,13 +2673,13 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
}
} else if (flattened && isFinalFlattening(derefType)) {
if (isLeft)
subTree = intermediate.addSymbol(*(*leftVariables)[memberIdxLeft++]);
subTree = intermediate.addSymbol(*(*leftVariables)[leftOffset++]);
else
subTree = intermediate.addSymbol(*(*rightVariables)[memberIdxRight++]);
subTree = intermediate.addSymbol(*(*rightVariables)[rightOffset++]);
} else {
// Index operator if it's an aggregate, else EOpNull
const TOperator accessOp = node->getType().isArray() ? EOpIndexDirect
: node->getType().isStruct() ? EOpIndexDirectStruct
const TOperator accessOp = type.isArray() ? EOpIndexDirect
: type.isStruct() ? EOpIndexDirectStruct
: EOpNull;
if (accessOp == EOpNull) {
subTree = splitNode;
@ -2684,12 +2720,12 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
arrayElement.push_back(element);
// Add a new AST symbol node if we have a temp variable holding a complex RHS.
TIntermTyped* subLeft = getMember(true, left, element, left, element);
TIntermTyped* subRight = getMember(false, right, element, right, element);
TIntermTyped* subLeft = getMember(true, left->getType(), element, left, element);
TIntermTyped* subRight = getMember(false, right->getType(), element, right, element);
TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left, element, splitLeft, element)
TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left->getType(), element, splitLeft, element)
: subLeft;
TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right, element, splitRight, element)
TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right->getType(), element, splitRight, element)
: subRight;
traverse(subLeft, subRight, subSplitLeft, subSplitRight);
@ -2714,13 +2750,13 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
const TType& typeL = *membersL[member].type;
const TType& typeR = *membersR[member].type;
TIntermTyped* subLeft = getMember(true, left, member, left, member);
TIntermTyped* subRight = getMember(false, right, member, right, member);
TIntermTyped* subLeft = getMember(true, left->getType(), member, left, member);
TIntermTyped* subRight = getMember(false, right->getType(), member, right, member);
// If there is no splitting, use the same values to avoid inefficiency.
TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left, member, splitLeft, memberL)
TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left->getType(), member, splitLeft, memberL)
: subLeft;
TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right, member, splitRight, memberR)
TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right->getType(), member, splitRight, memberR)
: subRight;
if (isClipOrCullDistance(subSplitLeft->getType()) || isClipOrCullDistance(subSplitRight->getType())) {

View File

@ -245,6 +245,8 @@ protected:
// Array and struct flattening
TIntermTyped* flattenAccess(TIntermTyped* base, int member);
TIntermTyped* flattenAccess(int uniqueId, int member, const TType&, int subset = -1);
int findSubtreeOffset(const TIntermNode&) const;
int findSubtreeOffset(const TType&, int subset, const TVector<int>& offsets) const;
bool shouldFlatten(const TType&) const;
bool wasFlattened(const TIntermTyped* node) const;
bool wasFlattened(int id) const { return flattenMap.find(id) != flattenMap.end(); }