Skip to content

Commit

Permalink
Support specialization composite constants
Browse files Browse the repository at this point in the history
Fix issue KhronosGroup#163, support creation and reference of composite type
specialization constants.

e.g.:
```
layout(constant_id = 200) const float myfloat = 1.25;
layout(constant_id = 201) const int myint = 14;
struct structtype {
  float f;
  int i;
};
const structtype outer_struct_var = {myfloat, myint};
void main(){}
```
generated code (use glslangValidator):
```
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 12

                              Capability Shader
               1:             ExtInstImport  "GLSL.std.450"
                              MemoryModel Logical GLSL450
                              EntryPoint Vertex 4  "main"
                              Source GLSL 450
                              Name 4  "main"
                              Name 10  "structtype"
                              MemberName 10(structtype) 0  "f"
                              MemberName 10(structtype) 1  "i"
                              Decorate 7 SpecId 200
                              Decorate 9 SpecId 201
               2:             TypeVoid
               3:             TypeFunction 2
               6:             TypeFloat 32
               7:    6(float) SpecConstant 1067450368
               8:             TypeInt 32 1
               9:      8(int) SpecConstant 14
  10(structtype):             TypeStruct 6(float) 8(int)
              11:10(structtype) SpecConstantComposite 7 9
         4(main):           2 Function None 3
               5:             Label
                              Return
                              FunctionEnd
```

Rname two function names to match their functionalities.
1) Rename `GlslangToSpvTraverser::createSpvSpecConstant()` to
`createSpvConstant()`;
2) Rename `GlslangToSpvTraverser::createSpvConstant()` to
`createSpvConstantFromConstUnionArray()`

Add function `GlslangToSpvTraverser::createSpvConstantFromSubTree()` to
handle constant creation from sub trees (e.g.: specialization constants).

Related PR: KhronosGroup#208
  • Loading branch information
Qining committed Mar 24, 2016
1 parent 28001b1 commit 0840838
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 19 deletions.
87 changes: 75 additions & 12 deletions SPIRV/GlslangToSpv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
spv::Id createSpvConstant(const glslang::TIntermTyped&);
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
spv::Id createSpvConstantFromConstSubTree(const glslang::TIntermTyped* subTree);
bool isTrivialLeaf(const glslang::TIntermTyped* node);
bool isTrivial(const glslang::TIntermTyped* node);
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
Expand Down Expand Up @@ -1520,7 +1521,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
{
int nextConst = 0;
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);

builder.clearAccessChain();
builder.setAccessChainRValue(constant);
Expand Down Expand Up @@ -1630,7 +1631,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
// can still have a mapping to a SPIR-V Id.
// This includes specialization constants.
if (node->getQualifier().isConstant()) {
return createSpvSpecConstant(*node);
return createSpvConstant(*node);
}

// Now, handle actual variables
Expand Down Expand Up @@ -3730,15 +3731,15 @@ void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::De
// recursively walks. So, this function walks the "top" of the tree:
// - emit specialization constant-building instructions for specConstant
// - when running into a non-spec-constant, switch to createSpvConstant()
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
{
assert(node.getQualifier().isConstant());

if (! node.getQualifier().specConstant) {
// hand off to the non-spec-constant path
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
int nextConst = 0;
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
nextConst, false);
}

