1
0
mirror of https://github.com/RPCS3/glslang.git synced 2025-01-24 12:04:57 +00:00

HLSL: Merge pull request from steve-lunarg/flatten-uniform-array

HLSL: Flatten uniform arrays
This commit is contained in:
John Kessenich 2016-09-22 10:01:37 -06:00 committed by GitHub
commit 4455258a08
11 changed files with 872 additions and 46 deletions

@ -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);

@ -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

@ -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);
}

@ -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 &&

@ -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.
//

@ -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;

@ -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.
//

@ -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

@ -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,

@ -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();
const auto getMember = [&](bool flatten, TIntermTyped* node,
const TVector<TVariable*>& memberVariables, int member) {
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);
}
return subTree;
};
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;
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));
const auto getMember = [&](bool flatten, TIntermTyped* node,
const TVector<TVariable*>& memberVariables, int member,
TOperator op, const TType& memberType) {
TIntermTyped* subTree;
if (flatten)
subTree = intermediate.addSymbol(*memberVariables[member]);
else {
subTree = intermediate.addIndex(op, node, intermediate.addConstantUnion(member, loc), loc);
subTree->setType(memberType);
}
return subTree;
};
// 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());

@ -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