diff --git a/Test/baseResults/hlsl.structarray.flatten.frag.out b/Test/baseResults/hlsl.structarray.flatten.frag.out new file mode 100644 index 00000000..6b22d663 --- /dev/null +++ b/Test/baseResults/hlsl.structarray.flatten.frag.out @@ -0,0 +1,197 @@ +hlsl.structarray.flatten.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:23 Function Definition: main(struct-PS_OUTPUT-vf41; (temp void) +0:23 Function Parameters: +0:23 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:24 move second child to first child (temp 4-component vector of float) +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:26 add (temp 4-component vector of float) +0:25 add (temp 4-component vector of float) +0:25 texture (temp 4-component vector of float) +0:25 Construct combined texture-sampler (temp sampler1D) +0:? 'tex' (uniform texture1D) +0:? 'samp' (uniform sampler) +0:25 Constant: +0:25 0.500000 +0:26 texture (temp 4-component vector of float) +0:26 Construct combined texture-sampler (temp sampler1D) +0:? 'g_texdata_array[1].tex' (uniform texture1D) +0:? 'g_texdata_array[1].samp' (uniform sampler) +0:26 Constant: +0:26 0.400000 +0:27 texture (temp 4-component vector of float) +0:27 Construct combined texture-sampler (temp sampler1D) +0:? 'g_texdata_array2[1].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[1].samp[0]' (uniform sampler) +0:27 Constant: +0:27 0.300000 +0:? Linker Objects +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:? 'g_samp' (uniform sampler) +0:? 'g_tex' (uniform texture1D) +0:? 'g_texdata_array2[0].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[0].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[0].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[0].tex[1]' (uniform texture1D) +0:? 'g_texdata_array2[1].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[1].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[1].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[1].tex[1]' (uniform texture1D) +0:? 'g_texdata_array2[2].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[2].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[2].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[2].tex[1]' (uniform texture1D) + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:23 Function Definition: main(struct-PS_OUTPUT-vf41; (temp void) +0:23 Function Parameters: +0:23 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:24 move second child to first child (temp 4-component vector of float) +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:26 add (temp 4-component vector of float) +0:25 add (temp 4-component vector of float) +0:25 texture (temp 4-component vector of float) +0:25 Construct combined texture-sampler (temp sampler1D) +0:? 'tex' (uniform texture1D) +0:? 'samp' (uniform sampler) +0:25 Constant: +0:25 0.500000 +0:26 texture (temp 4-component vector of float) +0:26 Construct combined texture-sampler (temp sampler1D) +0:? 'g_texdata_array[1].tex' (uniform texture1D) +0:? 'g_texdata_array[1].samp' (uniform sampler) +0:26 Constant: +0:26 0.400000 +0:27 texture (temp 4-component vector of float) +0:27 Construct combined texture-sampler (temp sampler1D) +0:? 'g_texdata_array2[1].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[1].samp[0]' (uniform sampler) +0:27 Constant: +0:27 0.300000 +0:? Linker Objects +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:? 'g_samp' (uniform sampler) +0:? 'g_tex' (uniform texture1D) +0:? 'g_texdata_array2[0].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[0].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[0].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[0].tex[1]' (uniform texture1D) +0:? 'g_texdata_array2[1].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[1].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[1].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[1].tex[1]' (uniform texture1D) +0:? 'g_texdata_array2[2].samp[0]' (uniform sampler) +0:? 'g_texdata_array2[2].samp[1]' (uniform sampler) +0:? 'g_texdata_array2[2].tex[0]' (uniform texture1D) +0:? 'g_texdata_array2[2].tex[1]' (uniform texture1D) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 50 + + Capability Shader + Capability Sampled1D + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 9 + ExecutionMode 4 OriginUpperLeft + Name 4 "main" + Name 9 "color" + Name 12 "tex" + Name 16 "samp" + Name 22 "g_texdata_array[1].tex" + Name 24 "g_texdata_array[1].samp" + Name 30 "g_texdata_array2[1].tex[0]" + Name 32 "g_texdata_array2[1].samp[0]" + Name 38 "g_samp" + Name 39 "g_tex" + Name 40 "g_texdata_array2[0].samp[0]" + Name 41 "g_texdata_array2[0].samp[1]" + Name 42 "g_texdata_array2[0].tex[0]" + Name 43 "g_texdata_array2[0].tex[1]" + Name 44 "g_texdata_array2[1].samp[1]" + Name 45 "g_texdata_array2[1].tex[1]" + Name 46 "g_texdata_array2[2].samp[0]" + Name 47 "g_texdata_array2[2].samp[1]" + Name 48 "g_texdata_array2[2].tex[0]" + Name 49 "g_texdata_array2[2].tex[1]" + Decorate 9(color) Location 0 + Decorate 12(tex) DescriptorSet 0 + Decorate 16(samp) DescriptorSet 0 + Decorate 22(g_texdata_array[1].tex) DescriptorSet 0 + Decorate 24(g_texdata_array[1].samp) DescriptorSet 0 + Decorate 30(g_texdata_array2[1].tex[0]) DescriptorSet 0 + Decorate 32(g_texdata_array2[1].samp[0]) DescriptorSet 0 + Decorate 38(g_samp) DescriptorSet 0 + Decorate 39(g_tex) DescriptorSet 0 + Decorate 40(g_texdata_array2[0].samp[0]) DescriptorSet 0 + Decorate 41(g_texdata_array2[0].samp[1]) DescriptorSet 0 + Decorate 42(g_texdata_array2[0].tex[0]) DescriptorSet 0 + Decorate 43(g_texdata_array2[0].tex[1]) DescriptorSet 0 + Decorate 44(g_texdata_array2[1].samp[1]) DescriptorSet 0 + Decorate 45(g_texdata_array2[1].tex[1]) DescriptorSet 0 + Decorate 46(g_texdata_array2[2].samp[0]) DescriptorSet 0 + Decorate 47(g_texdata_array2[2].samp[1]) DescriptorSet 0 + Decorate 48(g_texdata_array2[2].tex[0]) DescriptorSet 0 + Decorate 49(g_texdata_array2[2].tex[1]) DescriptorSet 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypePointer Output 7(fvec4) + 9(color): 8(ptr) Variable Output + 10: TypeImage 6(float) 1D sampled format:Unknown + 11: TypePointer UniformConstant 10 + 12(tex): 11(ptr) Variable UniformConstant + 14: TypeSampler + 15: TypePointer UniformConstant 14 + 16(samp): 15(ptr) Variable UniformConstant + 18: TypeSampledImage 10 + 20: 6(float) Constant 1056964608 +22(g_texdata_array[1].tex): 11(ptr) Variable UniformConstant +24(g_texdata_array[1].samp): 15(ptr) Variable UniformConstant + 27: 6(float) Constant 1053609165 +30(g_texdata_array2[1].tex[0]): 11(ptr) Variable UniformConstant +32(g_texdata_array2[1].samp[0]): 15(ptr) Variable UniformConstant + 35: 6(float) Constant 1050253722 + 38(g_samp): 15(ptr) Variable UniformConstant + 39(g_tex): 11(ptr) Variable UniformConstant +40(g_texdata_array2[0].samp[0]): 15(ptr) Variable UniformConstant +41(g_texdata_array2[0].samp[1]): 15(ptr) Variable UniformConstant +42(g_texdata_array2[0].tex[0]): 11(ptr) Variable UniformConstant +43(g_texdata_array2[0].tex[1]): 11(ptr) Variable UniformConstant +44(g_texdata_array2[1].samp[1]): 15(ptr) Variable UniformConstant +45(g_texdata_array2[1].tex[1]): 11(ptr) Variable UniformConstant +46(g_texdata_array2[2].samp[0]): 15(ptr) Variable UniformConstant +47(g_texdata_array2[2].samp[1]): 15(ptr) Variable UniformConstant +48(g_texdata_array2[2].tex[0]): 11(ptr) Variable UniformConstant +49(g_texdata_array2[2].tex[1]): 11(ptr) Variable UniformConstant + 4(main): 2 Function None 3 + 5: Label + 13: 10 Load 12(tex) + 17: 14 Load 16(samp) + 19: 18 SampledImage 13 17 + 21: 7(fvec4) ImageSampleImplicitLod 19 20 + 23: 10 Load 22(g_texdata_array[1].tex) + 25: 14 Load 24(g_texdata_array[1].samp) + 26: 18 SampledImage 23 25 + 28: 7(fvec4) ImageSampleImplicitLod 26 27 + 29: 7(fvec4) FAdd 21 28 + 31: 10 Load 30(g_texdata_array2[1].tex[0]) + 33: 14 Load 32(g_texdata_array2[1].samp[0]) + 34: 18 SampledImage 31 33 + 36: 7(fvec4) ImageSampleImplicitLod 34 35 + 37: 7(fvec4) FAdd 29 36 + Store 9(color) 37 + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.structarray.flatten.geom.out b/Test/baseResults/hlsl.structarray.flatten.geom.out new file mode 100644 index 00000000..0994af84 --- /dev/null +++ b/Test/baseResults/hlsl.structarray.flatten.geom.out @@ -0,0 +1,100 @@ +hlsl.structarray.flatten.geom +ERROR: 0:10: 'vin' : recursive type not yet supported in GS input +ERROR: 1 compilation errors. No code generated. + + +Shader version: 450 +invocations = -1 +max_vertices = 4 +input primitive = lines +output primitive = triangle_strip +ERROR: node is still EOpNull! +0:10 Function Definition: main(struct-VertexData-vf4-vf4-vf21[2];struct-VertexData-vf4-vf4-vf21; (temp void) +0:10 Function Parameters: +0:10 'vin' (in 2-element array of structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:10 'outStream' (out structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:? Sequence +0:13 move second child to first child (temp 4-component vector of float) +0:13 color: direct index for structure (temp 4-component vector of float) +0:13 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:13 Constant: +0:13 1 (const int) +0:? 'vin[0].color' (layout(location=1 ) in 4-component vector of float) +0:14 move second child to first child (temp 2-component vector of float) +0:14 uv: direct index for structure (temp 2-component vector of float) +0:14 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:14 Constant: +0:14 2 (const int) +0:? 'vin[0].uv' (layout(location=2 ) in 2-component vector of float) +0:15 move second child to first child (temp 4-component vector of float) +0:15 position: direct index for structure (temp 4-component vector of float) +0:15 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:15 Constant: +0:15 0 (const int) +0:? 'vin[0].position' (layout(location=0 ) in 4-component vector of float) +0:16 Sequence +0:16 move second child to first child (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 'outStream' (out structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 EmitVertex (temp void) +0:? Linker Objects +0:? 'vin[0].position' (layout(location=0 ) in 4-component vector of float) +0:? 'vin[0].color' (layout(location=1 ) in 4-component vector of float) +0:? 'vin[0].uv' (layout(location=2 ) in 2-component vector of float) +0:? 'vin[1].position' (layout(location=3 ) in 4-component vector of float) +0:? 'vin[1].color' (layout(location=4 ) in 4-component vector of float) +0:? 'vin[1].uv' (layout(location=5 ) in 2-component vector of float) +0:? 'position' (layout(location=0 ) out 4-component vector of float) +0:? 'color' (layout(location=1 ) out 4-component vector of float) +0:? 'uv' (layout(location=2 ) out 2-component vector of float) + + +Linked geometry stage: + + +Shader version: 450 +invocations = 1 +max_vertices = 4 +input primitive = lines +output primitive = triangle_strip +ERROR: node is still EOpNull! +0:10 Function Definition: main(struct-VertexData-vf4-vf4-vf21[2];struct-VertexData-vf4-vf4-vf21; (temp void) +0:10 Function Parameters: +0:10 'vin' (in 2-element array of structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:10 'outStream' (out structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:? Sequence +0:13 move second child to first child (temp 4-component vector of float) +0:13 color: direct index for structure (temp 4-component vector of float) +0:13 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:13 Constant: +0:13 1 (const int) +0:? 'vin[0].color' (layout(location=1 ) in 4-component vector of float) +0:14 move second child to first child (temp 2-component vector of float) +0:14 uv: direct index for structure (temp 2-component vector of float) +0:14 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:14 Constant: +0:14 2 (const int) +0:? 'vin[0].uv' (layout(location=2 ) in 2-component vector of float) +0:15 move second child to first child (temp 4-component vector of float) +0:15 position: direct index for structure (temp 4-component vector of float) +0:15 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:15 Constant: +0:15 0 (const int) +0:? 'vin[0].position' (layout(location=0 ) in 4-component vector of float) +0:16 Sequence +0:16 move second child to first child (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 'outStream' (out structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) +0:16 EmitVertex (temp void) +0:? Linker Objects +0:? 'vin[0].position' (layout(location=0 ) in 4-component vector of float) +0:? 'vin[0].color' (layout(location=1 ) in 4-component vector of float) +0:? 'vin[0].uv' (layout(location=2 ) in 2-component vector of float) +0:? 'vin[1].position' (layout(location=3 ) in 4-component vector of float) +0:? 'vin[1].color' (layout(location=4 ) in 4-component vector of float) +0:? 'vin[1].uv' (layout(location=5 ) in 2-component vector of float) +0:? 'position' (layout(location=0 ) out 4-component vector of float) +0:? 'color' (layout(location=1 ) out 4-component vector of float) +0:? 'uv' (layout(location=2 ) out 2-component vector of float) + +SPIR-V is not generated for failed compile or link diff --git a/Test/baseResults/hlsl.structin.vert.out b/Test/baseResults/hlsl.structin.vert.out index f3e56b6a..a5feea8a 100755 --- a/Test/baseResults/hlsl.structin.vert.out +++ b/Test/baseResults/hlsl.structin.vert.out @@ -16,14 +16,8 @@ Shader version: 450 0:11 add (temp 4-component vector of float) 0:11 add (temp 4-component vector of float) 0:11 add (temp 4-component vector of float) -0:11 direct index (layout(location=1 ) temp 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) -0:11 Constant: -0:11 1 (const int) -0:11 direct index (layout(location=1 ) temp 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) -0:11 Constant: -0:11 0 (const int) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) 0:11 Construct vec4 (temp 4-component vector of float) 0:11 Convert uint to float (temp float) 0:11 direct index (temp uint) @@ -34,12 +28,24 @@ Shader version: 450 0:11 'e' (layout(location=5 ) in 4-component vector of float) 0:13 Sequence 0:13 Sequence -0:13 move second child to first child (temp 2-element array of 4-component vector of float) -0:? 'm' (layout(location=0 ) out 2-element array of 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 move second child to first child (temp 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:13 direct index (temp 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 Constant: +0:13 0 (const int) 0:13 Constant: 0:13 0 (const int) +0:13 move second child to first child (temp 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) +0:13 direct index (temp 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 Constant: +0:13 0 (const int) +0:13 Constant: +0:13 1 (const int) 0:13 move second child to first child (temp 2-component vector of uint) 0:? 'coord' (layout(location=2 ) out 2-component vector of uint) 0:13 coord: direct index for structure (temp 2-component vector of uint) @@ -54,14 +60,20 @@ Shader version: 450 0:13 2 (const int) 0:13 Branch: Return 0:? Linker Objects -0:? 'm' (layout(location=0 ) out 2-element array of 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) 0:? 'coord' (layout(location=2 ) out 2-component vector of uint) 0:? 'b' (layout(location=3 ) smooth out 4-component vector of float) 0:? 'd' (layout(location=0 ) in 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) 0:? 'coord' (layout(location=3 ) in 2-component vector of uint) 0:? 'b' (layout(location=4 ) in 4-component vector of float) 0:? 'e' (layout(location=5 ) in 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) Linked vertex stage: @@ -84,14 +96,8 @@ Shader version: 450 0:11 add (temp 4-component vector of float) 0:11 add (temp 4-component vector of float) 0:11 add (temp 4-component vector of float) -0:11 direct index (layout(location=1 ) temp 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) -0:11 Constant: -0:11 1 (const int) -0:11 direct index (layout(location=1 ) temp 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) -0:11 Constant: -0:11 0 (const int) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) 0:11 Construct vec4 (temp 4-component vector of float) 0:11 Convert uint to float (temp float) 0:11 direct index (temp uint) @@ -102,12 +108,24 @@ Shader version: 450 0:11 'e' (layout(location=5 ) in 4-component vector of float) 0:13 Sequence 0:13 Sequence -0:13 move second child to first child (temp 2-element array of 4-component vector of float) -0:? 'm' (layout(location=0 ) out 2-element array of 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 move second child to first child (temp 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:13 direct index (temp 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 Constant: +0:13 0 (const int) 0:13 Constant: 0:13 0 (const int) +0:13 move second child to first child (temp 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) +0:13 direct index (temp 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) +0:13 Constant: +0:13 0 (const int) +0:13 Constant: +0:13 1 (const int) 0:13 move second child to first child (temp 2-component vector of uint) 0:? 'coord' (layout(location=2 ) out 2-component vector of uint) 0:13 coord: direct index for structure (temp 2-component vector of uint) @@ -122,45 +140,55 @@ Shader version: 450 0:13 2 (const int) 0:13 Branch: Return 0:? Linker Objects -0:? 'm' (layout(location=0 ) out 2-element array of 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) 0:? 'coord' (layout(location=2 ) out 2-component vector of uint) 0:? 'b' (layout(location=3 ) smooth out 4-component vector of float) 0:? 'd' (layout(location=0 ) in 4-component vector of float) -0:? 'm' (layout(location=1 ) in 2-element array of 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) 0:? 'coord' (layout(location=3 ) in 2-component vector of uint) 0:? 'b' (layout(location=4 ) in 4-component vector of float) 0:? 'e' (layout(location=5 ) in 4-component vector of float) +0:? 'm[0]' (layout(location=0 ) out 4-component vector of float) +0:? 'm[1]' (layout(location=1 ) out 4-component vector of float) +0:? 'm[0]' (layout(location=1 ) in 4-component vector of float) +0:? 'm[1]' (layout(location=2 ) in 4-component vector of float) // Module Version 10000 // Generated by (magic number): 80001 -// Id's are bound by 60 +// Id's are bound by 59 Capability Shader 1: ExtInstImport "GLSL.std.450" MemoryModel Logical GLSL450 - EntryPoint Vertex 4 "main" 18 28 36 39 45 50 55 59 + EntryPoint Vertex 4 "main" 18 20 24 32 35 41 45 50 54 58 Name 4 "main" Name 12 "VI" MemberName 12(VI) 0 "m" MemberName 12(VI) 1 "coord" MemberName 12(VI) 2 "b" Name 14 "local" - Name 18 "m" - Name 28 "coord" - Name 36 "d" - Name 39 "e" - Name 45 "m" + Name 18 "m[1]" + Name 20 "m[0]" + Name 24 "coord" + Name 32 "d" + Name 35 "e" + Name 41 "m[0]" + Name 45 "m[1]" Name 50 "coord" - Name 55 "b" - Name 59 "b" - Decorate 18(m) Location 1 - Decorate 28(coord) Location 3 - Decorate 36(d) Location 0 - Decorate 39(e) Location 5 - Decorate 45(m) Location 0 + Name 54 "b" + Name 58 "b" + Decorate 18(m[1]) Location 2 + Decorate 20(m[0]) Location 1 + Decorate 24(coord) Location 3 + Decorate 32(d) Location 0 + Decorate 35(e) Location 5 + Decorate 41(m[0]) Location 0 + Decorate 45(m[1]) Location 1 Decorate 50(coord) Location 2 - Decorate 55(b) Location 3 - Decorate 59(b) Location 4 + Decorate 54(b) Location 3 + Decorate 58(b) Location 4 2: TypeVoid 3: TypeFunction 2 6: TypeFloat 32 @@ -173,54 +201,54 @@ Shader version: 450 13: TypePointer Function 12(VI) 15: TypeInt 32 1 16: 15(int) Constant 2 - 17: TypePointer Input 10 - 18(m): 17(ptr) Variable Input - 19: 15(int) Constant 1 - 20: TypePointer Input 7(fvec4) - 23: 15(int) Constant 0 - 27: TypePointer Input 11(ivec2) - 28(coord): 27(ptr) Variable Input - 29: 8(int) Constant 0 - 30: TypePointer Input 8(int) - 36(d): 20(ptr) Variable Input - 39(e): 20(ptr) Variable Input - 42: TypePointer Function 7(fvec4) - 44: TypePointer Output 10 - 45(m): 44(ptr) Variable Output - 46: TypePointer Function 10 + 17: TypePointer Input 7(fvec4) + 18(m[1]): 17(ptr) Variable Input + 20(m[0]): 17(ptr) Variable Input + 23: TypePointer Input 11(ivec2) + 24(coord): 23(ptr) Variable Input + 25: 8(int) Constant 0 + 26: TypePointer Input 8(int) + 32(d): 17(ptr) Variable Input + 35(e): 17(ptr) Variable Input + 38: TypePointer Function 7(fvec4) + 40: TypePointer Output 7(fvec4) + 41(m[0]): 40(ptr) Variable Output + 42: 15(int) Constant 0 + 45(m[1]): 40(ptr) Variable Output + 46: 15(int) Constant 1 49: TypePointer Output 11(ivec2) 50(coord): 49(ptr) Variable Output 51: TypePointer Function 11(ivec2) - 54: TypePointer Output 7(fvec4) - 55(b): 54(ptr) Variable Output - 59(b): 20(ptr) Variable Input + 54(b): 40(ptr) Variable Output + 58(b): 17(ptr) Variable Input 4(main): 2 Function None 3 5: Label 14(local): 13(ptr) Variable Function - 21: 20(ptr) AccessChain 18(m) 19 - 22: 7(fvec4) Load 21 - 24: 20(ptr) AccessChain 18(m) 23 - 25: 7(fvec4) Load 24 - 26: 7(fvec4) FAdd 22 25 - 31: 30(ptr) AccessChain 28(coord) 29 - 32: 8(int) Load 31 - 33: 6(float) ConvertUToF 32 - 34: 7(fvec4) CompositeConstruct 33 33 33 33 - 35: 7(fvec4) FAdd 26 34 - 37: 7(fvec4) Load 36(d) - 38: 7(fvec4) FAdd 35 37 - 40: 7(fvec4) Load 39(e) - 41: 7(fvec4) FAdd 38 40 - 43: 42(ptr) AccessChain 14(local) 16 - Store 43 41 - 47: 46(ptr) AccessChain 14(local) 23 - 48: 10 Load 47 - Store 45(m) 48 - 52: 51(ptr) AccessChain 14(local) 19 + 19: 7(fvec4) Load 18(m[1]) + 21: 7(fvec4) Load 20(m[0]) + 22: 7(fvec4) FAdd 19 21 + 27: 26(ptr) AccessChain 24(coord) 25 + 28: 8(int) Load 27 + 29: 6(float) ConvertUToF 28 + 30: 7(fvec4) CompositeConstruct 29 29 29 29 + 31: 7(fvec4) FAdd 22 30 + 33: 7(fvec4) Load 32(d) + 34: 7(fvec4) FAdd 31 33 + 36: 7(fvec4) Load 35(e) + 37: 7(fvec4) FAdd 34 36 + 39: 38(ptr) AccessChain 14(local) 16 + Store 39 37 + 43: 38(ptr) AccessChain 14(local) 42 42 + 44: 7(fvec4) Load 43 + Store 41(m[0]) 44 + 47: 38(ptr) AccessChain 14(local) 42 46 + 48: 7(fvec4) Load 47 + Store 45(m[1]) 48 + 52: 51(ptr) AccessChain 14(local) 46 53: 11(ivec2) Load 52 Store 50(coord) 53 - 56: 42(ptr) AccessChain 14(local) 16 - 57: 7(fvec4) Load 56 - Store 55(b) 57 + 55: 38(ptr) AccessChain 14(local) 16 + 56: 7(fvec4) Load 55 + Store 54(b) 56 Return FunctionEnd diff --git a/Test/hlsl.structarray.flatten.frag b/Test/hlsl.structarray.flatten.frag new file mode 100644 index 00000000..eedb931d --- /dev/null +++ b/Test/hlsl.structarray.flatten.frag @@ -0,0 +1,28 @@ +SamplerState g_samp; +Texture1D g_tex; + +struct tex_t { + SamplerState samp; + Texture1D tex; + int nonopaque_thing; +}; + +struct tex_with_arrays_t { + SamplerState samp[2]; + Texture1D tex[2]; + int nonopaque_thing; +}; + +uniform tex_t g_texdata; +uniform tex_t g_texdata_array[3]; +uniform tex_with_arrays_t g_texdata_array2[3]; + +struct PS_OUTPUT { float4 color : SV_Target0; }; + +void main(out PS_OUTPUT ps_output) +{ + ps_output.color = + g_texdata.tex.Sample(g_texdata.samp, 0.5) + + g_texdata_array[1].tex.Sample(g_texdata_array[1].samp, 0.4) + + g_texdata_array2[1].tex[0].Sample(g_texdata_array2[1].samp[0], 0.3); +} diff --git a/Test/hlsl.structarray.flatten.geom b/Test/hlsl.structarray.flatten.geom new file mode 100644 index 00000000..1b05dc11 --- /dev/null +++ b/Test/hlsl.structarray.flatten.geom @@ -0,0 +1,17 @@ + +struct VertexData { + float4 position : POSITION; + float4 color : COLOR0; + float2 uv : TEXCOORD0; +}; + +[maxvertexcount(4)] +void main(line VertexData vin[2], inout TriangleStream outStream) +{ + VertexData vout; + + vout.color = vin[0].color; + vout.uv = vin[0].uv; + vout.position = vin[0].position; + outStream.Append(vout); +} diff --git a/Test/hlsl.structin.vert b/Test/hlsl.structin.vert index 7eba552d..43d0cfd0 100644 --- a/Test/hlsl.structin.vert +++ b/Test/hlsl.structin.vert @@ -11,4 +11,4 @@ VI main(float4 d, VI vi, float4 e) : SV_POSITION local.b = vi.m[1] + vi.m[0] + float4(vi.coord.x) + d + e; return local; -} \ No newline at end of file +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 1e7b65bf..ba347958 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -203,6 +203,8 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.shapeConvRet.frag", "main"}, {"hlsl.stringtoken.frag", "main"}, {"hlsl.string.frag", "main"}, + {"hlsl.structarray.flatten.frag", "main"}, + {"hlsl.structarray.flatten.geom", "main"}, {"hlsl.structin.vert", "main"}, {"hlsl.intrinsics.vert", "VertexShaderFunction"}, {"hlsl.matType.frag", "PixelShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 61fb4dd9..e676e95e 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -389,7 +389,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) else if (variableType.getBasicType() == EbtBlock) parseContext.declareBlock(idToken.loc, variableType, idToken.string); else { - if (variableType.getQualifier().storage == EvqUniform && ! variableType.isOpaque()) { + if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) { // this isn't really an individual variable, but a member of the $Global buffer parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string); } else { @@ -2215,6 +2215,20 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) return false; } + // This is to guarantee we do this no matter how we get out of the stack frame. + // This way there's no bug if an early return forgets to do it. + struct tFinalize { + tFinalize(HlslParseContext& p) : parseContext(p) { } + ~tFinalize() { parseContext.finalizeFlattening(); } + HlslParseContext& parseContext; + } finalize(parseContext); + + // Initialize the flattening accumulation data, so we can track data across multiple bracket or + // dot operators. This can also be nested, e.g, for [], so we have to track each nesting + // level: hence the init and finalize. Even though in practice these must be + // constants, they are parsed no matter what. + parseContext.initFlattening(); + // Something was found, chain as many postfix operations as exist. do { TSourceLoc loc = token.loc; @@ -2248,7 +2262,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) node = parseContext.handleDotDereference(field.loc, node, *field.string); // In the event of a method node, we look for an open paren and accept the function call. - if (node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) { + if (node != nullptr && node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) { if (! acceptFunctionCall(field, node, base)) { expected("function parameters"); return false; diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 2d99c094..6aa965fe 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -45,6 +45,7 @@ #include "../glslang/OSDependent/osinclude.h" #include +#include #include namespace glslang { @@ -651,11 +652,11 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, else { // at least one of base and index is variable... - if (base->getAsSymbolNode() && shouldFlatten(base->getType())) { + if (base->getAsSymbolNode() && (wasFlattened(base) || shouldFlatten(base->getType()))) { if (index->getQualifier().storage != EvqConst) error(loc, "Invalid variable index to flattened uniform array", base->getAsSymbolNode()->getName().c_str(), ""); - result = flattenAccess(base, indexValue); + result = flattenAccess(loc, base, indexValue); flattened = (result != base); } else { if (index->getQualifier().storage == EvqConst) { @@ -831,8 +832,8 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt } } if (fieldFound) { - if (base->getAsSymbolNode() && shouldFlatten(base->getType())) - result = flattenAccess(base, member); + if (base->getAsSymbolNode() && (wasFlattened(base) || shouldFlatten(base->getType()))) + result = flattenAccess(loc, base, member); else { if (base->getType().getQualifier().storage == EvqConst) result = intermediate.foldDereference(base, member, loc); @@ -850,6 +851,12 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt return result; } +// Determine whether we should flatten an arbitrary type. +bool HlslParseContext::shouldFlatten(const TType& type) const +{ + return shouldFlattenIO(type) || shouldFlattenUniform(type); +} + // Is this an IO variable that can't be passed down the stack? // E.g., pipeline inputs to the vertex stage and outputs from the fragment stage. bool HlslParseContext::shouldFlattenIO(const TType& type) const @@ -869,27 +876,98 @@ bool HlslParseContext::shouldFlattenUniform(const TType& type) const { const TStorageQualifier qualifier = type.getQualifier().storage; - return type.isArray() && - intermediate.getFlattenUniformArrays() && + return ((type.isArray() && intermediate.getFlattenUniformArrays()) || type.isStruct()) && qualifier == EvqUniform && - type.isOpaque(); + type.containsOpaque(); } +// Top level variable flattening: construct data void HlslParseContext::flatten(const TSourceLoc& loc, const TVariable& variable) { const TType& type = variable.getType(); - // Presently, flattening of structure arrays is unimplemented. - // We handle one, or the other. - if (type.isArray() && type.isStruct()) { - error(loc, "cannot flatten structure array", variable.getName().c_str(), ""); + // emplace gives back a pair whose .first is an iterator to the item... + auto entry = flattenMap.emplace(variable.getUniqueId(), + TFlattenData(type.getQualifier().layoutBinding)); + + // ... and the item is a map pair, so first->second is the TFlattenData itself. + flatten(loc, variable, type, entry.first->second, ""); +} + +// Recursively flatten the given variable at the provided type, building the flattenData as we go. +// +// This is mutually recursive with flattenStruct and flattenArray. +// We are going to flatten an arbitrarily nested composite structure into a linear sequence of +// members, and later on, we want to turn a path through the tree structure into a final +// location in this linear sequence. +// +// If the tree was N-ary, that can be directly calculated. However, we are dealing with +// arbitrary numbers - peraps a struct of 7 members containing an array of 3. Thus, we must +// build a data structure to allow the sequence of bracket and dot operators on arrays and +// structs to arrive at the proper member. +// +// To avoid storing a tree with pointers, we are going to flatten the tree into a vector of integers. +// The leaves are the indexes into the flattened member array. +// Each level will have the next location for the Nth item stored sequentially, so for instance: +// +// struct { float2 a[2]; int b; float4 c[3] }; +// +// This will produce the following flattened tree: +// Pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 +// (3, 7, 8, 5, 6, 0, 1, 2, 11, 12, 13, 3, 4, 5} +// +// Given a reference to mystruct.c[1], the access chain is (2,1), so we traverse: +// (0+2) = 8 --> (8+1) = 12 --> 12 = 4 +// +// so the 4th flattened member in traversal order is ours. +// +int HlslParseContext::flatten(const TSourceLoc& loc, const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name) +{ + // TODO: when struct splitting is in place we can remove this restriction. + if (language == EShLangGeometry) { + const TType derefType(type, 0); + if (!isFinalFlattening(derefType) && type.getQualifier().storage == EvqVaryingIn) + error(loc, "recursive type not yet supported in GS input", variable.getName().c_str(), ""); } - if (type.isStruct()) - flattenStruct(variable); - + // If something is an arrayed struct, the array flattener will recursively call flatten() + // to then flatten the struct, so this is an "if else": we don't do both. if (type.isArray()) - flattenArray(loc, variable); + return flattenArray(loc, variable, type, flattenData, name); + else if (type.isStruct()) + return flattenStruct(loc, variable, type, flattenData, name); + else { + assert(0); // should never happen + return -1; + } +} + +// Add a single flattened member to the flattened data being tracked for the composite +// Returns true for the final flattening level. +int HlslParseContext::addFlattenedMember(const TSourceLoc& loc, + const TVariable& variable, const TType& type, TFlattenData& flattenData, + const TString& memberName, bool track) +{ + if (isFinalFlattening(type)) { + // This is as far as we flatten. Insert the variable. + TVariable* memberVariable = makeInternalVariable(memberName.c_str(), type); + mergeQualifiers(memberVariable->getWritableType().getQualifier(), variable.getType().getQualifier()); + + if (flattenData.nextBinding != TQualifier::layoutBindingEnd) + memberVariable->getWritableType().getQualifier().layoutBinding = flattenData.nextBinding++; + + flattenData.offsets.push_back(flattenData.members.size()); + flattenData.members.push_back(memberVariable); + + if (track) + trackLinkageDeferred(*memberVariable); + + return flattenData.offsets.size()-1; // location of the member reference + } else { + // Further recursion required + return flatten(loc, variable, type, flattenData, memberName); + } } // Figure out the mapping between an aggregate's top members and an @@ -899,84 +977,103 @@ void HlslParseContext::flatten(const TSourceLoc& loc, const TVariable& variable) // effecting a transfer of this information to the flattened variable form. // // Assumes shouldFlatten() or equivalent was called first. -// -// TODO: generalize this to arbitrary nesting? -void HlslParseContext::flattenStruct(const TVariable& variable) +int HlslParseContext::flattenStruct(const TSourceLoc& loc, const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name) { - TVector memberVariables; + assert(type.isStruct()); + + auto members = *type.getStruct(); + + // Reserve space for this tree level. + int start = flattenData.offsets.size(); + int pos = start; + flattenData.offsets.resize(int(pos + members.size()), -1); - auto members = *variable.getType().getStruct(); for (int member = 0; member < (int)members.size(); ++member) { - TVariable* memberVariable = makeInternalVariable(members[member].type->getFieldName().c_str(), - *members[member].type); - mergeQualifiers(memberVariable->getWritableType().getQualifier(), variable.getType().getQualifier()); - memberVariables.push_back(memberVariable); + TType& dereferencedType = *members[member].type; + const TString memberName = name + (name.empty() ? "" : ".") + dereferencedType.getFieldName(); + + const int mpos = addFlattenedMember(loc, variable, dereferencedType, flattenData, memberName, false); + flattenData.offsets[pos++] = mpos; // N.B. Erase I/O-related annotations from the source-type member. - members[member].type->getQualifier().makeTemporary(); + dereferencedType.getQualifier().makeTemporary(); } - flattenMap[variable.getUniqueId()] = memberVariables; + return start; } // Figure out mapping between an array's members and an // equivalent set of individual variables. // // Assumes shouldFlatten() or equivalent was called first. -void HlslParseContext::flattenArray(const TSourceLoc& loc, const TVariable& variable) +int HlslParseContext::flattenArray(const TSourceLoc& loc, const TVariable& variable, const TType& type, + TFlattenData& flattenData, TString name) { - const TType& type = variable.getType(); assert(type.isArray()); if (type.isImplicitlySizedArray()) error(loc, "cannot flatten implicitly sized array", variable.getName().c_str(), ""); - if (type.getArraySizes()->getNumDims() != 1) - error(loc, "cannot flatten multi-dimensional array", variable.getName().c_str(), ""); - - const int size = type.getCumulativeArraySize(); - - TVector memberVariables; - + const int size = type.getOuterArraySize(); const TType dereferencedType(type, 0); - int binding = type.getQualifier().layoutBinding; - if (dereferencedType.isStruct() || dereferencedType.isArray()) { - error(loc, "cannot flatten array of aggregate types", variable.getName().c_str(), ""); - } + if (name.empty()) + name = variable.getName(); - for (int element=0; element < size; ++element) { + // Reserve space for this tree level. + int start = flattenData.offsets.size(); + int pos = start; + flattenData.offsets.resize(int(pos + size), -1); + + for (int element=0; element < size; ++element) { char elementNumBuf[20]; // sufficient for MAXINT snprintf(elementNumBuf, sizeof(elementNumBuf)-1, "[%d]", element); - const TString memberName = variable.getName() + elementNumBuf; + const int mpos = addFlattenedMember(loc, variable, dereferencedType, flattenData, + name + elementNumBuf, true); - TVariable* memberVariable = makeInternalVariable(memberName.c_str(), dereferencedType); - memberVariable->getWritableType().getQualifier() = variable.getType().getQualifier(); - - memberVariable->getWritableType().getQualifier().layoutBinding = binding; - - if (binding != TQualifier::layoutBindingEnd) - ++binding; - - memberVariables.push_back(memberVariable); - trackLinkageDeferred(*memberVariable); + flattenData.offsets[pos++] = mpos; } - flattenMap[variable.getUniqueId()] = memberVariables; + return start; } +// Return true if we have flattened this node. +bool HlslParseContext::wasFlattened(const TIntermTyped* node) const +{ + return node != nullptr && + node->getAsSymbolNode() != nullptr && + wasFlattened(node->getAsSymbolNode()->getId()); +} + + // Turn an access into an aggregate that was flattened to instead be // an access to the individual variable the member was flattened to. // Assumes shouldFlatten() or equivalent was called first. -TIntermTyped* HlslParseContext::flattenAccess(TIntermTyped* base, int member) +TIntermTyped* HlslParseContext::flattenAccess(const TSourceLoc&, TIntermTyped* base, int member) { + const TType dereferencedType(base->getType(), member); // dereferenced type + const TIntermSymbol& symbolNode = *base->getAsSymbolNode(); - if (flattenMap.find(symbolNode.getId()) == flattenMap.end()) + const auto flattenData = flattenMap.find(symbolNode.getId()); + + if (flattenData == flattenMap.end()) return base; - const TVariable* memberVariable = flattenMap[symbolNode.getId()][member]; - return intermediate.addSymbol(*memberVariable); + // Calculate new cumulative offset from the packed tree + flattenOffset.back() = flattenData->second.offsets[flattenOffset.back() + member]; + + if (isFinalFlattening(dereferencedType)) { + // Finished flattening: create symbol for variable + member = flattenData->second.offsets[flattenOffset.back()]; + const TVariable* memberVariable = flattenData->second.members[member]; + return intermediate.addSymbol(*memberVariable); + } else { + // If this is not the final flattening, accumulate the position and return + // an object of the partially dereferenced type. + return new TIntermSymbol(symbolNode.getId(), "flattenShadow", dereferencedType); + } } // Variables that correspond to the user-interface in and out of a stage @@ -1002,8 +1099,8 @@ void HlslParseContext::assignLocations(TVariable& variable) } }; - if (shouldFlatten(variable.getType())) { - auto& memberList = flattenMap[variable.getUniqueId()]; + if (wasFlattened(variable.getUniqueId())) { + auto& memberList = flattenMap[variable.getUniqueId()].members; for (auto member = memberList.begin(); member != memberList.end(); ++member) assignLocation(**member); } else @@ -1294,7 +1391,7 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op return nullptr; const auto mustFlatten = [&](const TIntermTyped& node) { - return shouldFlatten(node.getType()) && node.getAsSymbolNode() && + return wasFlattened(&node) && node.getAsSymbolNode() && flattenMap.find(node.getAsSymbolNode()->getId()) != flattenMap.end(); }; @@ -1327,10 +1424,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op memberCount = left->getType().getCumulativeArraySize(); if (flattenLeft) - leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second; + leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second.members; if (flattenRight) { - rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second; + rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second.members; } else { // The RHS is not flattened. There are several cases: // 1. 1 item to copy: Use the RHS directly. @@ -1355,13 +1452,15 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op } } + int memberIdx = 0; + const auto getMember = [&](bool flatten, TIntermTyped* node, const TVector& memberVariables, int member, TOperator op, const TType& memberType) -> TIntermTyped * { TIntermTyped* subTree; - if (flatten) - subTree = intermediate.addSymbol(*memberVariables[member]); - else { + if (flatten && isFinalFlattening(memberType)) { + subTree = intermediate.addSymbol(*memberVariables[memberIdx++]); + } else { subTree = intermediate.addIndex(op, node, intermediate.addConstantUnion(member, loc), loc); subTree->setType(memberType); } @@ -1369,46 +1468,59 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op return subTree; }; - // Return the proper RHS node: a new symbol from a TVariable, copy - // of an TIntermSymbol node, or sometimes the right node directly. - const auto getRHS = [&]() { - return rhsTempVar ? intermediate.addSymbol(*rhsTempVar, loc) : - cloneSymNode ? intermediate.addSymbol(*cloneSymNode) : - right; + // Cannot use auto here, because this is recursive, and auto can't work out the type without seeing the + // whole thing. So, we'll resort to an explicit type via std::function. + const std::function + traverse = [&](TIntermTyped* left, TIntermTyped* right) -> void { + // If we get here, we are assigning to or from a whole array or struct that must be + // flattened, so have to do member-by-member assignment: + + if (left->getType().isArray()) { + // array case + const TType dereferencedType(left->getType(), 0); + + for (int element=0; element < left->getType().getOuterArraySize(); ++element) { + // Add a new AST symbol node if we have a temp variable holding a complex RHS. + TIntermTyped* subRight = getMember(flattenRight, right, *rightVariables, element, + EOpIndexDirect, dereferencedType); + TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, element, + EOpIndexDirect, dereferencedType); + + if (isFinalFlattening(dereferencedType)) + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); + else + traverse(subLeft, subRight); + } + } else if (left->getType().isStruct()) { + // struct case + const auto& members = *left->getType().getStruct(); + + for (int member = 0; member < (int)members.size(); ++member) { + TIntermTyped* subRight = getMember(flattenRight, right, *rightVariables, member, + EOpIndexDirectStruct, *members[member].type); + TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, member, + EOpIndexDirectStruct, *members[member].type); + + if (isFinalFlattening(*members[member].type)) + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); + else + traverse(subLeft, subRight); + } + } else { + assert(0); // we should never be called on a non-flattenable thing, because + // that case bails out above to a simple copy. + } + }; - // Handle struct assignment - if (left->getType().isStruct()) { - // If we get here, we are assigning to or from a whole struct that must be - // flattened, so have to do member-by-member assignment: - const auto& members = *left->getType().getStruct(); + // Use the proper RHS node: a new symbol from a TVariable, copy + // of an TIntermSymbol node, or sometimes the right node directly. + right = rhsTempVar ? intermediate.addSymbol(*rhsTempVar, loc) : + cloneSymNode ? intermediate.addSymbol(*cloneSymNode) : + right; - for (int member = 0; member < (int)members.size(); ++member) { - TIntermTyped* subRight = getMember(flattenRight, getRHS(), *rightVariables, member, - EOpIndexDirectStruct, *members[member].type); - TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, member, - EOpIndexDirectStruct, *members[member].type); - assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); - } - } - - // Handle array assignment - if (left->getType().isArray()) { - // If we get here, we are assigning to or from a whole array that must be - // flattened, so have to do member-by-member assignment: - - const TType dereferencedType(left->getType(), 0); - - for (int element=0; element < memberCount; ++element) { - // Add a new AST symbol node if we have a temp variable holding a complex RHS. - TIntermTyped* subRight = getMember(flattenRight, getRHS(), *rightVariables, element, - EOpIndexDirect, dereferencedType); - TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, element, - EOpIndexDirect, dereferencedType); - - assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); - } - } + // This makes the whole assignment, recursing through subtypes as needed. + traverse(left, right); assert(assignList != nullptr); assignList->setOperator(EOpSequence); @@ -2701,7 +2813,7 @@ void HlslParseContext::addInputArgumentConversions(const TFunction& function, TI arg = intermediate.addShapeConversion(EOpFunctionCall, *function[i].type, arg); setArg(i, arg); } else { - if (shouldFlatten(arg->getType())) { + if (wasFlattened(arg)) { // Will make a two-level subtree. // The deepest will copy member-by-member to build the structure to pass. // The level above that will be a two-operand EOpComma sequence that follows the copy by the @@ -2749,7 +2861,7 @@ TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& fu return function[argNum].type->getQualifier().isParamOutput() && (*function[argNum].type != arguments[argNum]->getAsTyped()->getType() || shouldConvertLValue(arguments[argNum]) || - shouldFlatten(arguments[argNum]->getAsTyped()->getType())); + wasFlattened(arguments[argNum]->getAsTyped())); }; // Will there be any output conversions? @@ -4589,23 +4701,23 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i inheritGlobalDefaults(type.getQualifier()); - bool flattenVar = false; + const bool flattenVar = shouldFlatten(type); // Declare the variable if (type.isArray()) { // array case - flattenVar = shouldFlatten(type); declareArray(loc, identifier, type, symbol, !flattenVar); - if (flattenVar) - flatten(loc, *symbol->getAsVariable()); } else { // non-array case if (! symbol) - symbol = declareNonArray(loc, identifier, type); + symbol = declareNonArray(loc, identifier, type, !flattenVar); else if (type != symbol->getType()) error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str()); } + if (flattenVar) + flatten(loc, *symbol->getAsVariable()); + if (! symbol) return nullptr; @@ -4658,14 +4770,14 @@ TVariable* HlslParseContext::makeInternalVariable(const char* name, const TType& // // Return the successfully declared variable. // -TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type) +TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type, bool track) { // make a new variable TVariable* variable = new TVariable(&identifier, type); // add variable to symbol table if (symbolTable.insert(*variable)) { - if (symbolTable.atGlobalLevel()) + if (track && symbolTable.atGlobalLevel()) trackLinkageDeferred(*variable); return variable; } diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 907490e3..206df9b8 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -169,10 +169,23 @@ public: // Potentially rename shader entry point function void renameShaderFunction(TString*& name) const; + // Reset data for incrementally built referencing of flattened composite structures + void initFlattening() { flattenLevel.push_back(0); flattenOffset.push_back(0); } + void finalizeFlattening() { flattenLevel.pop_back(); flattenOffset.pop_back(); } + protected: + struct TFlattenData { + TFlattenData() : nextBinding(TQualifier::layoutBindingEnd) { } + TFlattenData(int nb) : nextBinding(nb) { } + + TVector members; // individual flattened variables + TVector offsets; // offset to next tree level + int nextBinding; // next binding to use. + }; + void inheritGlobalDefaults(TQualifier& dst) const; TVariable* makeInternalVariable(const char* name, const TType&) const; - TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&); + TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool track); void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool track); TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer); @@ -183,13 +196,19 @@ protected: bool shouldConvertLValue(const TIntermNode*) const; // Array and struct flattening - bool shouldFlatten(const TType& type) const { return shouldFlattenIO(type) || shouldFlattenUniform(type); } - TIntermTyped* flattenAccess(TIntermTyped* base, int member); + bool shouldFlatten(const TType& type) const; + TIntermTyped* flattenAccess(const TSourceLoc&, TIntermTyped* base, int member); bool shouldFlattenIO(const TType&) const; bool shouldFlattenUniform(const TType&) const; + bool wasFlattened(const TIntermTyped* node) const; + bool wasFlattened(int id) const { return flattenMap.find(id) != flattenMap.end(); } + int addFlattenedMember(const TSourceLoc& loc, const TVariable&, const TType&, TFlattenData&, const TString& name, bool track); + bool isFinalFlattening(const TType& type) const { return !(type.isStruct() || type.isArray()); } + void flatten(const TSourceLoc& loc, const TVariable& variable); - void flattenStruct(const TVariable& variable); - void flattenArray(const TSourceLoc& loc, const TVariable& variable); + int flatten(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name); + int flattenStruct(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name); + int flattenArray(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name); // Current state of parsing struct TPragma contextPragma; @@ -252,7 +271,10 @@ protected: // TVector ioArraySymbolResizeList; - TMap> flattenMap; + TMap flattenMap; + TVector flattenLevel; // nested postfix operator level for flattening + TVector flattenOffset; // cumulative offset for flattening + unsigned int nextInLocation; unsigned int nextOutLocation;