Expand All @@ -3747,7 +3748,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
if (node.getAsSymbolNode() && node.getQualifier().hasSpecConstantId()) {
// this is a direct literal assigned to a layout(constant_id=) declaration
int nextConst = 0;
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
nextConst, true);
} else {
// gl_WorkgroupSize is a special case until the front-end handles hierarchical specialization constants,
Expand All @@ -3761,8 +3762,10 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim));
}
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
} else if (auto* sn = node.getAsSymbolNode()){
return createSpvConstantFromConstSubTree(sn->getConstSubtree());
} else {
spv::MissingFunctionality("specialization-constant expression trees");
spv::MissingFunctionality("Neither a front-end constant nor a spec constant.");
exit(1);
return spv::NoResult;
}
Expand All @@ -3775,7 +3778,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
// If there are not enough elements present in 'consts', 0 will be substituted;
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
//
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
{
// vector of constants for SPIR-V
std::vector<spv::Id> spvConsts;
Expand All @@ -3786,15 +3789,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
if (glslangType.isArray()) {
glslang::TType elementType(glslangType, 0);
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
} else if (glslangType.isMatrix()) {
glslang::TType vectorType(glslangType, 0);
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
} else if (glslangType.getStruct()) {
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
} else if (glslangType.isVector()) {
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
bool zero = nextConst >= consts.size();
Expand Down Expand Up @@ -3851,6 +3854,66 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
return builder.makeCompositeConstant(typeId, spvConsts);
}

// Create constant ID from const initializer sub tree.
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree(
const glslang::TIntermTyped* subTree) {
const glslang::TType& glslangType = subTree->getType();
spv::Id typeId = convertGlslangToSpvType(glslangType);
bool is_spec_const = subTree->getType().getQualifier().isSpecConstant();
if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) {
// Aggregate node, we should generate OpConstantComposite or
// OpSpecConstantComposite instruction.
std::vector<spv::Id> const_constituents;
for (auto NI = an->getSequence().begin(); NI != an->getSequence().end();
NI++) {
const_constituents.push_back(
createSpvConstantFromConstSubTree((*NI)->getAsTyped()));
}
// Note that constructors are aggregate nodes, so expressions like:
// float x = float(y) will become an aggregate node. If 'x' is declared
// as a constant, the aggregate node representing 'float(y)' will be
// processed here.
if (builder.isVectorType(typeId) || builder.isMatrixType(typeId) ||
builder.isAggregateType(typeId)) {
return builder.makeCompositeConstant(typeId, const_constituents, is_spec_const);
} else {
assert(builder.isScalarType(typeId) && const_constituents.size() == 1);
return const_constituents.front();
}

} else if (const glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) {
// Binary operation node, we should generate OpSpecConstantOp <binary op>
// This case should only happen when Specialization Constants are involved.
spv::MissingFunctionality("OpSpecConstantOp <binary op> not implemented");
return spv::NoResult;

} else if (const glslang::TIntermUnary* un = subTree->getAsUnaryNode()) {
// Unary operation node, similar to binary operation node, should only
// happen when specialization constants are involved.
spv::MissingFunctionality("OpSpecConstantOp <unary op> not implemented");
return spv::NoResult;

} else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) {
// ConstantUnion node, should redirect to
// createSpvConstantFromConstUnionArray
int nextConst = 0;
return createSpvConstantFromConstUnionArray(
glslangType, cn->getConstArray(), nextConst, is_spec_const);

} else if (const glslang::TIntermSymbol* sn = subTree->getAsSymbolNode()) {
// Symbol node. Call getSymbolId(). This should cover both cases 1) the
// symbol has already been assigned an ID, 2) need a new ID for this
// symbol.
return getSymbolId(sn);

} else {
spv::MissingFunctionality(
"createSpvConstantFromConstSubTree() not covered TIntermTyped* const "
"initializer subtree.");
return spv::NoResult;
}
}

// Return true if the node is a constant or symbol whose reading has no
// non-trivial observable cost or effect.
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
Expand Down
172 changes: 172 additions & 0 deletions Test/baseResults/spv.specConstantComposite.vert.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
spv.specConstantComposite.vert
Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.


Linked vertex stage:


// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 106

