Merge pull request #991 from LoopDawg/resource-set-binding-fix
HLSL: Fix crash with --resource-set-binding [n] (global form, not per-register form)
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 2899a74..b65d6ed 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -2914,6 +2914,13 @@
// Make all the functions, skeletally, without actually visiting their bodies.
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
{
+ const auto getParamDecorations = [](std::vector<spv::Decoration>& decorations, const glslang::TType& type) {
+ spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
+ if (paramPrecision != spv::NoPrecision)
+ decorations.push_back(paramPrecision);
+ TranslateMemoryDecoration(type.getQualifier(), decorations);
+ };
+
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntryPoint(glslFunction))
@@ -2934,11 +2941,13 @@
// 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;
+ std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
- bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() == glslangIntermediate->implicitThisName;
+ bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
+ glslangIntermediate->implicitThisName;
+ paramDecorations.resize(parameters.size());
for (int p = 0; p < (int)parameters.size(); ++p) {
const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
spv::Id typeId = convertGlslangToSpvType(paramType);
@@ -2952,14 +2961,15 @@
typeId = builder.makePointer(spv::StorageClassFunction, typeId);
else
rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
- paramPrecisions.push_back(TranslatePrecisionDecoration(paramType));
+ getParamDecorations(paramDecorations[p], paramType);
paramTypes.push_back(typeId);
}
spv::Block* functionBlock;
spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
convertGlslangToSpvType(glslFunction->getType()),
- glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock);
+ glslFunction->getName().c_str(), paramTypes,
+ paramDecorations, &functionBlock);
if (implicitThis)
function->setImplicitThis();
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 11e9fe6..d472eb5 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -983,16 +983,16 @@
Block* entry;
std::vector<Id> params;
- std::vector<Decoration> precisions;
+ std::vector<std::vector<Decoration>> decorations;
- entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, precisions, &entry);
+ entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
return entryPointFunction;
}
// Comments in header
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
- const std::vector<Id>& paramTypes, const std::vector<Decoration>& precisions, Block **entry)
+ const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
{
// Make the function and initial instructions in it
Id typeId = makeFunctionType(returnType, paramTypes);
@@ -1001,8 +1001,10 @@
// Set up the precisions
setPrecision(function->getId(), precision);
- for (unsigned p = 0; p < (unsigned)precisions.size(); ++p)
- setPrecision(firstParamId + p, precisions[p]);
+ for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
+ for (int d = 0; d < (int)decorations[p].size(); ++d)
+ addDecoration(firstParamId + p, decorations[p][d]);
+ }
// CFG
if (entry) {
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 2b17ba6..3a94919 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -247,7 +247,7 @@
// Return the function, pass back the entry.
// The returned pointer is only valid for the lifetime of this builder.
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
- const std::vector<Decoration>& precisions, Block **entry = 0);
+ const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
// Create a return. An 'implicit' return is one not appearing in the source
// code. In the case of an implicit return, no post-return block is inserted.
diff --git a/Test/baseResults/hlsl.flattenOpaqueInit.vert.out b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out
new file mode 100755
index 0000000..774260f
--- /dev/null
+++ b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out
@@ -0,0 +1,132 @@
+hlsl.flattenOpaqueInit.vert
+Shader version: 500
+0:? Sequence
+0:5 Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:5 Function Parameters:
+0:? 'smpl' ( in sampler)
+0:? 'tex' ( in texture2D)
+0:? Sequence
+0:6 Branch: Return with expression
+0:6 texture ( temp 4-component vector of float)
+0:6 Construct combined texture-sampler ( temp sampler2D)
+0:? 'tex' ( in texture2D)
+0:? 'smpl' ( in sampler)
+0:? Constant:
+0:? 0.300000
+0:? 0.400000
+0:10 Function Definition: @main( ( temp 4-component vector of float)
+0:10 Function Parameters:
+0:? Sequence
+0:12 Branch: Return with expression
+0:12 Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:10 Function Definition: main( ( temp void)
+0:10 Function Parameters:
+0:? Sequence
+0:10 move second child to first child ( temp 4-component vector of float)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10 Function Call: @main( ( temp 4-component vector of float)
+0:? Linker Objects
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked vertex stage:
+
+
+Shader version: 500
+0:? Sequence
+0:5 Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:5 Function Parameters:
+0:? 'smpl' ( in sampler)
+0:? 'tex' ( in texture2D)
+0:? Sequence
+0:6 Branch: Return with expression
+0:6 texture ( temp 4-component vector of float)
+0:6 Construct combined texture-sampler ( temp sampler2D)
+0:? 'tex' ( in texture2D)
+0:? 'smpl' ( in sampler)
+0:? Constant:
+0:? 0.300000
+0:? 0.400000
+0:10 Function Definition: @main( ( temp 4-component vector of float)
+0:10 Function Parameters:
+0:? Sequence
+0:12 Branch: Return with expression
+0:12 Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:10 Function Definition: main( ( temp void)
+0:10 Function Parameters:
+0:? Sequence
+0:10 move second child to first child ( temp 4-component vector of float)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10 Function Call: @main( ( temp 4-component vector of float)
+0:? Linker Objects
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 40
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Vertex 4 "main" 38
+ Source HLSL 500
+ Name 4 "main"
+ Name 15 "lookUp(struct-FxaaTex-p1-t211;"
+ Name 13 "smpl"
+ Name 14 "tex"
+ Name 18 "@main("
+ Name 32 "g_tInputTexture_sampler"
+ Name 33 "g_tInputTexture"
+ Name 38 "@entryPointOutput"
+ Decorate 32(g_tInputTexture_sampler) DescriptorSet 0
+ Decorate 33(g_tInputTexture) DescriptorSet 0
+ Decorate 38(@entryPointOutput) Location 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeSampler
+ 7: TypePointer UniformConstant 6
+ 8: TypeFloat 32
+ 9: TypeImage 8(float) 2D sampled format:Unknown
+ 10: TypePointer UniformConstant 9
+ 11: TypeVector 8(float) 4
+ 12: TypeFunction 11(fvec4) 7(ptr) 10(ptr)
+ 17: TypeFunction 11(fvec4)
+ 22: TypeSampledImage 9
+ 24: TypeVector 8(float) 2
+ 25: 8(float) Constant 1050253722
+ 26: 8(float) Constant 1053609165
+ 27: 24(fvec2) ConstantComposite 25 26
+ 28: 8(float) Constant 0
+32(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant
+33(g_tInputTexture): 10(ptr) Variable UniformConstant
+ 37: TypePointer Output 11(fvec4)
+38(@entryPointOutput): 37(ptr) Variable Output
+ 4(main): 2 Function None 3
+ 5: Label
+ 39: 11(fvec4) FunctionCall 18(@main()
+ Store 38(@entryPointOutput) 39
+ Return
+ FunctionEnd
+15(lookUp(struct-FxaaTex-p1-t211;): 11(fvec4) Function None 12
+ 13(smpl): 7(ptr) FunctionParameter
+ 14(tex): 10(ptr) FunctionParameter
+ 16: Label
+ 20: 9 Load 14(tex)
+ 21: 6 Load 13(smpl)
+ 23: 22 SampledImage 20 21
+ 29: 11(fvec4) ImageSampleExplicitLod 23 27 Lod 28
+ ReturnValue 29
+ FunctionEnd
+ 18(@main(): 11(fvec4) Function None 17
+ 19: Label
+ 34: 11(fvec4) FunctionCall 15(lookUp(struct-FxaaTex-p1-t211;) 32(g_tInputTexture_sampler) 33(g_tInputTexture)
+ ReturnValue 34
+ FunctionEnd
diff --git a/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out
new file mode 100755
index 0000000..3deaddd
--- /dev/null
+++ b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out
@@ -0,0 +1,159 @@
+hlsl.flattenOpaqueInitMix.vert
+Shader version: 500
+0:? Sequence
+0:5 Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:5 Function Parameters:
+0:? 'smpl' ( in sampler)
+0:? 'tex' ( in texture2D)
+0:? 'f' ( in float)
+0:? Sequence
+0:6 Branch: Return with expression
+0:6 texture ( temp 4-component vector of float)
+0:6 Construct combined texture-sampler ( temp sampler2D)
+0:? 'tex' ( in texture2D)
+0:? 'smpl' ( in sampler)
+0:? Construct vec2 ( temp 2-component vector of float)
+0:? 'f' ( in float)
+0:? 'f' ( in float)
+0:10 Function Definition: @main( ( temp 4-component vector of float)
+0:10 Function Parameters:
+0:? Sequence
+0:11 Sequence
+0:? Sequence
+0:11 move second child to first child ( temp float)
+0:? 'f' ( temp float)
+0:11 Constant:
+0:11 0.500000
+0:12 Branch: Return with expression
+0:12 Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? 'f' ( temp float)
+0:10 Function Definition: main( ( temp void)
+0:10 Function Parameters:
+0:? Sequence
+0:10 move second child to first child ( temp 4-component vector of float)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10 Function Call: @main( ( temp 4-component vector of float)
+0:? Linker Objects
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked vertex stage:
+
+
+Shader version: 500
+0:? Sequence
+0:5 Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:5 Function Parameters:
+0:? 'smpl' ( in sampler)
+0:? 'tex' ( in texture2D)
+0:? 'f' ( in float)
+0:? Sequence
+0:6 Branch: Return with expression
+0:6 texture ( temp 4-component vector of float)
+0:6 Construct combined texture-sampler ( temp sampler2D)
+0:? 'tex' ( in texture2D)
+0:? 'smpl' ( in sampler)
+0:? Construct vec2 ( temp 2-component vector of float)
+0:? 'f' ( in float)
+0:? 'f' ( in float)
+0:10 Function Definition: @main( ( temp 4-component vector of float)
+0:10 Function Parameters:
+0:? Sequence
+0:11 Sequence
+0:? Sequence
+0:11 move second child to first child ( temp float)
+0:? 'f' ( temp float)
+0:11 Constant:
+0:11 0.500000
+0:12 Branch: Return with expression
+0:12 Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? 'f' ( temp float)
+0:10 Function Definition: main( ( temp void)
+0:10 Function Parameters:
+0:? Sequence
+0:10 move second child to first child ( temp 4-component vector of float)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10 Function Call: @main( ( temp 4-component vector of float)
+0:? Linker Objects
+0:? 'g_tInputTexture_sampler' ( uniform sampler)
+0:? 'g_tInputTexture' ( uniform texture2D)
+0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 46
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Vertex 4 "main" 44
+ Source HLSL 500
+ Name 4 "main"
+ Name 17 "lookUp(struct-FxaaTex-p1-t21-f11;"
+ Name 14 "smpl"
+ Name 15 "tex"
+ Name 16 "f"
+ Name 20 "@main("
+ Name 34 "f"
+ Name 36 "g_tInputTexture_sampler"
+ Name 37 "g_tInputTexture"
+ Name 38 "param"
+ Name 44 "@entryPointOutput"
+ Decorate 36(g_tInputTexture_sampler) DescriptorSet 0
+ Decorate 37(g_tInputTexture) DescriptorSet 0
+ Decorate 44(@entryPointOutput) Location 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeSampler
+ 7: TypePointer UniformConstant 6
+ 8: TypeFloat 32
+ 9: TypeImage 8(float) 2D sampled format:Unknown
+ 10: TypePointer UniformConstant 9
+ 11: TypePointer Function 8(float)
+ 12: TypeVector 8(float) 4
+ 13: TypeFunction 12(fvec4) 7(ptr) 10(ptr) 11(ptr)
+ 19: TypeFunction 12(fvec4)
+ 24: TypeSampledImage 9
+ 28: TypeVector 8(float) 2
+ 30: 8(float) Constant 0
+ 35: 8(float) Constant 1056964608
+36(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant
+37(g_tInputTexture): 10(ptr) Variable UniformConstant
+ 43: TypePointer Output 12(fvec4)
+44(@entryPointOutput): 43(ptr) Variable Output
+ 4(main): 2 Function None 3
+ 5: Label
+ 45: 12(fvec4) FunctionCall 20(@main()
+ Store 44(@entryPointOutput) 45
+ Return
+ FunctionEnd
+17(lookUp(struct-FxaaTex-p1-t21-f11;): 12(fvec4) Function None 13
+ 14(smpl): 7(ptr) FunctionParameter
+ 15(tex): 10(ptr) FunctionParameter
+ 16(f): 11(ptr) FunctionParameter
+ 18: Label
+ 22: 9 Load 15(tex)
+ 23: 6 Load 14(smpl)
+ 25: 24 SampledImage 22 23
+ 26: 8(float) Load 16(f)
+ 27: 8(float) Load 16(f)
+ 29: 28(fvec2) CompositeConstruct 26 27
+ 31: 12(fvec4) ImageSampleExplicitLod 25 29 Lod 30
+ ReturnValue 31
+ FunctionEnd
+ 20(@main(): 12(fvec4) Function None 19
+ 21: Label
+ 34(f): 11(ptr) Variable Function
+ 38(param): 11(ptr) Variable Function
+ Store 34(f) 35
+ 39: 8(float) Load 34(f)
+ Store 38(param) 39
+ 40: 12(fvec4) FunctionCall 17(lookUp(struct-FxaaTex-p1-t21-f11;) 36(g_tInputTexture_sampler) 37(g_tInputTexture) 38(param)
+ ReturnValue 40
+ FunctionEnd
diff --git a/Test/baseResults/hlsl.structbuffer.fn.frag.out b/Test/baseResults/hlsl.structbuffer.fn.frag.out
index 63aaa62..2e2a44f 100644
--- a/Test/baseResults/hlsl.structbuffer.fn.frag.out
+++ b/Test/baseResults/hlsl.structbuffer.fn.frag.out
@@ -184,6 +184,7 @@
MemberDecorate 9 0 NonWritable
MemberDecorate 9 0 Offset 0
Decorate 9 BufferBlock
+ Decorate 13(sb) NonWritable
Decorate 17 ArrayStride 16
MemberDecorate 18 0 Offset 0
Decorate 18 BufferBlock
diff --git a/Test/baseResults/hlsl.structbuffer.fn2.comp.out b/Test/baseResults/hlsl.structbuffer.fn2.comp.out
index 686a0a2..cb12ba5 100644
--- a/Test/baseResults/hlsl.structbuffer.fn2.comp.out
+++ b/Test/baseResults/hlsl.structbuffer.fn2.comp.out
@@ -166,6 +166,7 @@
MemberDecorate 9 0 NonWritable
MemberDecorate 9 0 Offset 0
Decorate 9 BufferBlock
+ Decorate 14(buffer) NonWritable
Decorate 44(g_input) DescriptorSet 0
Decorate 44(g_input) Binding 0
Decorate 50(g_output) DescriptorSet 0
diff --git a/Test/baseResults/spv.paramMemory.frag.out b/Test/baseResults/spv.paramMemory.frag.out
new file mode 100755
index 0000000..8b98b49
--- /dev/null
+++ b/Test/baseResults/spv.paramMemory.frag.out
@@ -0,0 +1,137 @@
+spv.paramMemory.frag
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 69
+
+ Capability Shader
+ Capability StorageImageReadWithoutFormat
+ Capability StorageImageWriteWithoutFormat
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Fragment 4 "main" 27 66
+ ExecutionMode 4 OriginUpperLeft
+ Source ESSL 310
+ Name 4 "main"
+ Name 16 "image_load(I21;vi2;"
+ Name 14 "image"
+ Name 15 "coords"
+ Name 23 "image_store(I21;vi2;vf4;"
+ Name 20 "image"
+ Name 21 "coords"
+ Name 22 "data"
+ Name 27 "in_coords"
+ Name 35 "read1"
+ Name 38 "image1"
+ Name 39 "param"
+ Name 42 "read2"
+ Name 45 "image2"
+ Name 46 "param"
+ Name 49 "image3"
+ Name 53 "param"
+ Name 55 "param"
+ Name 57 "image4"
+ Name 61 "param"
+ Name 63 "param"
+ Name 66 "out_color"
+ Decorate 14(image) Coherent
+ Decorate 14(image) NonWritable
+ Decorate 20(image) Coherent
+ Decorate 20(image) NonReadable
+ Decorate 27(in_coords) Flat
+ Decorate 27(in_coords) Location 0
+ Decorate 38(image1) DescriptorSet 0
+ Decorate 38(image1) Binding 0
+ Decorate 38(image1) Coherent
+ Decorate 38(image1) NonWritable
+ Decorate 45(image2) DescriptorSet 0
+ Decorate 45(image2) Binding 2
+ Decorate 45(image2) NonWritable
+ Decorate 49(image3) DescriptorSet 0
+ Decorate 49(image3) Binding 1
+ Decorate 49(image3) Coherent
+ Decorate 49(image3) NonReadable
+ Decorate 57(image4) DescriptorSet 0
+ Decorate 57(image4) Binding 3
+ Decorate 57(image4) NonReadable
+ Decorate 66(out_color) Location 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeImage 6(float) 2D nonsampled format:Unknown
+ 8: TypePointer UniformConstant 7
+ 9: TypeInt 32 1
+ 10: TypeVector 9(int) 2
+ 11: TypePointer Function 10(ivec2)
+ 12: TypeVector 6(float) 4
+ 13: TypeFunction 12(fvec4) 8(ptr) 11(ptr)
+ 18: TypePointer Function 12(fvec4)
+ 19: TypeFunction 2 8(ptr) 11(ptr) 18(ptr)
+ 26: TypePointer Input 10(ivec2)
+ 27(in_coords): 26(ptr) Variable Input
+ 36: TypeImage 6(float) 2D nonsampled format:Rgba32f
+ 37: TypePointer UniformConstant 36
+ 38(image1): 37(ptr) Variable UniformConstant
+ 43: TypeImage 6(float) 2D nonsampled format:Rgba16f
+ 44: TypePointer UniformConstant 43
+ 45(image2): 44(ptr) Variable UniformConstant
+ 49(image3): 37(ptr) Variable UniformConstant
+ 51: 6(float) Constant 1056964608
+ 57(image4): 44(ptr) Variable UniformConstant
+ 59: 6(float) Constant 1073741824
+ 65: TypePointer Output 12(fvec4)
+ 66(out_color): 65(ptr) Variable Output
+ 67: 6(float) Constant 0
+ 68: 12(fvec4) ConstantComposite 67 67 67 67
+ 4(main): 2 Function None 3
+ 5: Label
+ 35(read1): 18(ptr) Variable Function
+ 39(param): 11(ptr) Variable Function
+ 42(read2): 18(ptr) Variable Function
+ 46(param): 11(ptr) Variable Function
+ 53(param): 11(ptr) Variable Function
+ 55(param): 18(ptr) Variable Function
+ 61(param): 11(ptr) Variable Function
+ 63(param): 18(ptr) Variable Function
+ 40: 10(ivec2) Load 27(in_coords)
+ Store 39(param) 40
+ 41: 12(fvec4) FunctionCall 16(image_load(I21;vi2;) 38(image1) 39(param)
+ Store 35(read1) 41
+ 47: 10(ivec2) Load 27(in_coords)
+ Store 46(param) 47
+ 48: 12(fvec4) FunctionCall 16(image_load(I21;vi2;) 45(image2) 46(param)
+ Store 42(read2) 48
+ 50: 12(fvec4) Load 35(read1)
+ 52: 12(fvec4) VectorTimesScalar 50 51
+ 54: 10(ivec2) Load 27(in_coords)
+ Store 53(param) 54
+ Store 55(param) 52
+ 56: 2 FunctionCall 23(image_store(I21;vi2;vf4;) 49(image3) 53(param) 55(param)
+ 58: 12(fvec4) Load 42(read2)
+ 60: 12(fvec4) VectorTimesScalar 58 59
+ 62: 10(ivec2) Load 27(in_coords)
+ Store 61(param) 62
+ Store 63(param) 60
+ 64: 2 FunctionCall 23(image_store(I21;vi2;vf4;) 57(image4) 61(param) 63(param)
+ Store 66(out_color) 68
+ Return
+ FunctionEnd
+16(image_load(I21;vi2;): 12(fvec4) Function None 13
+ 14(image): 8(ptr) FunctionParameter
+ 15(coords): 11(ptr) FunctionParameter
+ 17: Label
+ 25: 7 Load 14(image)
+ 28: 10(ivec2) Load 27(in_coords)
+ 29: 12(fvec4) ImageRead 25 28
+ ReturnValue 29
+ FunctionEnd
+23(image_store(I21;vi2;vf4;): 2 Function None 19
+ 20(image): 8(ptr) FunctionParameter
+ 21(coords): 11(ptr) FunctionParameter
+ 22(data): 18(ptr) FunctionParameter
+ 24: Label
+ 32: 7 Load 20(image)
+ 33: 10(ivec2) Load 27(in_coords)
+ 34: 12(fvec4) Load 22(data)
+ ImageWrite 32 33 34
+ Return
+ FunctionEnd
diff --git a/Test/hlsl.flattenOpaqueInit.vert b/Test/hlsl.flattenOpaqueInit.vert
new file mode 100644
index 0000000..5efb02e
--- /dev/null
+++ b/Test/hlsl.flattenOpaqueInit.vert
@@ -0,0 +1,13 @@
+struct FxaaTex { SamplerState smpl; Texture2D tex; };
+SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture;
+
+float4 lookUp(FxaaTex tex)
+{
+ return tex.tex.Sample(tex.smpl, float2(0.3, 0.4));
+}
+
+float4 main() : SV_TARGET0
+{
+ FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture };
+ return lookUp(tex);
+}
\ No newline at end of file
diff --git a/Test/hlsl.flattenOpaqueInitMix.vert b/Test/hlsl.flattenOpaqueInitMix.vert
new file mode 100644
index 0000000..2e712ee
--- /dev/null
+++ b/Test/hlsl.flattenOpaqueInitMix.vert
@@ -0,0 +1,13 @@
+struct FxaaTex { SamplerState smpl; Texture2D tex; float f; };
+SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture;
+
+float4 lookUp(FxaaTex tex)
+{
+ return tex.tex.Sample(tex.smpl, float2(tex.f, tex.f));
+}
+
+float4 main() : SV_TARGET0
+{
+ FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture, 0.5 };
+ return lookUp(tex);
+}
\ No newline at end of file
diff --git a/Test/spv.paramMemory.frag b/Test/spv.paramMemory.frag
new file mode 100644
index 0000000..79d2fe5
--- /dev/null
+++ b/Test/spv.paramMemory.frag
@@ -0,0 +1,30 @@
+#version 310 es
+
+readonly coherent uniform layout(set = 0, binding = 0, rgba32f) highp image2D image1;
+readonly uniform layout(set = 0, binding = 2, rgba16f) highp image2D image2;
+writeonly coherent uniform layout(set = 0, binding = 1, rgba32f) highp image2D image3;
+writeonly uniform layout(set = 0, binding = 3, rgba16f) highp image2D image4;
+
+flat in layout(location = 0) highp ivec2 in_coords;
+out layout(location = 0) highp vec4 out_color;
+
+highp vec4 image_load(readonly coherent highp image2D image, highp ivec2 coords)
+{
+ return imageLoad(image, in_coords);
+}
+
+void image_store(writeonly coherent highp image2D image, highp ivec2 coords, highp vec4 data)
+{
+ imageStore(image, in_coords, data);
+}
+
+void main()
+{
+ highp vec4 read1 = image_load(image1, in_coords);
+ highp vec4 read2 = image_load(image2, in_coords);
+
+ image_store(image3, in_coords, read1*0.5);
+ image_store(image4, in_coords, read2*2.0);
+
+ out_color = vec4(0.0);
+}
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 46ddee8..1d56c1f 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1386,7 +1386,6 @@
unaryArg = callNode.getAsUnaryNode()->getOperand();
arg0 = unaryArg;
}
- const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr
switch (callNode.getOp()) {
case EOpTextureGather:
@@ -1417,7 +1416,7 @@
profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
else
profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
- if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+ if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
if (! fnCandidate[0].type->getSampler().shadow)
compArg = 3;
@@ -1427,7 +1426,7 @@
if (! fnCandidate[0].type->getSampler().shadow)
compArg = 3;
// check for constant offsets
- if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+ if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
error(loc, "must be a compile-time constant:", feature, "offsets argument");
break;
default:
@@ -1435,8 +1434,8 @@
}
if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
- if (aggArgs[compArg]->getAsConstantUnion()) {
- int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
+ if ((*argp)[compArg]->getAsConstantUnion()) {
+ int value = (*argp)[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
if (value < 0 || value > 3)
error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
} else
@@ -1518,12 +1517,12 @@
}
if (arg > 0) {
- if (! aggArgs[arg]->getAsConstantUnion())
+ if (! (*argp)[arg]->getAsConstantUnion())
error(loc, "argument must be compile-time constant", "texel offset", "");
else {
- const TType& type = aggArgs[arg]->getAsTyped()->getType();
+ const TType& type = (*argp)[arg]->getAsTyped()->getType();
for (int c = 0; c < type.getVectorSize(); ++c) {
- int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
+ int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
}
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index 26f81bd..93f1568 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1836,6 +1836,7 @@
const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); }
int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; }
int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); }
+int TProgram::getUniformBinding(int index) const { return reflection->getUniform(index).getBinding(); }
int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; }
int TProgram::getUniformBlockCounterIndex(int index) const { return reflection->getUniformBlock(index).counterIndex; }
int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; }
diff --git a/glslang/MachineIndependent/reflection.h b/glslang/MachineIndependent/reflection.h
index 7a1cc8e..fedfbe8 100644
--- a/glslang/MachineIndependent/reflection.h
+++ b/glslang/MachineIndependent/reflection.h
@@ -59,7 +59,15 @@
name(pName), offset(pOffset),
glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), type(pType.clone()) { }
- void dump() const {
+ const TType* const getType() const { return type; }
+ int getBinding() const
+ {
+ if (type == nullptr || !type->getQualifier().hasBinding())
+ return -1;
+ return type->getQualifier().layoutBinding;
+ }
+ void dump() const
+ {
printf("%s: offset %d, type %x, size %d, index %d, binding %d",
name.c_str(), offset, glDefineType, size, index, getBinding() );
@@ -68,8 +76,7 @@
printf("\n");
}
-
- const TType* const getType() const { return type; }
+ static TObjectReflection badReflection() { return TObjectReflection(); }
TString name;
int offset;
@@ -78,15 +85,7 @@
int index;
int counterIndex;
- static TObjectReflection badReflection() { return TObjectReflection(); }
-
protected:
- int getBinding() const {
- if (type == nullptr || type->getQualifier().layoutBinding == TQualifier::layoutBindingEnd)
- return -1;
- return type->getQualifier().layoutBinding;
- }
-
TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
const TType* type;
diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h
index 2a02478..12672ee 100644
--- a/glslang/Public/ShaderLang.h
+++ b/glslang/Public/ShaderLang.h
@@ -619,6 +619,7 @@
const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int blockIndex) const; // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name) const; // can be used for glGetUniformIndices()
+ int getUniformBinding(int index) const; // returns the binding number
int getUniformBlockIndex(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformBlockCounterIndex(int index) const; // returns block index of associated counter.
int getUniformType(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index ea90b62..21f606e 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -122,6 +122,8 @@
{"hlsl.float4.frag", "PixelShaderFunction"},
{"hlsl.flatten.return.frag", "main"},
{"hlsl.flattenOpaque.frag", "main"},
+ {"hlsl.flattenOpaqueInit.vert", "main"},
+ {"hlsl.flattenOpaqueInitMix.vert", "main"},
{"hlsl.forLoop.frag", "PixelShaderFunction"},
{"hlsl.gather.array.dx10.frag", "main"},
{"hlsl.gather.basic.dx10.frag", "main"},
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 268aa0b..dfad30c 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -275,6 +275,7 @@
"spv.noWorkgroup.comp",
"spv.offsets.frag",
"spv.Operations.frag",
+ "spv.paramMemory.frag",
"spv.precision.frag",
"spv.prepost.frag",
"spv.qualifiers.vert",
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 0c64c71..dc44c36 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -506,12 +506,14 @@
}
// Deal with sampler aliasing: turning assignments into aliases
+// Return a placeholder node for higher-level code that think assignments must
+// generate code.
TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node)
{
// Can only alias an assignment: "s1 = s2"
TIntermBinary* binary = node->getAsBinaryNode();
if (binary == nullptr || node->getAsOperator()->getOp() != EOpAssign ||
- binary->getLeft() ->getAsSymbolNode() == nullptr ||
+ binary->getLeft()->getAsSymbolNode() == nullptr ||
binary->getRight()->getAsSymbolNode() == nullptr) {
error(loc, "can't modify sampler", op, "");
return node;
@@ -520,11 +522,25 @@
if (controlFlowNestingLevel > 0)
warn(loc, "sampler or image aliased under control flow; consumption must be in same path", op, "");
+ TIntermTyped* set = setOpaqueLvalue(binary->getLeft(), binary->getRight());
+ if (set == nullptr)
+ warn(loc, "could not create alias for sampler", op, "");
+ else
+ node = set;
+
+ return node;
+}
+
+// Do an opaque assignment that needs to turn into an alias.
+// Return nullptr if it can't be done, otherwise return a placeholder
+// node for higher-level code that think assignments must generate code.
+TIntermTyped* HlslParseContext::setOpaqueLvalue(TIntermTyped* leftTyped, TIntermTyped* rightTyped)
+{
// Best is if we are aliasing a flattened struct member "S.s1 = s2",
// in which case we want to update the flattening information with the alias,
// making everything else work seamlessly.
- TIntermSymbol* left = binary->getLeft()->getAsSymbolNode();
- TIntermSymbol* right = binary->getRight()->getAsSymbolNode();
+ TIntermSymbol* left = leftTyped->getAsSymbolNode();
+ TIntermSymbol* right = rightTyped->getAsSymbolNode();
for (auto fit = flattenMap.begin(); fit != flattenMap.end(); ++fit) {
for (auto mit = fit->second.members.begin(); mit != fit->second.members.end(); ++mit) {
if ((*mit)->getUniqueId() == left->getId()) {
@@ -533,15 +549,12 @@
(*mit)->setUniqueId(right->getId());
// replace node (rest of compiler expects either an error or code to generate)
// with pointless access
- node = binary->getRight();
- return node;
+ return right;
}
}
}
- warn(loc, "could not create alias for sampler", op, "");
-
- return node;
+ return nullptr;
}
void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
@@ -2412,6 +2425,34 @@
return assignList;
}
+// For a declaration with an initializer, where the initialized symbol is flattened,
+// and possibly contains opaque values, such that the initializer should never exist
+// as emitted code, because even creating the initializer would write opaques.
+//
+// Decompose this into individual member-wise assignments, which themselves are
+// expected to then not exist for opaque types, because they will turn into aliases.
+//
+// Return a node that contains the non-aliased assignments that must continue to exist.
+TIntermAggregate* HlslParseContext::flattenedInit(const TSourceLoc& loc, TIntermSymbol* symbol, const TIntermAggregate& initializer)
+{
+ TIntermAggregate* initList = nullptr;
+ // synthesize an access to each member, and then an assignment to it
+ const TTypeList& typeList = *symbol->getType().getStruct();
+ for (int member = 0; member < (int)typeList.size(); ++member) {
+ TIntermTyped* memberInitializer = initializer.getSequence()[member]->getAsTyped();
+ TIntermTyped* flattenedMember = flattenAccess(symbol, member);
+ if (flattenedMember->getType().containsOpaque())
+ setOpaqueLvalue(flattenedMember, memberInitializer);
+ else
+ initList = intermediate.growAggregate(initList, handleAssign(loc, EOpAssign, flattenedMember,
+ memberInitializer));
+ }
+
+ if (initList)
+ initList->setOperator(EOpSequence);
+ return initList;
+}
+
// Some simple source assignments need to be flattened to a sequence
// of AST assignments. Catch these and flatten, otherwise, pass through
// to intermediate.addAssign().
@@ -2449,7 +2490,7 @@
// A temporary to store the right node's value, so we don't keep indirecting into it
// if it's not a simple symbol.
- TVariable* rhsTempVar = nullptr;
+ TVariable* rhsTempVar = nullptr;
// If the RHS is a simple symbol node, we'll copy it for each member.
TIntermSymbol* cloneSymNode = nullptr;
@@ -7228,27 +7269,22 @@
error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
}
- if (flattenVar)
- flatten(loc, *symbol->getAsVariable());
-
if (symbol == nullptr)
return nullptr;
+ if (flattenVar)
+ flatten(loc, *symbol->getAsVariable());
+
+ if (initializer == nullptr)
+ return nullptr;
+
// Deal with initializer
- TIntermNode* initNode = nullptr;
- if (symbol && initializer) {
- if (flattenVar)
- error(loc, "flattened array with initializer list unsupported", identifier.c_str(), "");
-
- TVariable* variable = symbol->getAsVariable();
- if (variable == nullptr) {
- error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
- return nullptr;
- }
- initNode = executeInitializer(loc, initializer, variable);
+ TVariable* variable = symbol->getAsVariable();
+ if (variable == nullptr) {
+ error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
+ return nullptr;
}
-
- return initNode;
+ return executeInitializer(loc, initializer, variable, flattenVar);
}
// Pick up global defaults from the provide global defaults into dst.
@@ -7314,7 +7350,7 @@
// Returning nullptr just means there is no code to execute to handle the
// initializer, which will, for example, be the case for constant initializers.
//
-TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
+TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable, bool flattened)
{
//
// Identifier must be of type constant, a global, or a temporary, and
@@ -7335,6 +7371,7 @@
TType skeletalType;
skeletalType.shallowCopy(variable->getType());
skeletalType.getQualifier().makeTemporary();
+ TIntermAggregate* initializerList = nullptr;
if (initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull)
initializer = convertInitializerList(loc, skeletalType, initializer, nullptr);
if (initializer == nullptr) {
@@ -7394,11 +7431,20 @@
// normal assigning of a value to a variable...
specializationCheck(loc, initializer->getType(), "initializer");
TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
- TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
- if (initNode == nullptr)
- assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
- return initNode;
+ // If we are flattening, it could be due to setting opaques, which must be handled
+ // as aliases, and the 'initializer' node cannot actually be emitted, because it
+ // itself stores the result of the constructor, and we can't store to opaques.
+ // handleAssign() will emit the initializer.
+ TIntermNode* initNode = nullptr;
+ if (flattened && intermSymbol->getType().containsOpaque())
+ return flattenedInit(loc, intermSymbol, *initializer->getAsAggregate());
+ else {
+ initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
+ if (initNode == nullptr)
+ assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return initNode;
+ }
}
return nullptr;
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 713e830..2d507c3 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -87,6 +87,7 @@
void remapNonEntryPointIO(TFunction& function);
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
+ TIntermAggregate* flattenedInit(const TSourceLoc&, TIntermSymbol*, const TIntermAggregate&);
TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*);
@@ -191,6 +192,7 @@
// Apply L-value conversions. E.g, turning a write to a RWTexture into an ImageStore.
TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
TIntermTyped* handleSamplerLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
+ TIntermTyped* setOpaqueLvalue(TIntermTyped* left, TIntermTyped* right);
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
@@ -231,7 +233,7 @@
TIntermSymbol* makeInternalVariableNode(const TSourceLoc&, const char* name, const TType&) const;
TVariable* declareNonArray(const TSourceLoc&, const TString& identifier, const TType&, bool track);
void declareArray(const TSourceLoc&, const TString& identifier, const TType&, TSymbol*&, bool track);
- TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
+ TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable, bool flattened);
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer, TIntermTyped* scalarInit);
bool isScalarConstructor(const TIntermNode*);
TOperator mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage);