EOptionReadHlsl = (1 << 17),
EOptionCascadingErrors = (1 << 18),
EOptionAutoMapBindings = (1 << 19),
+ EOptionFlattenUniformArrays = (1 << 20),
};
//
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();
}
// -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.");
}
//
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);
" --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);
--- /dev/null
+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
--- /dev/null
+
+// 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);
+}
// 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 &&
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.
//
shiftSamplerBinding(0),
shiftTextureBinding(0),
shiftUboBinding(0),
- autoMapBindings(false)
+ autoMapBindings(false),
+ flattenUniformArrays(false)
{
localSize[0] = 1;
localSize[1] = 1;
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; }
unsigned int shiftTextureBinding;
unsigned int shiftUboBinding;
bool autoMapBindings;
+ bool flattenUniformArrays;
EProfile profile;
int version;
void setShiftTextureBinding(unsigned int base);
void setShiftUboBinding(unsigned int base);
void setAutoMapBindings(bool map);
+ void setFlattenUniformArrays(bool flatten);
// Interface to #include handlers.
//
}
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.
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,
);
// 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
// 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;
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,
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);
+ }
}
}
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;
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.
//
// 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;
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)
{
remapEntryPointIO(function);
if (entryPointOutput) {
if (shouldFlatten(entryPointOutput->getType()))
- flatten(*entryPointOutput);
+ flatten(loc, *entryPointOutput);
assignLocations(*entryPointOutput);
}
} else
// get IO straightened out
if (inEntryPoint) {
if (shouldFlatten(*param.type))
- flatten(*variable);
+ flatten(loc, *variable);
assignLocations(*variable);
}
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;
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)
// 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(), "");
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;
}
// 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());
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&);
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