Capability Shader
Capability Float64
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 27 105
Source GLSL 450
Name 4 "main"
Name 6 "refer_primary_spec_const("
Name 8 "refer_composite_spec_const("
Name 10 "refer_copmosite_dot_dereference("
Name 12 "refer_composite_bracket_dereference("
Name 16 "refer_spec_const_array_length("
Name 18 "declare_spec_const_in_func("
Name 27 "color"
Name 41 "flat_struct"
MemberName 41(flat_struct) 0 "i"
MemberName 41(flat_struct) 1 "f"
MemberName 41(flat_struct) 2 "d"
MemberName 41(flat_struct) 3 "b"
Name 42 "nesting_struct"
MemberName 42(nesting_struct) 0 "nested"
MemberName 42(nesting_struct) 1 "v"
MemberName 42(nesting_struct) 2 "i"
Name 72 "indexable"
Name 76 "indexable"
Name 83 "len"
Name 105 "global_vec4_array_with_spec_length"
Decorate 21 SpecId 203
Decorate 28 SpecId 200
Decorate 32 SpecId 201
Decorate 43 SpecId 202
2: TypeVoid
3: TypeFunction 2
14: TypeInt 32 1
15: TypeFunction 14(int)
20: TypeBool
21: 20(bool) SpecConstantTrue
24: TypeFloat 32
25: TypeVector 24(float) 4
26: TypePointer Output 25(fvec4)
27(color): 26(ptr) Variable Output
28: 14(int) SpecConstant 3
32: 24(float) SpecConstant 1078523331
33: 25(fvec4) SpecConstantComposite 32 32 32 32
36: 24(float) Constant 1133908460
37: 25(fvec4) SpecConstantComposite 32 32 36 36
40: TypeFloat 64
41(flat_struct): TypeStruct 14(int) 24(float) 40(float) 20(bool)
42(nesting_struct): TypeStruct 41(flat_struct) 25(fvec4) 14(int)
43: 40(float) SpecConstant 1413754136 1074340347
44:41(flat_struct) SpecConstantComposite 28 32 43 21
45:42(nesting_struct) SpecConstantComposite 44 33 28
46: 14(int) Constant 2
51: TypeInt 32 0
52: 51(int) Constant 0
57: 51(int) Constant 5
58: TypeArray 24(float) 57
59: 24(float) Constant 1065353216
60: 24(float) Constant 1073741824
61: 24(float) Constant 1077936128
62: 58 SpecConstantComposite 32 32 59 60 61
63: 14(int) Constant 1
68: TypeArray 14(int) 57
69: 14(int) Constant 30
70: 68 SpecConstantComposite 28 28 63 46 69
71: TypePointer Function 68
73: TypePointer Function 14(int)
87: 24(float) Constant 1106321080
88:41(flat_struct) SpecConstantComposite 69 87 43 21
89: 14(int) Constant 10
90:42(nesting_struct) SpecConstantComposite 88 37 89
96: 20(bool) ConstantFalse
97:41(flat_struct) SpecConstantComposite 28 32 43 96
98: 24(float) Constant 1036831949
99: 25(fvec4) ConstantComposite 98 98 98 98
100:42(nesting_struct) SpecConstantComposite 97 99 28
101: 14(int) Constant 3000
102:42(nesting_struct) SpecConstantComposite 88 37 101
103: TypeArray 25(fvec4) 28
104: TypePointer Input 103
105(global_vec4_array_with_spec_length): 104(ptr) Variable Input
4(main): 2 Function None 3
5: Label
Return
FunctionEnd
6(refer_primary_spec_const(): 2 Function None 3
7: Label
SelectionMerge 23 None
BranchConditional 21 22 23
22: Label
29: 24(float) ConvertSToF 28
30: 25(fvec4) Load 27(color)
31: 25(fvec4) VectorTimesScalar 30 29
Store 27(color) 31
Branch 23
23: Label
Return
FunctionEnd
8(refer_composite_spec_const(): 2 Function None 3
9: Label
34: 25(fvec4) Load 27(color)
35: 25(fvec4) FAdd 34 33
Store 27(color) 35
38: 25(fvec4) Load 27(color)
39: 25(fvec4) FSub 38 37
Store 27(color) 39
Return
FunctionEnd
10(refer_copmosite_dot_dereference(): 2 Function None 3
11: Label
47: 14(int) CompositeExtract 45 2
48: 24(float) ConvertSToF 47
49: 25(fvec4) Load 27(color)
50: 25(fvec4) VectorTimesScalar 49 48
Store 27(color) 50
53: 24(float) CompositeExtract 33 0
54: 25(fvec4) Load 27(color)
55: 25(fvec4) CompositeConstruct 53 53 53 53
56: 25(fvec4) FAdd 54 55
Store 27(color) 56
Return
FunctionEnd
12(refer_composite_bracket_dereference(): 2 Function None 3
13: Label
72(indexable): 71(ptr) Variable Function
76(indexable): 71(ptr) Variable Function
64: 24(float) CompositeExtract 62 1
65: 25(fvec4) Load 27(color)
66: 25(fvec4) CompositeConstruct 64 64 64 64
67: 25(fvec4) FSub 65 66
Store 27(color) 67
Store 72(indexable) 70
74: 73(ptr) AccessChain 72(indexable) 28
75: 14(int) Load 74
Store 76(indexable) 70
77: 73(ptr) AccessChain 76(indexable) 75
78: 14(int) Load 77
79: 24(float) ConvertSToF 78
80: 25(fvec4) Load 27(color)
81: 25(fvec4) CompositeConstruct 79 79 79 79
82: 25(fvec4) FDiv 80 81
Store 27(color) 82
Return
FunctionEnd
16(refer_spec_const_array_length(): 14(int) Function None 15
17: Label
83(len): 73(ptr) Variable Function
Store 83(len) 28
84: 14(int) Load 83(len)
ReturnValue 84
FunctionEnd
18(declare_spec_const_in_func(): 2 Function None 3
19: Label
91: 14(int) CompositeExtract 90 2
92: 24(float) ConvertSToF 91
93: 25(fvec4) Load 27(color)
94: 25(fvec4) CompositeConstruct 92 92 92 92
95: 25(fvec4) FDiv 93 94
Store 27(color) 95
Return
FunctionEnd
Loading

0 comments on commit 0840838

Please sign in to comment.