diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 063e416d35a1e91209944f96746097eaf864a482..30af4fe44abcd429dc524f046f1113284df707b8 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -81,6 +81,7 @@ enum TOptions { EOptionReadHlsl = (1 << 17), EOptionCascadingErrors = (1 << 18), EOptionAutoMapBindings = (1 << 19), + EOptionFlattenUniformArrays = (1 << 20), }; // @@ -285,6 +286,10 @@ void ProcessArguments(int argc, char* argv[]) lowerword == "auto-map-binding" || lowerword == "amb") { Options |= EOptionAutoMapBindings; + } else if (lowerword == "flatten-uniform-arrays" || // synonyms + lowerword == "flatten-uniform-array" || + lowerword == "fua") { + Options |= EOptionFlattenUniformArrays; } else { usage(); } @@ -407,6 +412,10 @@ void ProcessArguments(int argc, char* argv[]) // -o or -x makes no sense if there is no target binary if (binaryFileName && (Options & EOptionSpv) == 0) Error("no binary generation requested (e.g., -V)"); + + if ((Options & EOptionFlattenUniformArrays) != 0 && + (Options & EOptionReadHlsl) == 0) + Error("uniform array flattening only valid when compiling HLSL source."); } // @@ -532,6 +541,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits) shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]); shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]); shader->setShiftUboBinding(baseUboBinding[compUnit.stage]); + shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0); if (Options & EOptionAutoMapBindings) shader->setAutoMapBindings(true); @@ -930,6 +940,9 @@ void usage() " --auto-map-bindings automatically bind uniform variables without\n" " explicit bindings.\n" " --amb synonym for --auto-map-bindings\n" + "\n" + " --flatten-uniform-arrays flatten uniform array references to scalars\n" + " --fua synonym for --flatten-uniform-arrays\n" ); exit(EFailUsage); diff --git a/Test/baseResults/hlsl.array.flatten.frag.out b/Test/baseResults/hlsl.array.flatten.frag.out new file mode 100644 index 0000000000000000000000000000000000000000..a3752251faee9e907db8332a461d5cfda2be591b --- /dev/null +++ b/Test/baseResults/hlsl.array.flatten.frag.out @@ -0,0 +1,588 @@ +hlsl.array.flatten.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:17 Function Definition: TestFn1( (global 4-component vector of float) +0:17 Function Parameters: +0:? Sequence +0:18 Branch: Return with expression +0:18 texture (global 4-component vector of float) +0:18 Construct combined texture-sampler (temp sampler1D) +0:? 'g_tex[1]' (temp texture1D) +0:? 'g_samp[1]' (temp sampler) +0:18 Constant: +0:18 0.200000 +0:22 Function Definition: TestFn2(t11[3];p1[3]; (global 4-component vector of float) +0:22 Function Parameters: +0:22 'l_tex' (in 3-element array of texture1D) +0:22 'l_samp' (in 3-element array of sampler) +0:? Sequence +0:23 Branch: Return with expression +0:23 texture (global 4-component vector of float) +0:23 Construct combined texture-sampler (temp sampler1D) +0:23 direct index (temp texture1D) +0:23 'l_tex' (in 3-element array of texture1D) +0:23 Constant: +0:23 2 (const int) +0:23 direct index (temp sampler) +0:23 'l_samp' (in 3-element array of sampler) +0:23 Constant: +0:23 2 (const int) +0:23 Constant: +0:23 0.200000 +0:26 Sequence +0:26 move second child to first child (temp 5-element array of int) +0:26 'not_flattened_a' (global 5-element array of int) +0:26 Constant: +0:26 1 (const int) +0:26 2 (const int) +0:26 3 (const int) +0:26 4 (const int) +0:26 5 (const int) +0:31 Function Definition: main(struct-PS_OUTPUT-vf41; (global void) +0:31 Function Parameters: +0:31 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:33 Sequence +0:? Sequence +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 0 (const int) +0:? 'g_samp[0]' (uniform sampler) +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 1 (const int) +0:? 'g_samp[1]' (uniform sampler) +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 2 (const int) +0:? 'g_samp[2]' (uniform sampler) +0:34 Sequence +0:? Sequence +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 0 (const int) +0:? 'g_tex[0]' (uniform texture1D) +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 1 (const int) +0:? 'g_tex[1]' (uniform texture1D) +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 2 (const int) +0:? 'g_tex[2]' (uniform texture1D) +0:35 Sequence +0:? Sequence +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 0 (const int) +0:? 'g_floats[0]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 1 (const int) +0:? 'g_floats[1]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 2 (const int) +0:? 'g_floats[2]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 3 (const int) +0:? 'g_floats[3]' (uniform float) +0:37 move second child to first child (temp 4-component vector of float) +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:37 add (temp 4-component vector of float) +0:37 Function Call: TestFn1( (global 4-component vector of float) +0:37 Function Call: TestFn2(t11[3];p1[3]; (global 4-component vector of float) +0:? Comma (temp 3-element array of texture1D) +0:? Sequence +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 0 (const int) +0:? 'g_tex[0]' (uniform texture1D) +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 1 (const int) +0:? 'g_tex[1]' (uniform texture1D) +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 2 (const int) +0:? 'g_tex[2]' (uniform texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Comma (temp 3-element array of sampler) +0:? Sequence +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 0 (const int) +0:? 'g_samp[0]' (uniform sampler) +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 1 (const int) +0:? 'g_samp[1]' (uniform sampler) +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 2 (const int) +0:? 'g_samp[2]' (uniform sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Linker Objects +0:? 'g_tex[0]' (uniform texture1D) +0:? 'g_tex[1]' (uniform texture1D) +0:? 'g_tex[2]' (uniform texture1D) +0:? 'g_tex_explicit[0]' (layout(binding=1 ) uniform texture1D) +0:? 'g_tex_explicit[1]' (layout(binding=2 ) uniform texture1D) +0:? 'g_tex_explicit[2]' (layout(binding=3 ) uniform texture1D) +0:? 'g_samp[0]' (uniform sampler) +0:? 'g_samp[1]' (uniform sampler) +0:? 'g_samp[2]' (uniform sampler) +0:? 'g_samp_explicit[0]' (layout(binding=5 ) uniform sampler) +0:? 'g_samp_explicit[1]' (layout(binding=6 ) uniform sampler) +0:? 'g_samp_explicit[2]' (layout(binding=7 ) uniform sampler) +0:? 'g_mats[0]' (uniform 3X3 matrix of float) +0:? 'g_mats[1]' (uniform 3X3 matrix of float) +0:? 'g_mats[2]' (uniform 3X3 matrix of float) +0:? 'g_mats[3]' (uniform 3X3 matrix of float) +0:? 'g_mats_explicit[0]' (layout(binding=10 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[1]' (layout(binding=11 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[2]' (layout(binding=12 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[3]' (layout(binding=13 ) uniform 3X3 matrix of float) +0:? 'g_floats[0]' (uniform float) +0:? 'g_floats[1]' (uniform float) +0:? 'g_floats[2]' (uniform float) +0:? 'g_floats[3]' (uniform float) +0:? 'not_flattened_a' (global 5-element array of int) +0:? 'color' (layout(location=0 ) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:17 Function Definition: TestFn1( (global 4-component vector of float) +0:17 Function Parameters: +0:? Sequence +0:18 Branch: Return with expression +0:18 texture (global 4-component vector of float) +0:18 Construct combined texture-sampler (temp sampler1D) +0:? 'g_tex[1]' (temp texture1D) +0:? 'g_samp[1]' (temp sampler) +0:18 Constant: +0:18 0.200000 +0:22 Function Definition: TestFn2(t11[3];p1[3]; (global 4-component vector of float) +0:22 Function Parameters: +0:22 'l_tex' (in 3-element array of texture1D) +0:22 'l_samp' (in 3-element array of sampler) +0:? Sequence +0:23 Branch: Return with expression +0:23 texture (global 4-component vector of float) +0:23 Construct combined texture-sampler (temp sampler1D) +0:23 direct index (temp texture1D) +0:23 'l_tex' (in 3-element array of texture1D) +0:23 Constant: +0:23 2 (const int) +0:23 direct index (temp sampler) +0:23 'l_samp' (in 3-element array of sampler) +0:23 Constant: +0:23 2 (const int) +0:23 Constant: +0:23 0.200000 +0:26 Sequence +0:26 move second child to first child (temp 5-element array of int) +0:26 'not_flattened_a' (global 5-element array of int) +0:26 Constant: +0:26 1 (const int) +0:26 2 (const int) +0:26 3 (const int) +0:26 4 (const int) +0:26 5 (const int) +0:31 Function Definition: main(struct-PS_OUTPUT-vf41; (global void) +0:31 Function Parameters: +0:31 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:33 Sequence +0:? Sequence +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 0 (const int) +0:? 'g_samp[0]' (uniform sampler) +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 1 (const int) +0:? 'g_samp[1]' (uniform sampler) +0:33 move second child to first child (temp sampler) +0:33 direct index (temp sampler) +0:33 'local_sampler_array' (temp 3-element array of sampler) +0:33 Constant: +0:33 2 (const int) +0:? 'g_samp[2]' (uniform sampler) +0:34 Sequence +0:? Sequence +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 0 (const int) +0:? 'g_tex[0]' (uniform texture1D) +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 1 (const int) +0:? 'g_tex[1]' (uniform texture1D) +0:34 move second child to first child (temp texture1D) +0:34 direct index (temp texture1D) +0:34 'local_texture_array' (temp 3-element array of texture1D) +0:34 Constant: +0:34 2 (const int) +0:? 'g_tex[2]' (uniform texture1D) +0:35 Sequence +0:? Sequence +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 0 (const int) +0:? 'g_floats[0]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 1 (const int) +0:? 'g_floats[1]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 2 (const int) +0:? 'g_floats[2]' (uniform float) +0:35 move second child to first child (temp float) +0:35 direct index (temp float) +0:35 'local_float_array' (temp 4-element array of float) +0:35 Constant: +0:35 3 (const int) +0:? 'g_floats[3]' (uniform float) +0:37 move second child to first child (temp 4-component vector of float) +0:? 'color' (layout(location=0 ) out 4-component vector of float) +0:37 add (temp 4-component vector of float) +0:37 Function Call: TestFn1( (global 4-component vector of float) +0:37 Function Call: TestFn2(t11[3];p1[3]; (global 4-component vector of float) +0:? Comma (temp 3-element array of texture1D) +0:? Sequence +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 0 (const int) +0:? 'g_tex[0]' (uniform texture1D) +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 1 (const int) +0:? 'g_tex[1]' (uniform texture1D) +0:? move second child to first child (temp texture1D) +0:? direct index (temp texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Constant: +0:? 2 (const int) +0:? 'g_tex[2]' (uniform texture1D) +0:? 'aggShadow' (temp 3-element array of texture1D) +0:? Comma (temp 3-element array of sampler) +0:? Sequence +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 0 (const int) +0:? 'g_samp[0]' (uniform sampler) +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 1 (const int) +0:? 'g_samp[1]' (uniform sampler) +0:? move second child to first child (temp sampler) +0:? direct index (temp sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Constant: +0:? 2 (const int) +0:? 'g_samp[2]' (uniform sampler) +0:? 'aggShadow' (temp 3-element array of sampler) +0:? Linker Objects +0:? 'g_tex[0]' (uniform texture1D) +0:? 'g_tex[1]' (uniform texture1D) +0:? 'g_tex[2]' (uniform texture1D) +0:? 'g_tex_explicit[0]' (layout(binding=1 ) uniform texture1D) +0:? 'g_tex_explicit[1]' (layout(binding=2 ) uniform texture1D) +0:? 'g_tex_explicit[2]' (layout(binding=3 ) uniform texture1D) +0:? 'g_samp[0]' (uniform sampler) +0:? 'g_samp[1]' (uniform sampler) +0:? 'g_samp[2]' (uniform sampler) +0:? 'g_samp_explicit[0]' (layout(binding=5 ) uniform sampler) +0:? 'g_samp_explicit[1]' (layout(binding=6 ) uniform sampler) +0:? 'g_samp_explicit[2]' (layout(binding=7 ) uniform sampler) +0:? 'g_mats[0]' (uniform 3X3 matrix of float) +0:? 'g_mats[1]' (uniform 3X3 matrix of float) +0:? 'g_mats[2]' (uniform 3X3 matrix of float) +0:? 'g_mats[3]' (uniform 3X3 matrix of float) +0:? 'g_mats_explicit[0]' (layout(binding=10 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[1]' (layout(binding=11 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[2]' (layout(binding=12 ) uniform 3X3 matrix of float) +0:? 'g_mats_explicit[3]' (layout(binding=13 ) uniform 3X3 matrix of float) +0:? 'g_floats[0]' (uniform float) +0:? 'g_floats[1]' (uniform float) +0:? 'g_floats[2]' (uniform float) +0:? 'g_floats[3]' (uniform float) +0:? 'not_flattened_a' (global 5-element array of int) +0:? 'color' (layout(location=0 ) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 128 + + Capability Shader + Capability Sampled1D + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 93 + ExecutionMode 4 OriginUpperLeft + Name 4 "main" + Name 9 "TestFn1(" + Name 22 "TestFn2(t11[3];p1[3];" + Name 20 "l_tex" + Name 21 "l_samp" + Name 28 "not_flattened_a" + Name 36 "g_tex[1]" + Name 39 "g_samp[1]" + Name 55 "local_sampler_array" + Name 57 "g_samp[0]" + Name 62 "g_samp[2]" + Name 65 "local_texture_array" + Name 66 "g_tex[0]" + Name 71 "g_tex[2]" + Name 77 "local_float_array" + Name 79 "g_floats[0]" + Name 83 "g_floats[1]" + Name 86 "g_floats[2]" + Name 89 "g_floats[3]" + Name 93 "color" + Name 95 "aggShadow" + Name 102 "aggShadow" + Name 111 "g_tex_explicit[0]" + Name 112 "g_tex_explicit[1]" + Name 113 "g_tex_explicit[2]" + Name 114 "g_samp_explicit[0]" + Name 115 "g_samp_explicit[1]" + Name 116 "g_samp_explicit[2]" + Name 120 "g_mats[0]" + Name 121 "g_mats[1]" + Name 122 "g_mats[2]" + Name 123 "g_mats[3]" + Name 124 "g_mats_explicit[0]" + Name 125 "g_mats_explicit[1]" + Name 126 "g_mats_explicit[2]" + Name 127 "g_mats_explicit[3]" + Decorate 57(g_samp[0]) DescriptorSet 0 + Decorate 62(g_samp[2]) DescriptorSet 0 + Decorate 66(g_tex[0]) DescriptorSet 0 + Decorate 71(g_tex[2]) DescriptorSet 0 + Decorate 93(color) Location 0 + Decorate 111(g_tex_explicit[0]) DescriptorSet 0 + Decorate 111(g_tex_explicit[0]) Binding 1 + Decorate 112(g_tex_explicit[1]) DescriptorSet 0 + Decorate 112(g_tex_explicit[1]) Binding 2 + Decorate 113(g_tex_explicit[2]) DescriptorSet 0 + Decorate 113(g_tex_explicit[2]) Binding 3 + Decorate 114(g_samp_explicit[0]) DescriptorSet 0 + Decorate 114(g_samp_explicit[0]) Binding 5 + Decorate 115(g_samp_explicit[1]) DescriptorSet 0 + Decorate 115(g_samp_explicit[1]) Binding 6 + Decorate 116(g_samp_explicit[2]) DescriptorSet 0 + Decorate 116(g_samp_explicit[2]) Binding 7 + Decorate 124(g_mats_explicit[0]) Binding 10 + Decorate 125(g_mats_explicit[1]) Binding 11 + Decorate 126(g_mats_explicit[2]) Binding 12 + Decorate 127(g_mats_explicit[3]) Binding 13 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeFunction 7(fvec4) + 11: TypeImage 6(float) 1D sampled format:Unknown + 12: TypeInt 32 0 + 13: 12(int) Constant 3 + 14: TypeArray 11 13 + 15: TypePointer UniformConstant 14 + 16: TypeSampler + 17: TypeArray 16 13 + 18: TypePointer UniformConstant 17 + 19: TypeFunction 7(fvec4) 15(ptr) 18(ptr) + 24: TypeInt 32 1 + 25: 12(int) Constant 5 + 26: TypeArray 24(int) 25 + 27: TypePointer Private 26 +28(not_flattened_a): 27(ptr) Variable Private + 29: 24(int) Constant 1 + 30: 24(int) Constant 2 + 31: 24(int) Constant 3 + 32: 24(int) Constant 4 + 33: 24(int) Constant 5 + 34: 26 ConstantComposite 29 30 31 32 33 + 35: TypePointer UniformConstant 11 + 36(g_tex[1]): 35(ptr) Variable UniformConstant + 38: TypePointer UniformConstant 16 + 39(g_samp[1]): 38(ptr) Variable UniformConstant + 41: TypeSampledImage 11 + 43: 6(float) Constant 1045220557 +55(local_sampler_array): 18(ptr) Variable UniformConstant + 56: 24(int) Constant 0 + 57(g_samp[0]): 38(ptr) Variable UniformConstant + 62(g_samp[2]): 38(ptr) Variable UniformConstant +65(local_texture_array): 15(ptr) Variable UniformConstant + 66(g_tex[0]): 35(ptr) Variable UniformConstant + 71(g_tex[2]): 35(ptr) Variable UniformConstant + 74: 12(int) Constant 4 + 75: TypeArray 6(float) 74 + 76: TypePointer Function 75 + 78: TypePointer UniformConstant 6(float) + 79(g_floats[0]): 78(ptr) Variable UniformConstant + 81: TypePointer Function 6(float) + 83(g_floats[1]): 78(ptr) Variable UniformConstant + 86(g_floats[2]): 78(ptr) Variable UniformConstant + 89(g_floats[3]): 78(ptr) Variable UniformConstant + 92: TypePointer Output 7(fvec4) + 93(color): 92(ptr) Variable Output + 95(aggShadow): 15(ptr) Variable UniformConstant + 102(aggShadow): 18(ptr) Variable UniformConstant +111(g_tex_explicit[0]): 35(ptr) Variable UniformConstant +112(g_tex_explicit[1]): 35(ptr) Variable UniformConstant +113(g_tex_explicit[2]): 35(ptr) Variable UniformConstant +114(g_samp_explicit[0]): 38(ptr) Variable UniformConstant +115(g_samp_explicit[1]): 38(ptr) Variable UniformConstant +116(g_samp_explicit[2]): 38(ptr) Variable UniformConstant + 117: TypeVector 6(float) 3 + 118: TypeMatrix 117(fvec3) 3 + 119: TypePointer UniformConstant 118 + 120(g_mats[0]): 119(ptr) Variable UniformConstant + 121(g_mats[1]): 119(ptr) Variable UniformConstant + 122(g_mats[2]): 119(ptr) Variable UniformConstant + 123(g_mats[3]): 119(ptr) Variable UniformConstant +124(g_mats_explicit[0]): 119(ptr) Variable UniformConstant +125(g_mats_explicit[1]): 119(ptr) Variable UniformConstant +126(g_mats_explicit[2]): 119(ptr) Variable UniformConstant +127(g_mats_explicit[3]): 119(ptr) Variable UniformConstant + 4(main): 2 Function None 3 + 5: Label +77(local_float_array): 76(ptr) Variable Function + Store 28(not_flattened_a) 34 + 58: 16 Load 57(g_samp[0]) + 59: 38(ptr) AccessChain 55(local_sampler_array) 56 + Store 59 58 + 60: 16 Load 39(g_samp[1]) + 61: 38(ptr) AccessChain 55(local_sampler_array) 29 + Store 61 60 + 63: 16 Load 62(g_samp[2]) + 64: 38(ptr) AccessChain 55(local_sampler_array) 30 + Store 64 63 + 67: 11 Load 66(g_tex[0]) + 68: 35(ptr) AccessChain 65(local_texture_array) 56 + Store 68 67 + 69: 11 Load 36(g_tex[1]) + 70: 35(ptr) AccessChain 65(local_texture_array) 29 + Store 70 69 + 72: 11 Load 71(g_tex[2]) + 73: 35(ptr) AccessChain 65(local_texture_array) 30 + Store 73 72 + 80: 6(float) Load 79(g_floats[0]) + 82: 81(ptr) AccessChain 77(local_float_array) 56 + Store 82 80 + 84: 6(float) Load 83(g_floats[1]) + 85: 81(ptr) AccessChain 77(local_float_array) 29 + Store 85 84 + 87: 6(float) Load 86(g_floats[2]) + 88: 81(ptr) AccessChain 77(local_float_array) 30 + Store 88 87 + 90: 6(float) Load 89(g_floats[3]) + 91: 81(ptr) AccessChain 77(local_float_array) 31 + Store 91 90 + 94: 7(fvec4) FunctionCall 9(TestFn1() + 96: 11 Load 66(g_tex[0]) + 97: 35(ptr) AccessChain 95(aggShadow) 56 + Store 97 96 + 98: 11 Load 36(g_tex[1]) + 99: 35(ptr) AccessChain 95(aggShadow) 29 + Store 99 98 + 100: 11 Load 71(g_tex[2]) + 101: 35(ptr) AccessChain 95(aggShadow) 30 + Store 101 100 + 103: 16 Load 57(g_samp[0]) + 104: 38(ptr) AccessChain 102(aggShadow) 56 + Store 104 103 + 105: 16 Load 39(g_samp[1]) + 106: 38(ptr) AccessChain 102(aggShadow) 29 + Store 106 105 + 107: 16 Load 62(g_samp[2]) + 108: 38(ptr) AccessChain 102(aggShadow) 30 + Store 108 107 + 109: 7(fvec4) FunctionCall 22(TestFn2(t11[3];p1[3];) 95(aggShadow) 102(aggShadow) + 110: 7(fvec4) FAdd 94 109 + Store 93(color) 110 + Return + FunctionEnd + 9(TestFn1(): 7(fvec4) Function None 8 + 10: Label + 37: 11 Load 36(g_tex[1]) + 40: 16 Load 39(g_samp[1]) + 42: 41 SampledImage 37 40 + 44: 7(fvec4) ImageSampleImplicitLod 42 43 + ReturnValue 44 + FunctionEnd +22(TestFn2(t11[3];p1[3];): 7(fvec4) Function None 19 + 20(l_tex): 15(ptr) FunctionParameter + 21(l_samp): 18(ptr) FunctionParameter + 23: Label + 47: 35(ptr) AccessChain 20(l_tex) 30 + 48: 11 Load 47 + 49: 38(ptr) AccessChain 21(l_samp) 30 + 50: 16 Load 49 + 51: 41 SampledImage 48 50 + 52: 7(fvec4) ImageSampleImplicitLod 51 43 + ReturnValue 52 + FunctionEnd diff --git a/Test/hlsl.array.flatten.frag b/Test/hlsl.array.flatten.frag new file mode 100644 index 0000000000000000000000000000000000000000..b243bec27dfe932d0f181887f738c6d28a12fd46 --- /dev/null +++ b/Test/hlsl.array.flatten.frag @@ -0,0 +1,38 @@ + +// uniform Texture1D g_tex3[3][2]; // TODO: legal in HLSL, but we don't handle it yet. + +uniform Texture1D g_tex[3]; +uniform Texture1D g_tex_explicit[3] : register(t1); + +SamplerState g_samp[3]; +SamplerState g_samp_explicit[3] : register(s5); + +uniform float3x3 g_mats[4]; +uniform float3x3 g_mats_explicit[4] : register(b10); +uniform float g_floats[4]; + +// uniform float g_floats[4] = { 10, 11, 12, 13 }; // TODO: ... add when initializer lists can be flattened. + +float4 TestFn1() +{ + return g_tex[1].Sample(g_samp[1], 0.2); +} + +float4 TestFn2(Texture1D l_tex[3], SamplerState l_samp[3]) +{ + return l_tex[2].Sample(l_samp[2], 0.2); +} + +int not_flattened_a[5] = { 1, 2, 3, 4, 5 }; + +struct PS_OUTPUT { float4 color : SV_Target0; }; + +void main(out PS_OUTPUT ps_output) +{ + // test flattening for local assignment initialization + SamplerState local_sampler_array[3] = g_samp; + Texture1D local_texture_array[3] = g_tex; + float local_float_array[4] = g_floats; + + ps_output.color = TestFn1() + TestFn2(g_tex, g_samp); +} diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 677cef39535ea0744abf4560ad239b6e3bd7c8b5..a0bee74e7aa8a496edf5a8c5b668b8d641bfd3d2 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -424,6 +424,11 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt // opaque types can be passed to functions if (op == EOpFunction) break; + + // HLSL can assign samplers directly (no constructor) + if (source == EShSourceHlsl && node->getBasicType() == EbtSampler) + break; + // samplers can get assigned via a sampler constructor // (well, not yet, but code in the rest of this function is ready for it) if (node->getBasicType() == EbtSampler && op == EOpAssign && diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index dc0c01b6f0d4d70d52b2812c4665fb6c7c1f3db1..ffd6b00c1465a65dfbdd0e156cf3cf0a2d25ac96 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -1493,6 +1493,8 @@ void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShift void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); } void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); } void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); } +void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); } + // // Turn the shader strings into a parse tree in the TIntermediate. // diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 4de811cff41b048f40b1edde7e5d157249dd7475..14b8a00a2c947a742ed71633098b6ab4c46654ba 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -145,7 +145,8 @@ public: shiftSamplerBinding(0), shiftTextureBinding(0), shiftUboBinding(0), - autoMapBindings(false) + autoMapBindings(false), + flattenUniformArrays(false) { localSize[0] = 1; localSize[1] = 1; @@ -176,6 +177,8 @@ public: unsigned int getShiftUboBinding() const { return shiftUboBinding; } void setAutoMapBindings(bool map) { autoMapBindings = map; } bool getAutoMapBindings() const { return autoMapBindings; } + void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; } + bool getFlattenUniformArrays() const { return flattenUniformArrays; } void setVersion(int v) { version = v; } int getVersion() const { return version; } @@ -385,6 +388,7 @@ protected: unsigned int shiftTextureBinding; unsigned int shiftUboBinding; bool autoMapBindings; + bool flattenUniformArrays; EProfile profile; int version; diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 80605ba336f2de9830f2092b1f9a846550931ce9..496e6d4dacf7c3c1d279798ff5d8dd261f38689d 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -304,6 +304,7 @@ public: void setShiftTextureBinding(unsigned int base); void setShiftUboBinding(unsigned int base); void setAutoMapBindings(bool map); + void setFlattenUniformArrays(bool flatten); // Interface to #include handlers. // diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 01cc0323edd7e5e130f88c354cc54a05a2e8f091..55450a74d5a7585723a1c2cd60ed419148e0bd95 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -58,6 +58,7 @@ std::string FileNameAsCustomTestSuffix( } using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>; +using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>; // Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully // generate both AST and SPIR-V. @@ -68,6 +69,13 @@ TEST_P(HlslCompileTest, FromFile) Target::BothASTAndSpv, GetParam().entryPoint); } +TEST_P(HlslCompileAndFlattenTest, FromFile) +{ + loadFileCompileFlattenUniformsAndCheck(GLSLANG_TEST_DIRECTORY, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, + Target::BothASTAndSpv, GetParam().entryPoint); +} + // clang-format off INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, @@ -181,5 +189,15 @@ INSTANTIATE_TEST_CASE_P( ); // clang-format on +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslCompileAndFlattenTest, + ::testing::ValuesIn(std::vector<FileNameEntryPointPair>{ + {"hlsl.array.flatten.frag", "main"}, + }), + FileNameAsCustomTestSuffix +); + +// clang-format on } // anonymous namespace } // namespace glslangtest diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index 47e2703aec5318441db32001659b400c07c00e79..4b364c4b21dc3e7954b2da4b5322b9cc2bd35224 100644 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -204,11 +204,14 @@ public: // the result and returns disassembly text. GlslangResult compileAndLink( const std::string shaderName, const std::string& code, - const std::string& entryPointName, EShMessages controls) + const std::string& entryPointName, EShMessages controls, + bool flattenUniformArrays = false) { const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); glslang::TShader shader(kind); + shader.setFlattenUniformArrays(flattenUniformArrays); + bool success = compile(&shader, code, entryPointName, controls); glslang::TProgram program; @@ -395,6 +398,32 @@ public: expectedOutputFname); } + void loadFileCompileFlattenUniformsAndCheck(const std::string& testDir, + const std::string& testName, + Source source, + Semantics semantics, + Target target, + const std::string& entryPointName="") + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + const EShMessages controls = DeriveOptions(source, semantics, target); + GlslangResult result = compileAndLink(testName, input, entryPointName, controls, true); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + void loadFileCompileIoMapAndCheck(const std::string& testDir, const std::string& testName, Source source, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 5af79040092deddaea61449c9f13004c19eb98b9..d5db6b23e8e86a22822b9f9deb15ee23eaeebb08 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -403,12 +403,19 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) handleIoResizeArrayAccess(loc, base); - if (index->getQualifier().storage == EvqConst) { - if (base->getType().isImplicitlySizedArray()) - updateImplicitArraySize(loc, base, indexValue); - result = intermediate.addIndex(EOpIndexDirect, base, index, loc); + if (base->getAsSymbolNode() && 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); } else { - result = intermediate.addIndex(EOpIndexIndirect, base, index, loc); + if (index->getQualifier().storage == EvqConst) { + if (base->getType().isImplicitlySizedArray()) + updateImplicitArraySize(loc, base, indexValue); + result = intermediate.addIndex(EOpIndexDirect, base, index, loc); + } else { + result = intermediate.addIndex(EOpIndexIndirect, base, index, loc); + } } } @@ -701,9 +708,9 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt return result; } -// Is this an aggregate that can't be passed down the stack? +// 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::shouldFlatten(const TType& type) const +bool HlslParseContext::shouldFlattenIO(const TType& type) const { if (! inEntryPoint) return false; @@ -715,6 +722,33 @@ bool HlslParseContext::shouldFlatten(const TType& type) const qualifier == EvqVaryingOut); } +// Is this a uniform array which should be flattened? +bool HlslParseContext::shouldFlattenUniform(const TType& type) const +{ + const TStorageQualifier qualifier = type.getQualifier().storage; + + return type.isArray() && + intermediate.getFlattenUniformArrays() && + qualifier == EvqUniform; +} + +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(), ""); + } + + if (type.isStruct()) + flattenStruct(variable); + + if (type.isArray()) + flattenArray(loc, variable); +} + // Figure out the mapping between an aggregate's top members and an // equivalent set of individual variables. // @@ -724,7 +758,7 @@ bool HlslParseContext::shouldFlatten(const TType& type) const // Assumes shouldFlatten() or equivalent was called first. // // TODO: generalize this to arbitrary nesting? -void HlslParseContext::flatten(const TVariable& variable) +void HlslParseContext::flattenStruct(const TVariable& variable) { TVector<TVariable*> memberVariables; @@ -742,8 +776,54 @@ void HlslParseContext::flatten(const TVariable& variable) flattenMap[variable.getUniqueId()] = memberVariables; } -// Turn an access into aggregate that was flattened to instead be -// an access to the individual variable the element/member was flattened to. +// 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) +{ + 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<TVariable*> memberVariables; + + 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(), ""); + } + + 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; + + 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); + intermediate.addSymbolLinkageNode(linkage, *memberVariable); + } + + flattenMap[variable.getUniqueId()] = memberVariables; +} + +// 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) { @@ -864,7 +944,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l remapEntryPointIO(function); if (entryPointOutput) { if (shouldFlatten(entryPointOutput->getType())) - flatten(*entryPointOutput); + flatten(loc, *entryPointOutput); assignLocations(*entryPointOutput); } } else @@ -896,7 +976,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l // get IO straightened out if (inEntryPoint) { if (shouldFlatten(*param.type)) - flatten(*variable); + flatten(loc, *variable); assignLocations(*variable); } @@ -1051,40 +1131,68 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op flattenMap.find(node.getAsSymbolNode()->getId()) != flattenMap.end(); }; - bool flattenLeft = mustFlatten(*left); - bool flattenRight = mustFlatten(*right); + const bool flattenLeft = mustFlatten(*left); + const bool flattenRight = mustFlatten(*right); if (! flattenLeft && ! flattenRight) return intermediate.addAssign(op, left, right, loc); - // 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(); + TIntermAggregate* assignList = nullptr; + const TVector<TVariable*>* leftVariables = nullptr; + const TVector<TVariable*>* rightVariables = nullptr; + + if (flattenLeft) + leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second; + if (flattenRight) + rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second; + const auto getMember = [&](bool flatten, TIntermTyped* node, - const TVector<TVariable*>& memberVariables, int member) { + const TVector<TVariable*>& memberVariables, int member, + TOperator op, const TType& memberType) { TIntermTyped* subTree; if (flatten) subTree = intermediate.addSymbol(*memberVariables[member]); else { - subTree = intermediate.addIndex(EOpIndexDirectStruct, node, - intermediate.addConstantUnion(member, loc), loc); - subTree->setType(*members[member].type); + subTree = intermediate.addIndex(op, node, intermediate.addConstantUnion(member, loc), loc); + subTree->setType(memberType); } return subTree; }; - - const TVector<TVariable*>* leftVariables = nullptr; - const TVector<TVariable*>* rightVariables = nullptr; - if (flattenLeft) - leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second; - if (flattenRight) - rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second; - TIntermAggregate* assignList = nullptr; - for (int member = 0; member < (int)members.size(); ++member) { - TIntermTyped* subRight = getMember(flattenRight, right, *rightVariables, member); - TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, member); - assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc)); + + // 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(); + + 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); + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, 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); + const int size = left->getType().getCumulativeArraySize(); + + for (int element=0; element < size; ++element) { + TIntermTyped* subRight = getMember(flattenRight, right, *rightVariables, element, + EOpIndexDirect, dereferencedType); + TIntermTyped* subLeft = getMember(flattenLeft, left, *leftVariables, element, + EOpIndexDirect, dereferencedType); + + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc)); + } } + + assert(assignList != nullptr); assignList->setOperator(EOpSequence); return assignList; @@ -4095,13 +4203,21 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i inheritGlobalDefaults(type.getQualifier()); + bool flattenVar = false; + // Declare the variable if (arraySizes || type.isArray()) { // Arrayness is potentially coming both from the type and from the // variable: "int[] a[];" or just one or the other. // Merge it all to the type, so all arrayness is part of the type. - arrayDimMerge(type, arraySizes); + arrayDimMerge(type, arraySizes); // Safe if there are no arraySizes + declareArray(loc, identifier, type, symbol, newDeclaration); + + flattenVar = shouldFlatten(type); + + if (flattenVar) + flatten(loc, *symbol->getAsVariable()); } else { // non-array case if (! symbol) @@ -4116,6 +4232,9 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i // 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) { error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); @@ -4124,9 +4243,12 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i initNode = executeInitializer(loc, initializer, variable); } - // see if it's a linker-level object to track - if (newDeclaration && symbolTable.atGlobalLevel()) - intermediate.addSymbolLinkageNode(linkage, *symbol); + // see if it's a linker-level object to track. if it's flattened above, + // that process added linkage objects for the flattened symbols, we don't + // add the aggregate here. + if (!flattenVar) + if (newDeclaration && symbolTable.atGlobalLevel()) + intermediate.addSymbolLinkageNode(linkage, *symbol); return initNode; } @@ -4257,7 +4379,7 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // normal assigning of a value to a variable... specializationCheck(loc, initializer->getType(), "initializer"); TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc); - TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc); + TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer); if (! initNode) assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 0162088321b0be323de6af52c67be1a3364c922f..b7d332370622123a2f41f7838a1620434ae2c7bc 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -83,9 +83,6 @@ public: TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); - bool shouldFlatten(const TType&) const; - void flatten(const TVariable& variable); - TIntermTyped* flattenAccess(TIntermTyped* base, int member); void assignLocations(TVariable& variable); TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); @@ -181,6 +178,15 @@ protected: const char* szExtraInfoFormat, TPrefixType prefix, va_list args); + // Array and struct flattening + bool shouldFlatten(const TType& type) const { return shouldFlattenIO(type) || shouldFlattenUniform(type); } + TIntermTyped* flattenAccess(TIntermTyped* base, int member); + bool shouldFlattenIO(const TType&) const; + bool shouldFlattenUniform(const TType&) const; + void flatten(const TSourceLoc& loc, const TVariable& variable); + void flattenStruct(const TVariable& variable); + void flattenArray(const TSourceLoc& loc, const TVariable& variable); + // Current state of parsing struct TPragma contextPragma; int loopNestingLevel; // 0 if outside all loops