spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim);
spv::Id accessChainLoad(const glslang::TType& type);
void accessChainStore(const glslang::TType& type, spv::Id rvalue);
+ void multiTypeStore(const glslang::TType&, spv::Id rValue);
glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
std::unordered_map<const char*, spv::Id> extBuiltinMap;
std::unordered_map<int, spv::Id> symbolValues;
- std::unordered_set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
+ std::unordered_set<int> rValueParameters; // set of formal function parameters passed as rValues, rather than a pointer
std::unordered_map<std::string, spv::Function*> functionMap;
std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
// For now, we consider all user variables as being in memory, so they are pointers,
// except for
- // A) "const in" arguments to a function, which are an intermediate object.
+ // A) R-Value arguments to a function, which are an intermediate object.
// See comments in handleUserFunctionCall().
- // B) Specialization constants (normal constant don't even come in as a variable),
+ // B) Specialization constants (normal constants don't even come in as a variable),
// These are also pure R-values.
glslang::TQualifier qualifier = symbol->getQualifier();
- if ((qualifier.storage == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end()) ||
- qualifier.isSpecConstant())
+ if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end())
builder.setAccessChainRValue(id);
else
builder.setAccessChainLValue(id);
// store the result
builder.setAccessChain(lValue);
- if (builder.isStructType(builder.getTypeId(rValue))) {
- //spv::Id lType = builder.getContainedTypeId(builder.getTypeId(builder.accessChainGetLValue()));
- //spv::Id rType = builder.getTypeId(rValue);
- //if (lType != rType) {
- // TODO: do member-wise copy instead, this is current issue
- // https://github.com/KhronosGroup/glslang/issues/304
- //} else
- accessChainStore(node->getType(), rValue);
- } else
- accessChainStore(node->getType(), rValue);
+ multiTypeStore(node->getType(), rValue);
// assignments are expressions having an rValue after they are evaluated...
builder.clearAccessChain();
// Wrap the builder's accessChainStore to:
// - do conversion of concrete to abstract type
+//
+// Implicitly uses the existing builder.accessChain as the storage target.
void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
{
// Need to convert to abstract types when necessary
builder.accessChainStore(rvalue);
}
+// For storing when types match at the glslang level, but not might match at the
+// SPIR-V level.
+//
+// This especially happens when a single glslang type expands to multiple
+// SPIR-V types, like a struct that is used in an member-undecorated way as well
+// as in a member-decorated way.
+//
+// NOTE: This function can handle any store request; if it's not special it
+// simplifies to a simple OpStore.
+//
+// Implicitly uses the existing builder.accessChain as the storage target.
+void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)
+{
+ // we only do the complex path here if it's a structure
+ if (! type.isStruct()) {
+ accessChainStore(type, rValue);
+ return;
+ }
+
+ // and, it has to be a case of structure type aliasing
+ spv::Id rType = builder.getTypeId(rValue);
+ spv::Id lValue = builder.accessChainGetLValue();
+ spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));
+ if (lType == rType) {
+ accessChainStore(type, rValue);
+ return;
+ }
+
+ // Recursively (as needed) copy a struct type to a different struct type,
+ // where the two types were the same type in GLSL. This requires member
+ // by member copy, recursively.
+
+ // loop over members
+ const glslang::TTypeList& members = *type.getStruct();
+ for (int m = 0; m < (int)members.size(); ++m) {
+ const glslang::TType& glslangMemberType = *members[m].type;
+
+ // get the source member
+ spv::Id memberRType = builder.getContainedTypeId(rType, m);
+ spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);
+
+ // set up the target storage
+ builder.clearAccessChain();
+ builder.setAccessChainLValue(lValue);
+ builder.accessChainPush(builder.makeIntConstant(m));
+
+ // store the member
+ multiTypeStore(glslangMemberType, memberRValue);
+ }
+}
+
// Decide whether or not this type should be
// decorated with offsets and strides, and if so
// whether std140 or std430 rules should be applied.
continue;
// We're on a user function. Set up the basic interface for the function now,
- // so that it's available to call.
- // Translating the body will happen later.
+ // so that it's available to call. Translating the body will happen later.
//
// Typically (except for a "const in" parameter), an address will be passed to the
// function. What it is an address of varies:
//
- // - "in" parameters not marked as "const" can be written to without modifying the argument,
- // so that write needs to be to a copy, hence the address of a copy works.
+ // - "in" parameters not marked as "const" can be written to without modifying the calling
+ // argument so that write needs to be to a copy, hence the address of a copy works.
//
// - "const in" parameters can just be the r-value, as no writes need occur.
//
- // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
- // copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
+ // - "out" and "inout" arguments can't be done as pointers to the calling argument, because
+ // GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
std::vector<spv::Id> paramTypes;
std::vector<spv::Decoration> paramPrecisions;
else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
typeId = builder.makePointer(spv::StorageClassFunction, typeId);
else
- constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
+ rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
paramPrecisions.push_back(TranslatePrecisionDecoration(paramType));
paramTypes.push_back(typeId);
}
// need to copy the input into output space
builder.setAccessChain(lValues[lValueCount]);
spv::Id copy = accessChainLoad(*argTypes[a]);
- builder.createStore(copy, arg);
+ builder.clearAccessChain();
+ builder.setAccessChainLValue(arg);
+ multiTypeStore(paramType, copy);
}
++lValueCount;
} else {
// 4. Copy back out an "out" arguments.
lValueCount = 0;
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+ const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
if (qualifiers[a] != glslang::EvqConstReadOnly) {
if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
spv::Id copy = builder.createLoad(spvArgs[a]);
builder.setAccessChain(lValues[lValueCount]);
- accessChainStore(glslangArgs[a]->getAsTyped()->getType(), copy);
+ multiTypeStore(paramType, copy);
}
++lValueCount;
}
--- /dev/null
+spv.multiStruct.comp
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+
+Linked compute stage:
+
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 97
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint GLCompute 4 "main"
+ ExecutionMode 4 LocalSize 1 1 1
+ Source GLSL 450
+ Name 4 "main"
+ Name 9 "MyStruct"
+ MemberName 9(MyStruct) 0 "foo"
+ MemberName 9(MyStruct) 1 "sb"
+ Name 11 "t"
+ Name 13 "MyStruct"
+ MemberName 13(MyStruct) 0 "foo"
+ MemberName 13(MyStruct) 1 "sb"
+ Name 14 "SSBO0"
+ MemberName 14(SSBO0) 0 "a"
+ Name 16 "inBuf"
+ Name 29 "SSBO1"
+ MemberName 29(SSBO1) 0 "b"
+ Name 31 "outBuf"
+ Name 43 "MyStruct"
+ MemberName 43(MyStruct) 0 "foo"
+ MemberName 43(MyStruct) 1 "sb"
+ Name 44 "UBO"
+ MemberName 44(UBO) 0 "c"
+ Name 46 "uBuf"
+ Name 61 "Nested"
+ MemberName 61(Nested) 0 "f"
+ MemberName 61(Nested) 1 "S"
+ Name 63 "n"
+ Name 64 "Nested"
+ MemberName 64(Nested) 0 "f"
+ MemberName 64(Nested) 1 "S"
+ Name 65 "UBON"
+ MemberName 65(UBON) 0 "N1"
+ Name 67 "uBufN"
+ Name 80 "Nested"
+ MemberName 80(Nested) 0 "f"
+ MemberName 80(Nested) 1 "S"
+ Name 81 "SSBO1N"
+ MemberName 81(SSBO1N) 0 "N2"
+ Name 83 "outBufN"
+ MemberDecorate 13(MyStruct) 0 Offset 0
+ MemberDecorate 13(MyStruct) 1 Offset 16
+ MemberDecorate 14(SSBO0) 0 Offset 0
+ Decorate 14(SSBO0) BufferBlock
+ Decorate 16(inBuf) DescriptorSet 0
+ Decorate 16(inBuf) Binding 0
+ MemberDecorate 29(SSBO1) 0 Offset 0
+ Decorate 29(SSBO1) BufferBlock
+ Decorate 31(outBuf) DescriptorSet 0
+ Decorate 31(outBuf) Binding 1
+ MemberDecorate 43(MyStruct) 0 Offset 0
+ MemberDecorate 43(MyStruct) 1 Offset 16
+ MemberDecorate 44(UBO) 0 Offset 0
+ Decorate 44(UBO) Block
+ Decorate 46(uBuf) DescriptorSet 0
+ Decorate 46(uBuf) Binding 2
+ MemberDecorate 64(Nested) 0 Offset 0
+ MemberDecorate 64(Nested) 1 Offset 16
+ MemberDecorate 65(UBON) 0 Offset 0
+ Decorate 65(UBON) Block
+ Decorate 67(uBufN) DescriptorSet 0
+ Decorate 67(uBufN) Binding 2
+ MemberDecorate 80(Nested) 0 Offset 0
+ MemberDecorate 80(Nested) 1 Offset 16
+ MemberDecorate 81(SSBO1N) 0 Offset 0
+ Decorate 81(SSBO1N) BufferBlock
+ Decorate 83(outBufN) DescriptorSet 0
+ Decorate 83(outBufN) Binding 1
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 4
+ 8: TypeBool
+ 9(MyStruct): TypeStruct 7(fvec4) 8(bool)
+ 10: TypePointer Function 9(MyStruct)
+ 12: TypeInt 32 0
+ 13(MyStruct): TypeStruct 7(fvec4) 12(int)
+ 14(SSBO0): TypeStruct 13(MyStruct)
+ 15: TypePointer Uniform 14(SSBO0)
+ 16(inBuf): 15(ptr) Variable Uniform
+ 17: TypeInt 32 1
+ 18: 17(int) Constant 0
+ 19: TypePointer Uniform 13(MyStruct)
+ 23: TypePointer Function 7(fvec4)
+ 26: 17(int) Constant 1
+ 27: TypePointer Function 8(bool)
+ 29(SSBO1): TypeStruct 13(MyStruct)
+ 30: TypePointer Uniform 29(SSBO1)
+ 31(outBuf): 30(ptr) Variable Uniform
+ 35: TypePointer Uniform 7(fvec4)
+ 38: 12(int) Constant 0
+ 39: 12(int) Constant 1
+ 41: TypePointer Uniform 12(int)
+ 43(MyStruct): TypeStruct 7(fvec4) 12(int)
+ 44(UBO): TypeStruct 43(MyStruct)
+ 45: TypePointer Uniform 44(UBO)
+ 46(uBuf): 45(ptr) Variable Uniform
+ 47: TypePointer Uniform 43(MyStruct)
+ 61(Nested): TypeStruct 6(float) 9(MyStruct)
+ 62: TypePointer Function 61(Nested)
+ 64(Nested): TypeStruct 6(float) 43(MyStruct)
+ 65(UBON): TypeStruct 64(Nested)
+ 66: TypePointer Uniform 65(UBON)
+ 67(uBufN): 66(ptr) Variable Uniform
+ 68: TypePointer Uniform 64(Nested)
+ 72: TypePointer Function 6(float)
+ 80(Nested): TypeStruct 6(float) 13(MyStruct)
+ 81(SSBO1N): TypeStruct 80(Nested)
+ 82: TypePointer Uniform 81(SSBO1N)
+ 83(outBufN): 82(ptr) Variable Uniform
+ 85: TypePointer Uniform 80(Nested)
+ 88: TypePointer Uniform 6(float)
+ 4(main): 2 Function None 3
+ 5: Label
+ 11(t): 10(ptr) Variable Function
+ 63(n): 62(ptr) Variable Function
+ 20: 19(ptr) AccessChain 16(inBuf) 18
+ 21:13(MyStruct) Load 20
+ 22: 7(fvec4) CompositeExtract 21 0
+ 24: 23(ptr) AccessChain 11(t) 18
+ Store 24 22
+ 25: 12(int) CompositeExtract 21 1
+ 28: 27(ptr) AccessChain 11(t) 26
+ Store 28 25
+ 32: 9(MyStruct) Load 11(t)
+ 33: 19(ptr) AccessChain 31(outBuf) 18
+ 34: 7(fvec4) CompositeExtract 32 0
+ 36: 35(ptr) AccessChain 33 18
+ Store 36 34
+ 37: 8(bool) CompositeExtract 32 1
+ 40: 12(int) Select 37 39 38
+ 42: 41(ptr) AccessChain 33 26
+ Store 42 40
+ 48: 47(ptr) AccessChain 46(uBuf) 18
+ 49:43(MyStruct) Load 48
+ 50: 7(fvec4) CompositeExtract 49 0
+ 51: 23(ptr) AccessChain 11(t) 18
+ Store 51 50
+ 52: 12(int) CompositeExtract 49 1
+ 53: 27(ptr) AccessChain 11(t) 26
+ Store 53 52
+ 54: 9(MyStruct) Load 11(t)
+ 55: 19(ptr) AccessChain 31(outBuf) 18
+ 56: 7(fvec4) CompositeExtract 54 0
+ 57: 35(ptr) AccessChain 55 18
+ Store 57 56
+ 58: 8(bool) CompositeExtract 54 1
+ 59: 12(int) Select 58 39 38
+ 60: 41(ptr) AccessChain 55 26
+ Store 60 59
+ 69: 68(ptr) AccessChain 67(uBufN) 18
+ 70: 64(Nested) Load 69
+ 71: 6(float) CompositeExtract 70 0
+ 73: 72(ptr) AccessChain 63(n) 18
+ Store 73 71
+ 74:43(MyStruct) CompositeExtract 70 1
+ 75: 10(ptr) AccessChain 63(n) 26
+ 76: 7(fvec4) CompositeExtract 74 0
+ 77: 23(ptr) AccessChain 75 18
+ Store 77 76
+ 78: 12(int) CompositeExtract 74 1
+ 79: 27(ptr) AccessChain 75 26
+ Store 79 78
+ 84: 61(Nested) Load 63(n)
+ 86: 85(ptr) AccessChain 83(outBufN) 18
+ 87: 6(float) CompositeExtract 84 0
+ 89: 88(ptr) AccessChain 86 18
+ Store 89 87
+ 90: 9(MyStruct) CompositeExtract 84 1
+ 91: 19(ptr) AccessChain 86 26
+ 92: 7(fvec4) CompositeExtract 90 0
+ 93: 35(ptr) AccessChain 91 18
+ Store 93 92
+ 94: 8(bool) CompositeExtract 90 1
+ 95: 12(int) Select 94 39 38
+ 96: 41(ptr) AccessChain 91 26
+ Store 96 95
+ Return
+ FunctionEnd
--- /dev/null
+spv.multiStructFuncall.frag
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+
+Linked fragment stage:
+
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 63
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ Name 4 "main"
+ Name 9 "S"
+ MemberName 9(S) 0 "m"
+ Name 12 "fooConst(struct-S-mf441;"
+ Name 11 "s"
+ Name 17 "foo(struct-S-mf441;"
+ Name 16 "s"
+ Name 20 "fooOut(struct-S-mf441;"
+ Name 19 "s"
+ Name 22 "S"
+ MemberName 22(S) 0 "m"
+ Name 23 "blockName"
+ MemberName 23(blockName) 0 "s1"
+ Name 25 ""
+ Name 33 "s2"
+ Name 36 "S"
+ MemberName 36(S) 0 "m"
+ Name 38 "param"
+ Name 45 "param"
+ Name 48 "param"
+ Name 59 "param"
+ MemberDecorate 22(S) 0 ColMajor
+ MemberDecorate 22(S) 0 Offset 0
+ MemberDecorate 22(S) 0 MatrixStride 16
+ MemberDecorate 23(blockName) 0 Offset 0
+ Decorate 23(blockName) BufferBlock
+ Decorate 25 DescriptorSet 0
+ MemberDecorate 36(S) 0 ColMajor
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 4
+ 8: TypeMatrix 7(fvec4) 4
+ 9(S): TypeStruct 8
+ 10: TypeFunction 2 9(S)
+ 14: TypePointer Function 9(S)
+ 15: TypeFunction 2 14(ptr)
+ 22(S): TypeStruct 8
+ 23(blockName): TypeStruct 22(S)
+ 24: TypePointer Uniform 23(blockName)
+ 25: 24(ptr) Variable Uniform
+ 26: TypeInt 32 1
+ 27: 26(int) Constant 0
+ 28: TypePointer Uniform 22(S)
+ 32: TypePointer Private 9(S)
+ 33(s2): 32(ptr) Variable Private
+ 36(S): TypeStruct 8
+ 37: TypePointer Function 36(S)
+ 42: TypePointer Function 8
+ 57: TypePointer Uniform 8
+ 4(main): 2 Function None 3
+ 5: Label
+ 38(param): 37(ptr) Variable Function
+ 45(param): 14(ptr) Variable Function
+ 48(param): 37(ptr) Variable Function
+ 59(param): 14(ptr) Variable Function
+ 29: 28(ptr) AccessChain 25 27
+ 30: 22(S) Load 29
+ 31: 2 FunctionCall 12(fooConst(struct-S-mf441;) 30
+ 34: 9(S) Load 33(s2)
+ 35: 2 FunctionCall 12(fooConst(struct-S-mf441;) 34
+ 39: 28(ptr) AccessChain 25 27
+ 40: 22(S) Load 39
+ 41: 8 CompositeExtract 40 0
+ 43: 42(ptr) AccessChain 38(param) 27
+ Store 43 41
+ 44: 2 FunctionCall 17(foo(struct-S-mf441;) 38(param)
+ 46: 9(S) Load 33(s2)
+ Store 45(param) 46
+ 47: 2 FunctionCall 17(foo(struct-S-mf441;) 45(param)
+ 49: 28(ptr) AccessChain 25 27
+ 50: 22(S) Load 49
+ 51: 8 CompositeExtract 50 0
+ 52: 42(ptr) AccessChain 48(param) 27
+ Store 52 51
+ 53: 2 FunctionCall 20(fooOut(struct-S-mf441;) 48(param)
+ 54: 36(S) Load 48(param)
+ 55: 28(ptr) AccessChain 25 27
+ 56: 8 CompositeExtract 54 0
+ 58: 57(ptr) AccessChain 55 27
+ Store 58 56
+ 60: 9(S) Load 33(s2)
+ Store 59(param) 60
+ 61: 2 FunctionCall 20(fooOut(struct-S-mf441;) 59(param)
+ 62: 9(S) Load 59(param)
+ Store 33(s2) 62
+ Return
+ FunctionEnd
+12(fooConst(struct-S-mf441;): 2 Function None 10
+ 11(s): 9(S) FunctionParameter
+ 13: Label
+ Return
+ FunctionEnd
+17(foo(struct-S-mf441;): 2 Function None 15
+ 16(s): 14(ptr) FunctionParameter
+ 18: Label
+ Return
+ FunctionEnd
+20(fooOut(struct-S-mf441;): 2 Function None 15
+ 19(s): 14(ptr) FunctionParameter
+ 21: Label
+ Return
+ FunctionEnd
--- /dev/null
+#version 450 core\r
+\r
+struct MyStruct\r
+{\r
+ vec4 foo;\r
+ bool sb;\r
+};\r
+\r
+layout(binding = 0, std430) buffer SSBO0\r
+{\r
+ MyStruct a;\r
+} inBuf;\r
+\r
+layout(binding = 1, std430) buffer SSBO1\r
+{\r
+ MyStruct b;\r
+} outBuf;\r
+\r
+layout(binding = 2, std140) uniform UBO\r
+{\r
+ MyStruct c;\r
+} uBuf;\r
+\r
+struct Nested {\r
+ float f;\r
+ MyStruct S;\r
+};\r
+\r
+layout(binding = 2, std140) uniform UBON\r
+{\r
+ Nested N1;\r
+} uBufN;\r
+\r
+layout(binding = 1, std430) buffer SSBO1N\r
+{\r
+ Nested N2;\r
+} outBufN;\r
+\r
+void main()\r
+{\r
+ MyStruct t = inBuf.a;\r
+ outBuf.b = t;\r
+ t = uBuf.c;\r
+ outBuf.b = t;\r
+\r
+ Nested n = uBufN.N1;\r
+ outBufN.N2 = n;\r
+}\r
--- /dev/null
+#version 450\r
+\r
+struct S { mat4 m; };\r
+buffer blockName { S s1; }; // need an S with decoration\r
+S s2; // no decorations on S\r
+\r
+void fooConst(const in S s) { }\r
+void foo(in S s) { }\r
+void fooOut(inout S s) { }\r
+\r
+void main()\r
+{\r
+ fooConst(s1);\r
+ fooConst(s2);\r
+\r
+ foo(s1);\r
+ foo(s2);\r
+\r
+ fooOut(s1);\r
+ fooOut(s2);\r
+}
\ No newline at end of file
// For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run).
-#define GLSLANG_REVISION "Overload400-PrecQual.1456"
-#define GLSLANG_DATE "01-Sep-2016"
+#define GLSLANG_REVISION "Overload400-PrecQual.1460"
+#define GLSLANG_DATE "02-Sep-2016"
"spv.matrix2.frag",
"spv.memoryQualifier.frag",
"spv.merge-unreachable.frag",
+ "spv.multiStruct.comp",
+ "spv.multiStructFuncall.frag",
"spv.newTexture.frag",
"spv.noDeadDecorations.vert",
"spv.nonSquare.vert",