HLSL: add methods to track user structure in texture return type.
authorLoopDawg <sk_opengl@khasekhemwy.net>
Mon, 31 Jul 2017 19:41:42 +0000 (13:41 -0600)
committerLoopDawg <sk_opengl@khasekhemwy.net>
Tue, 15 Aug 2017 22:40:21 +0000 (16:40 -0600)
Some languages allow a restricted set of user structure types returned from texture sampling
operations.  Restrictions include the total vector size of all components may not exceed 4,
and the basic types of all members must be identical.

This adds underpinnings for that ability.  Because storing a whole TType or even a simple
TTypeList in the TSampler would be expensive, the structure definition is held in a
table outside the TType.  The TSampler contains a small bitfield index, currently 4 bits
to support up to 15 separate texture template structure types, but that can be adjusted
up or down.  Vector returns are handled as before.

There are abstraction methods accepting and returning a TType (such as may have been parsed
from a grammar).  The new methods will accept a texture template type and set the
sampler to the structure if possible, checking a range of error conditions such as whether
the total structure vector components exceed 4, or whether their basic types differe, or
whether the struct contains non-vector-or-scalar members.  Another query returns the
appropriate TType for the sampler.

High level summary of design:

In the TSampler, this holds an index into the texture structure return type table:

    unsigned int structReturnIndex : structReturnIndexBits;

These are the methods to set or get the return type from the TSampler.  They work for vector or structure returns, and potentially could be expanded to handle other things (small arrays?) if ever needed.

    bool setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc);
    void getTextureReturnType(const TSampler& sampler, const TType& retType, const TSourceLoc& loc) const;

The ``convertReturn`` lambda in ``HlslParseContext::decomposeSampleMethods`` is greatly expanded to know how to copy a vec4 sample return to whatever the structure type should be.  This is a little awkward since it involves introducing a comma expression to return the proper aggregate value after a set of memberwise copies.

Test/baseResults/hlsl.texture.struct.frag.out [new file with mode: 0644]
Test/hlsl.texture.struct.frag [new file with mode: 0644]
Test/hlsl.texture.subvec4.frag
glslang/Include/Types.h
glslang/MachineIndependent/SymbolTable.cpp
gtests/Hlsl.FromFile.cpp
hlsl/hlslGrammar.cpp
hlsl/hlslParseHelper.cpp
hlsl/hlslParseHelper.h

diff --git a/Test/baseResults/hlsl.texture.struct.frag.out b/Test/baseResults/hlsl.texture.struct.frag.out
new file mode 100644 (file)
index 0000000..09af451
--- /dev/null
@@ -0,0 +1,1184 @@
+hlsl.texture.struct.frag
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:38  Function Definition: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38    Function Parameters: 
+0:38      't1' ( in texture2D)
+0:?     Sequence
+0:38      Branch: Return with expression
+0:38        Sequence
+0:38          move second child to first child ( temp 4-component vector of float)
+0:38            '@sampleResultShadow' ( temp 4-component vector of float)
+0:?             texture ( temp 4-component vector of float)
+0:38              Construct combined texture-sampler ( temp sampler2D)
+0:38                't1' ( in texture2D)
+0:38                'g_sSamp' ( uniform sampler)
+0:?               Constant:
+0:?                 0.600000
+0:?                 0.610000
+0:38          move second child to first child ( temp float)
+0:38            c0: direct index for structure ( temp float)
+0:38              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38              Constant:
+0:38                0 (const uint)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                0 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            direct index ( temp float)
+0:38              c1: direct index for structure ( temp 2-component vector of float)
+0:38                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38                Constant:
+0:38                  1 (const uint)
+0:38              Constant:
+0:38                0 (const int)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                1 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            direct index ( temp float)
+0:38              c1: direct index for structure ( temp 2-component vector of float)
+0:38                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38                Constant:
+0:38                  1 (const uint)
+0:38              Constant:
+0:38                1 (const int)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                2 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            c2: direct index for structure ( temp float)
+0:38              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38              Constant:
+0:38                2 (const uint)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                3 (const uint)
+0:38          '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:39  Function Definition: fn1(t2-tx-struct1-1; ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39    Function Parameters: 
+0:39      't2' ( in texture2D)
+0:?     Sequence
+0:39      Branch: Return with expression
+0:39        Sequence
+0:39          move second child to first child ( temp 4-component vector of float)
+0:39            '@sampleResultShadow' ( temp 4-component vector of float)
+0:?             texture ( temp 4-component vector of float)
+0:39              Construct combined texture-sampler ( temp sampler2D)
+0:39                't2' ( in texture2D)
+0:39                'g_sSamp' ( uniform sampler)
+0:?               Constant:
+0:?                 0.600000
+0:?                 0.610000
+0:39          move second child to first child ( temp float)
+0:39            c0: direct index for structure ( temp float)
+0:39              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39              Constant:
+0:39                0 (const uint)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                0 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                0 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                1 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                1 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                2 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                2 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                3 (const uint)
+0:39          '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:42  Function Definition: @main( ( temp 4-component vector of float)
+0:42    Function Parameters: 
+0:?     Sequence
+0:43      Sequence
+0:43        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43          's1' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43          Sequence
+0:43            move second child to first child ( temp 4-component vector of float)
+0:43              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:43                Construct combined texture-sampler ( temp sampler2D)
+0:43                  'g_tTex2s1' ( uniform texture2D)
+0:43                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.100000
+0:?                   0.110000
+0:43            move second child to first child ( temp float)
+0:43              c0: direct index for structure ( temp float)
+0:43                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                Constant:
+0:43                  0 (const uint)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  0 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              direct index ( temp float)
+0:43                c1: direct index for structure ( temp 2-component vector of float)
+0:43                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                  Constant:
+0:43                    1 (const uint)
+0:43                Constant:
+0:43                  0 (const int)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  1 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              direct index ( temp float)
+0:43                c1: direct index for structure ( temp 2-component vector of float)
+0:43                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                  Constant:
+0:43                    1 (const uint)
+0:43                Constant:
+0:43                  1 (const int)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  2 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              c2: direct index for structure ( temp float)
+0:43                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                Constant:
+0:43                  2 (const uint)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  3 (const uint)
+0:43            '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:44      Sequence
+0:44        move second child to first child ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44          's2' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44          Sequence
+0:44            move second child to first child ( temp 4-component vector of float)
+0:44              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:44                Construct combined texture-sampler ( temp sampler2D)
+0:44                  'g_tTex2s2' ( uniform texture2D)
+0:44                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.200000
+0:?                   0.210000
+0:44            move second child to first child ( temp float)
+0:44              c0: direct index for structure ( temp float)
+0:44                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                Constant:
+0:44                  0 (const uint)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  0 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  0 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  1 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  1 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  2 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  2 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  3 (const uint)
+0:44            '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:45      Sequence
+0:45        move second child to first child ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45          's3' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45          Sequence
+0:45            move second child to first child ( temp 4-component vector of float)
+0:45              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:45                Construct combined texture-sampler ( temp sampler2D)
+0:45                  'g_tTex2s3' ( uniform texture2D)
+0:45                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.300000
+0:?                   0.310000
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c0: direct index for structure ( temp 2-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    0 (const uint)
+0:45                Constant:
+0:45                  0 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  0 (const uint)
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c0: direct index for structure ( temp 2-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    0 (const uint)
+0:45                Constant:
+0:45                  1 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  1 (const uint)
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c1: direct index for structure ( temp 1-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    1 (const uint)
+0:45                Constant:
+0:45                  0 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  2 (const uint)
+0:45            '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:46      Sequence
+0:46        move second child to first child ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46          's4' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46          Sequence
+0:46            move second child to first child ( temp 4-component vector of int)
+0:46              '@sampleResultShadow' ( temp 4-component vector of int)
+0:?               texture ( temp 4-component vector of int)
+0:46                Construct combined texture-sampler ( temp isampler2D)
+0:46                  'g_tTex2s4' ( uniform itexture2D)
+0:46                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.400000
+0:?                   0.410000
+0:46            move second child to first child ( temp int)
+0:46              c0: direct index for structure ( temp int)
+0:46                '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                Constant:
+0:46                  0 (const uint)
+0:46              direct index ( temp int)
+0:46                '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                Constant:
+0:46                  0 (const uint)
+0:46            move second child to first child ( temp float)
+0:46              direct index ( temp float)
+0:46                c1: direct index for structure ( temp 2-component vector of int)
+0:46                  '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46                Constant:
+0:46                  0 (const int)
+0:46              Convert int to float ( temp float)
+0:46                direct index ( temp int)
+0:46                  '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46            move second child to first child ( temp float)
+0:46              direct index ( temp float)
+0:46                c1: direct index for structure ( temp 2-component vector of int)
+0:46                  '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46                Constant:
+0:46                  1 (const int)
+0:46              Convert int to float ( temp float)
+0:46                direct index ( temp int)
+0:46                  '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                  Constant:
+0:46                    2 (const uint)
+0:46            move second child to first child ( temp int)
+0:46              c2: direct index for structure ( temp int)
+0:46                '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                Constant:
+0:46                  2 (const uint)
+0:46              direct index ( temp int)
+0:46                '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                Constant:
+0:46                  3 (const uint)
+0:46            '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:47      Sequence
+0:47        move second child to first child ( temp structure{ temp uint c0,  temp uint c1})
+0:47          's5' ( temp structure{ temp uint c0,  temp uint c1})
+0:47          Sequence
+0:47            move second child to first child ( temp 4-component vector of uint)
+0:47              '@sampleResultShadow' ( temp 4-component vector of uint)
+0:?               texture ( temp 4-component vector of uint)
+0:47                Construct combined texture-sampler ( temp usampler2D)
+0:47                  'g_tTex2s5' ( uniform utexture2D)
+0:47                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.500000
+0:?                   0.510000
+0:47            move second child to first child ( temp uint)
+0:47              c0: direct index for structure ( temp uint)
+0:47                '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:47                Constant:
+0:47                  0 (const uint)
+0:47              direct index ( temp uint)
+0:47                '@sampleResultShadow' ( temp 4-component vector of uint)
+0:47                Constant:
+0:47                  0 (const uint)
+0:47            move second child to first child ( temp uint)
+0:47              c1: direct index for structure ( temp uint)
+0:47                '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:47                Constant:
+0:47                  1 (const uint)
+0:47              direct index ( temp uint)
+0:47                '@sampleResultShadow' ( temp 4-component vector of uint)
+0:47                Constant:
+0:47                  1 (const uint)
+0:47            '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:49      Sequence
+0:49        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49          'r0' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49          Function Call: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49            'g_tTex2s1' ( uniform texture2D)
+0:50      Sequence
+0:50        move second child to first child ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50          'r1' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50          Function Call: fn1(t2-tx-struct1-1; ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50            'g_tTex2s2' ( uniform texture2D)
+0:51      Sequence
+0:51        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51          'r2' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51          Function Call: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51            'g_tTex2s1a' ( uniform texture2D)
+0:53      Branch: Return with expression
+0:53        Constant:
+0:53          0.000000
+0:53          0.000000
+0:53          0.000000
+0:53          0.000000
+0:42  Function Definition: main( ( temp void)
+0:42    Function Parameters: 
+0:?     Sequence
+0:42      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:42        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_sSamp' ( uniform sampler)
+0:?     'g_tTex2s1' ( uniform texture2D)
+0:?     'g_tTex2s2' ( uniform texture2D)
+0:?     'g_tTex2s3' ( uniform texture2D)
+0:?     'g_tTex2s4' ( uniform itexture2D)
+0:?     'g_tTex2s5' ( uniform utexture2D)
+0:?     'g_tTex2s1a' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:38  Function Definition: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38    Function Parameters: 
+0:38      't1' ( in texture2D)
+0:?     Sequence
+0:38      Branch: Return with expression
+0:38        Sequence
+0:38          move second child to first child ( temp 4-component vector of float)
+0:38            '@sampleResultShadow' ( temp 4-component vector of float)
+0:?             texture ( temp 4-component vector of float)
+0:38              Construct combined texture-sampler ( temp sampler2D)
+0:38                't1' ( in texture2D)
+0:38                'g_sSamp' ( uniform sampler)
+0:?               Constant:
+0:?                 0.600000
+0:?                 0.610000
+0:38          move second child to first child ( temp float)
+0:38            c0: direct index for structure ( temp float)
+0:38              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38              Constant:
+0:38                0 (const uint)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                0 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            direct index ( temp float)
+0:38              c1: direct index for structure ( temp 2-component vector of float)
+0:38                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38                Constant:
+0:38                  1 (const uint)
+0:38              Constant:
+0:38                0 (const int)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                1 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            direct index ( temp float)
+0:38              c1: direct index for structure ( temp 2-component vector of float)
+0:38                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38                Constant:
+0:38                  1 (const uint)
+0:38              Constant:
+0:38                1 (const int)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                2 (const uint)
+0:38          move second child to first child ( temp float)
+0:38            c2: direct index for structure ( temp float)
+0:38              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:38              Constant:
+0:38                2 (const uint)
+0:38            direct index ( temp float)
+0:38              '@sampleResultShadow' ( temp 4-component vector of float)
+0:38              Constant:
+0:38                3 (const uint)
+0:38          '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:39  Function Definition: fn1(t2-tx-struct1-1; ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39    Function Parameters: 
+0:39      't2' ( in texture2D)
+0:?     Sequence
+0:39      Branch: Return with expression
+0:39        Sequence
+0:39          move second child to first child ( temp 4-component vector of float)
+0:39            '@sampleResultShadow' ( temp 4-component vector of float)
+0:?             texture ( temp 4-component vector of float)
+0:39              Construct combined texture-sampler ( temp sampler2D)
+0:39                't2' ( in texture2D)
+0:39                'g_sSamp' ( uniform sampler)
+0:?               Constant:
+0:?                 0.600000
+0:?                 0.610000
+0:39          move second child to first child ( temp float)
+0:39            c0: direct index for structure ( temp float)
+0:39              '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39              Constant:
+0:39                0 (const uint)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                0 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                0 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                1 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                1 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                2 (const uint)
+0:39          move second child to first child ( temp float)
+0:39            direct index ( temp float)
+0:39              c1: direct index for structure ( temp 3-component vector of float)
+0:39                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:39                Constant:
+0:39                  1 (const uint)
+0:39              Constant:
+0:39                2 (const int)
+0:39            direct index ( temp float)
+0:39              '@sampleResultShadow' ( temp 4-component vector of float)
+0:39              Constant:
+0:39                3 (const uint)
+0:39          '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:42  Function Definition: @main( ( temp 4-component vector of float)
+0:42    Function Parameters: 
+0:?     Sequence
+0:43      Sequence
+0:43        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43          's1' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43          Sequence
+0:43            move second child to first child ( temp 4-component vector of float)
+0:43              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:43                Construct combined texture-sampler ( temp sampler2D)
+0:43                  'g_tTex2s1' ( uniform texture2D)
+0:43                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.100000
+0:?                   0.110000
+0:43            move second child to first child ( temp float)
+0:43              c0: direct index for structure ( temp float)
+0:43                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                Constant:
+0:43                  0 (const uint)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  0 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              direct index ( temp float)
+0:43                c1: direct index for structure ( temp 2-component vector of float)
+0:43                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                  Constant:
+0:43                    1 (const uint)
+0:43                Constant:
+0:43                  0 (const int)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  1 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              direct index ( temp float)
+0:43                c1: direct index for structure ( temp 2-component vector of float)
+0:43                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                  Constant:
+0:43                    1 (const uint)
+0:43                Constant:
+0:43                  1 (const int)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  2 (const uint)
+0:43            move second child to first child ( temp float)
+0:43              c2: direct index for structure ( temp float)
+0:43                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:43                Constant:
+0:43                  2 (const uint)
+0:43              direct index ( temp float)
+0:43                '@sampleResultShadow' ( temp 4-component vector of float)
+0:43                Constant:
+0:43                  3 (const uint)
+0:43            '@sampleStructTemp' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:44      Sequence
+0:44        move second child to first child ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44          's2' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44          Sequence
+0:44            move second child to first child ( temp 4-component vector of float)
+0:44              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:44                Construct combined texture-sampler ( temp sampler2D)
+0:44                  'g_tTex2s2' ( uniform texture2D)
+0:44                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.200000
+0:?                   0.210000
+0:44            move second child to first child ( temp float)
+0:44              c0: direct index for structure ( temp float)
+0:44                '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                Constant:
+0:44                  0 (const uint)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  0 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  0 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  1 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  1 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  2 (const uint)
+0:44            move second child to first child ( temp float)
+0:44              direct index ( temp float)
+0:44                c1: direct index for structure ( temp 3-component vector of float)
+0:44                  '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:44                  Constant:
+0:44                    1 (const uint)
+0:44                Constant:
+0:44                  2 (const int)
+0:44              direct index ( temp float)
+0:44                '@sampleResultShadow' ( temp 4-component vector of float)
+0:44                Constant:
+0:44                  3 (const uint)
+0:44            '@sampleStructTemp' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:45      Sequence
+0:45        move second child to first child ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45          's3' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45          Sequence
+0:45            move second child to first child ( temp 4-component vector of float)
+0:45              '@sampleResultShadow' ( temp 4-component vector of float)
+0:?               texture ( temp 4-component vector of float)
+0:45                Construct combined texture-sampler ( temp sampler2D)
+0:45                  'g_tTex2s3' ( uniform texture2D)
+0:45                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.300000
+0:?                   0.310000
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c0: direct index for structure ( temp 2-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    0 (const uint)
+0:45                Constant:
+0:45                  0 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  0 (const uint)
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c0: direct index for structure ( temp 2-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    0 (const uint)
+0:45                Constant:
+0:45                  1 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  1 (const uint)
+0:45            move second child to first child ( temp float)
+0:45              direct index ( temp float)
+0:45                c1: direct index for structure ( temp 1-component vector of float)
+0:45                  '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:45                  Constant:
+0:45                    1 (const uint)
+0:45                Constant:
+0:45                  0 (const int)
+0:45              direct index ( temp float)
+0:45                '@sampleResultShadow' ( temp 4-component vector of float)
+0:45                Constant:
+0:45                  2 (const uint)
+0:45            '@sampleStructTemp' ( temp structure{ temp 2-component vector of float c0,  temp 1-component vector of float c1})
+0:46      Sequence
+0:46        move second child to first child ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46          's4' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46          Sequence
+0:46            move second child to first child ( temp 4-component vector of int)
+0:46              '@sampleResultShadow' ( temp 4-component vector of int)
+0:?               texture ( temp 4-component vector of int)
+0:46                Construct combined texture-sampler ( temp isampler2D)
+0:46                  'g_tTex2s4' ( uniform itexture2D)
+0:46                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.400000
+0:?                   0.410000
+0:46            move second child to first child ( temp int)
+0:46              c0: direct index for structure ( temp int)
+0:46                '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                Constant:
+0:46                  0 (const uint)
+0:46              direct index ( temp int)
+0:46                '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                Constant:
+0:46                  0 (const uint)
+0:46            move second child to first child ( temp float)
+0:46              direct index ( temp float)
+0:46                c1: direct index for structure ( temp 2-component vector of int)
+0:46                  '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46                Constant:
+0:46                  0 (const int)
+0:46              Convert int to float ( temp float)
+0:46                direct index ( temp int)
+0:46                  '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46            move second child to first child ( temp float)
+0:46              direct index ( temp float)
+0:46                c1: direct index for structure ( temp 2-component vector of int)
+0:46                  '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                  Constant:
+0:46                    1 (const uint)
+0:46                Constant:
+0:46                  1 (const int)
+0:46              Convert int to float ( temp float)
+0:46                direct index ( temp int)
+0:46                  '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                  Constant:
+0:46                    2 (const uint)
+0:46            move second child to first child ( temp int)
+0:46              c2: direct index for structure ( temp int)
+0:46                '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:46                Constant:
+0:46                  2 (const uint)
+0:46              direct index ( temp int)
+0:46                '@sampleResultShadow' ( temp 4-component vector of int)
+0:46                Constant:
+0:46                  3 (const uint)
+0:46            '@sampleStructTemp' ( temp structure{ temp int c0,  temp 2-component vector of int c1,  temp int c2})
+0:47      Sequence
+0:47        move second child to first child ( temp structure{ temp uint c0,  temp uint c1})
+0:47          's5' ( temp structure{ temp uint c0,  temp uint c1})
+0:47          Sequence
+0:47            move second child to first child ( temp 4-component vector of uint)
+0:47              '@sampleResultShadow' ( temp 4-component vector of uint)
+0:?               texture ( temp 4-component vector of uint)
+0:47                Construct combined texture-sampler ( temp usampler2D)
+0:47                  'g_tTex2s5' ( uniform utexture2D)
+0:47                  'g_sSamp' ( uniform sampler)
+0:?                 Constant:
+0:?                   0.500000
+0:?                   0.510000
+0:47            move second child to first child ( temp uint)
+0:47              c0: direct index for structure ( temp uint)
+0:47                '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:47                Constant:
+0:47                  0 (const uint)
+0:47              direct index ( temp uint)
+0:47                '@sampleResultShadow' ( temp 4-component vector of uint)
+0:47                Constant:
+0:47                  0 (const uint)
+0:47            move second child to first child ( temp uint)
+0:47              c1: direct index for structure ( temp uint)
+0:47                '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:47                Constant:
+0:47                  1 (const uint)
+0:47              direct index ( temp uint)
+0:47                '@sampleResultShadow' ( temp 4-component vector of uint)
+0:47                Constant:
+0:47                  1 (const uint)
+0:47            '@sampleStructTemp' ( temp structure{ temp uint c0,  temp uint c1})
+0:49      Sequence
+0:49        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49          'r0' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49          Function Call: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:49            'g_tTex2s1' ( uniform texture2D)
+0:50      Sequence
+0:50        move second child to first child ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50          'r1' ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50          Function Call: fn1(t2-tx-struct1-1; ( temp structure{ temp float c0,  temp 3-component vector of float c1})
+0:50            'g_tTex2s2' ( uniform texture2D)
+0:51      Sequence
+0:51        move second child to first child ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51          'r2' ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51          Function Call: fn1(t2-tx-struct0-1; ( temp structure{ temp float c0,  temp 2-component vector of float c1,  temp float c2})
+0:51            'g_tTex2s1a' ( uniform texture2D)
+0:53      Branch: Return with expression
+0:53        Constant:
+0:53          0.000000
+0:53          0.000000
+0:53          0.000000
+0:53          0.000000
+0:42  Function Definition: main( ( temp void)
+0:42    Function Parameters: 
+0:?     Sequence
+0:42      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:42        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_sSamp' ( uniform sampler)
+0:?     'g_tTex2s1' ( uniform texture2D)
+0:?     'g_tTex2s2' ( uniform texture2D)
+0:?     'g_tTex2s3' ( uniform texture2D)
+0:?     'g_tTex2s4' ( uniform itexture2D)
+0:?     'g_tTex2s5' ( uniform utexture2D)
+0:?     'g_tTex2s1a' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 233
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 231
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 10  "s1_t"
+                              MemberName 10(s1_t) 0  "c0"
+                              MemberName 10(s1_t) 1  "c1"
+                              MemberName 10(s1_t) 2  "c2"
+                              Name 13  "fn1(t2-tx-struct0-1;"
+                              Name 12  "t1"
+                              Name 16  "s2_t"
+                              MemberName 16(s2_t) 0  "c0"
+                              MemberName 16(s2_t) 1  "c1"
+                              Name 19  "fn1(t2-tx-struct1-1;"
+                              Name 18  "t2"
+                              Name 23  "@main("
+                              Name 26  "@sampleResultShadow"
+                              Name 30  "g_sSamp"
+                              Name 39  "@sampleStructTemp"
+                              Name 65  "@sampleResultShadow"
+                              Name 71  "@sampleStructTemp"
+                              Name 87  "s1"
+                              Name 88  "@sampleResultShadow"
+                              Name 89  "g_tTex2s1"
+                              Name 97  "@sampleStructTemp"
+                              Name 111  "s2"
+                              Name 112  "@sampleResultShadow"
+                              Name 113  "g_tTex2s2"
+                              Name 121  "@sampleStructTemp"
+                              Name 135  "s3_t"
+                              MemberName 135(s3_t) 0  "c0"
+                              MemberName 135(s3_t) 1  "c1"
+                              Name 137  "s3"
+                              Name 138  "@sampleResultShadow"
+                              Name 139  "g_tTex2s3"
+                              Name 147  "@sampleStructTemp"
+                              Name 159  "s4_t"
+                              MemberName 159(s4_t) 0  "c0"
+                              MemberName 159(s4_t) 1  "c1"
+                              MemberName 159(s4_t) 2  "c2"
+                              Name 161  "s4"
+                              Name 164  "@sampleResultShadow"
+                              Name 167  "g_tTex2s4"
+                              Name 176  "@sampleStructTemp"
+                              Name 193  "s5_t"
+                              MemberName 193(s5_t) 0  "c0"
+                              MemberName 193(s5_t) 1  "c1"
+                              Name 195  "s5"
+                              Name 198  "@sampleResultShadow"
+                              Name 201  "g_tTex2s5"
+                              Name 210  "@sampleStructTemp"
+                              Name 219  "r0"
+                              Name 221  "r1"
+                              Name 223  "r2"
+                              Name 224  "g_tTex2s1a"
+                              Name 231  "@entryPointOutput"
+                              Decorate 30(g_sSamp) DescriptorSet 0
+                              Decorate 89(g_tTex2s1) DescriptorSet 0
+                              Decorate 113(g_tTex2s2) DescriptorSet 0
+                              Decorate 139(g_tTex2s3) DescriptorSet 0
+                              Decorate 167(g_tTex2s4) DescriptorSet 0
+                              Decorate 201(g_tTex2s5) DescriptorSet 0
+                              Decorate 224(g_tTex2s1a) DescriptorSet 0
+                              Decorate 231(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeImage 6(float) 2D sampled format:Unknown
+               8:             TypePointer UniformConstant 7
+               9:             TypeVector 6(float) 2
+        10(s1_t):             TypeStruct 6(float) 9(fvec2) 6(float)
+              11:             TypeFunction 10(s1_t) 8(ptr)
+              15:             TypeVector 6(float) 3
+        16(s2_t):             TypeStruct 6(float) 15(fvec3)
+              17:             TypeFunction 16(s2_t) 8(ptr)
+              21:             TypeVector 6(float) 4
+              22:             TypeFunction 21(fvec4)
+              25:             TypePointer Function 21(fvec4)
+              28:             TypeSampler
+              29:             TypePointer UniformConstant 28
+     30(g_sSamp):     29(ptr) Variable UniformConstant
+              32:             TypeSampledImage 7
+              34:    6(float) Constant 1058642330
+              35:    6(float) Constant 1058810102
+              36:    9(fvec2) ConstantComposite 34 35
+              38:             TypePointer Function 10(s1_t)
+              40:             TypeInt 32 1
+              41:     40(int) Constant 0
+              42:             TypeInt 32 0
+              43:     42(int) Constant 0
+              44:             TypePointer Function 6(float)
+              48:     40(int) Constant 1
+              49:     42(int) Constant 1
+              53:     42(int) Constant 2
+              57:     40(int) Constant 2
+              58:     42(int) Constant 3
+              70:             TypePointer Function 16(s2_t)
+   89(g_tTex2s1):      8(ptr) Variable UniformConstant
+              93:    6(float) Constant 1036831949
+              94:    6(float) Constant 1038174126
+              95:    9(fvec2) ConstantComposite 93 94
+  113(g_tTex2s2):      8(ptr) Variable UniformConstant
+             117:    6(float) Constant 1045220557
+             118:    6(float) Constant 1045891645
+             119:    9(fvec2) ConstantComposite 117 118
+       135(s3_t):             TypeStruct 9(fvec2) 6(float)
+             136:             TypePointer Function 135(s3_t)
+  139(g_tTex2s3):      8(ptr) Variable UniformConstant
+             143:    6(float) Constant 1050253722
+             144:    6(float) Constant 1050589266
+             145:    9(fvec2) ConstantComposite 143 144
+             158:             TypeVector 40(int) 2
+       159(s4_t):             TypeStruct 40(int) 158(ivec2) 40(int)
+             160:             TypePointer Function 159(s4_t)
+             162:             TypeVector 40(int) 4
+             163:             TypePointer Function 162(ivec4)
+             165:             TypeImage 40(int) 2D sampled format:Unknown
+             166:             TypePointer UniformConstant 165
+  167(g_tTex2s4):    166(ptr) Variable UniformConstant
+             170:             TypeSampledImage 165
+             172:    6(float) Constant 1053609165
+             173:    6(float) Constant 1053944709
+             174:    9(fvec2) ConstantComposite 172 173
+             177:             TypePointer Function 40(int)
+       193(s5_t):             TypeStruct 42(int) 42(int)
+             194:             TypePointer Function 193(s5_t)
+             196:             TypeVector 42(int) 4
+             197:             TypePointer Function 196(ivec4)
+             199:             TypeImage 42(int) 2D sampled format:Unknown
+             200:             TypePointer UniformConstant 199
+  201(g_tTex2s5):    200(ptr) Variable UniformConstant
+             204:             TypeSampledImage 199
+             206:    6(float) Constant 1056964608
+             207:    6(float) Constant 1057132380
+             208:    9(fvec2) ConstantComposite 206 207
+             211:             TypePointer Function 42(int)
+ 224(g_tTex2s1a):      8(ptr) Variable UniformConstant
+             226:    6(float) Constant 0
+             227:   21(fvec4) ConstantComposite 226 226 226 226
+             230:             TypePointer Output 21(fvec4)
+231(@entryPointOutput):    230(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+             232:   21(fvec4) FunctionCall 23(@main()
+                              Store 231(@entryPointOutput) 232
+                              Return
+                              FunctionEnd
+13(fn1(t2-tx-struct0-1;):    10(s1_t) Function None 11
+          12(t1):      8(ptr) FunctionParameter
+              14:             Label
+26(@sampleResultShadow):     25(ptr) Variable Function
+39(@sampleStructTemp):     38(ptr) Variable Function
+              27:           7 Load 12(t1)
+              31:          28 Load 30(g_sSamp)
+              33:          32 SampledImage 27 31
+              37:   21(fvec4) ImageSampleImplicitLod 33 36
+                              Store 26(@sampleResultShadow) 37
+              45:     44(ptr) AccessChain 26(@sampleResultShadow) 43
+              46:    6(float) Load 45
+              47:     44(ptr) AccessChain 39(@sampleStructTemp) 41
+                              Store 47 46
+              50:     44(ptr) AccessChain 26(@sampleResultShadow) 49
+              51:    6(float) Load 50
+              52:     44(ptr) AccessChain 39(@sampleStructTemp) 48 43
+                              Store 52 51
+              54:     44(ptr) AccessChain 26(@sampleResultShadow) 53
+              55:    6(float) Load 54
+              56:     44(ptr) AccessChain 39(@sampleStructTemp) 48 49
+                              Store 56 55
+              59:     44(ptr) AccessChain 26(@sampleResultShadow) 58
+              60:    6(float) Load 59
+              61:     44(ptr) AccessChain 39(@sampleStructTemp) 57
+                              Store 61 60
+              62:    10(s1_t) Load 39(@sampleStructTemp)
+                              ReturnValue 62
+                              FunctionEnd
+19(fn1(t2-tx-struct1-1;):    16(s2_t) Function None 17
+          18(t2):      8(ptr) FunctionParameter
+              20:             Label
+65(@sampleResultShadow):     25(ptr) Variable Function
+71(@sampleStructTemp):     70(ptr) Variable Function
+              66:           7 Load 18(t2)
+              67:          28 Load 30(g_sSamp)
+              68:          32 SampledImage 66 67
+              69:   21(fvec4) ImageSampleImplicitLod 68 36
+                              Store 65(@sampleResultShadow) 69
+              72:     44(ptr) AccessChain 65(@sampleResultShadow) 43
+              73:    6(float) Load 72
+              74:     44(ptr) AccessChain 71(@sampleStructTemp) 41
+                              Store 74 73
+              75:     44(ptr) AccessChain 65(@sampleResultShadow) 49
+              76:    6(float) Load 75
+              77:     44(ptr) AccessChain 71(@sampleStructTemp) 48 43
+                              Store 77 76
+              78:     44(ptr) AccessChain 65(@sampleResultShadow) 53
+              79:    6(float) Load 78
+              80:     44(ptr) AccessChain 71(@sampleStructTemp) 48 49
+                              Store 80 79
+              81:     44(ptr) AccessChain 65(@sampleResultShadow) 58
+              82:    6(float) Load 81
+              83:     44(ptr) AccessChain 71(@sampleStructTemp) 48 53
+                              Store 83 82
+              84:    16(s2_t) Load 71(@sampleStructTemp)
+                              ReturnValue 84
+                              FunctionEnd
+      23(@main():   21(fvec4) Function None 22
+              24:             Label
+          87(s1):     38(ptr) Variable Function
+88(@sampleResultShadow):     25(ptr) Variable Function
+97(@sampleStructTemp):     38(ptr) Variable Function
+         111(s2):     70(ptr) Variable Function
+112(@sampleResultShadow):     25(ptr) Variable Function
+121(@sampleStructTemp):     70(ptr) Variable Function
+         137(s3):    136(ptr) Variable Function
+138(@sampleResultShadow):     25(ptr) Variable Function
+147(@sampleStructTemp):    136(ptr) Variable Function
+         161(s4):    160(ptr) Variable Function
+164(@sampleResultShadow):    163(ptr) Variable Function
+176(@sampleStructTemp):    160(ptr) Variable Function
+         195(s5):    194(ptr) Variable Function
+198(@sampleResultShadow):    197(ptr) Variable Function
+210(@sampleStructTemp):    194(ptr) Variable Function
+         219(r0):     38(ptr) Variable Function
+         221(r1):     70(ptr) Variable Function
+         223(r2):     38(ptr) Variable Function
+              90:           7 Load 89(g_tTex2s1)
+              91:          28 Load 30(g_sSamp)
+              92:          32 SampledImage 90 91
+              96:   21(fvec4) ImageSampleImplicitLod 92 95
+                              Store 88(@sampleResultShadow) 96
+              98:     44(ptr) AccessChain 88(@sampleResultShadow) 43
+              99:    6(float) Load 98
+             100:     44(ptr) AccessChain 97(@sampleStructTemp) 41
+                              Store 100 99
+             101:     44(ptr) AccessChain 88(@sampleResultShadow) 49
+             102:    6(float) Load 101
+             103:     44(ptr) AccessChain 97(@sampleStructTemp) 48 43
+                              Store 103 102
+             104:     44(ptr) AccessChain 88(@sampleResultShadow) 53
+             105:    6(float) Load 104
+             106:     44(ptr) AccessChain 97(@sampleStructTemp) 48 49
+                              Store 106 105
+             107:     44(ptr) AccessChain 88(@sampleResultShadow) 58
+             108:    6(float) Load 107
+             109:     44(ptr) AccessChain 97(@sampleStructTemp) 57
+                              Store 109 108
+             110:    10(s1_t) Load 97(@sampleStructTemp)
+                              Store 87(s1) 110
+             114:           7 Load 113(g_tTex2s2)
+             115:          28 Load 30(g_sSamp)
+             116:          32 SampledImage 114 115
+             120:   21(fvec4) ImageSampleImplicitLod 116 119
+                              Store 112(@sampleResultShadow) 120
+             122:     44(ptr) AccessChain 112(@sampleResultShadow) 43
+             123:    6(float) Load 122
+             124:     44(ptr) AccessChain 121(@sampleStructTemp) 41
+                              Store 124 123
+             125:     44(ptr) AccessChain 112(@sampleResultShadow) 49
+             126:    6(float) Load 125
+             127:     44(ptr) AccessChain 121(@sampleStructTemp) 48 43
+                              Store 127 126
+             128:     44(ptr) AccessChain 112(@sampleResultShadow) 53
+             129:    6(float) Load 128
+             130:     44(ptr) AccessChain 121(@sampleStructTemp) 48 49
+                              Store 130 129
+             131:     44(ptr) AccessChain 112(@sampleResultShadow) 58
+             132:    6(float) Load 131
+             133:     44(ptr) AccessChain 121(@sampleStructTemp) 48 53
+                              Store 133 132
+             134:    16(s2_t) Load 121(@sampleStructTemp)
+                              Store 111(s2) 134
+             140:           7 Load 139(g_tTex2s3)
+             141:          28 Load 30(g_sSamp)
+             142:          32 SampledImage 140 141
+             146:   21(fvec4) ImageSampleImplicitLod 142 145
+                              Store 138(@sampleResultShadow) 146
+             148:     44(ptr) AccessChain 138(@sampleResultShadow) 43
+             149:    6(float) Load 148
+             150:     44(ptr) AccessChain 147(@sampleStructTemp) 41 43
+                              Store 150 149
+             151:     44(ptr) AccessChain 138(@sampleResultShadow) 49
+             152:    6(float) Load 151
+             153:     44(ptr) AccessChain 147(@sampleStructTemp) 41 49
+                              Store 153 152
+             154:     44(ptr) AccessChain 138(@sampleResultShadow) 53
+             155:    6(float) Load 154
+             156:     44(ptr) AccessChain 147(@sampleStructTemp) 48
+                              Store 156 155
+             157:   135(s3_t) Load 147(@sampleStructTemp)
+                              Store 137(s3) 157
+             168:         165 Load 167(g_tTex2s4)
+             169:          28 Load 30(g_sSamp)
+             171:         170 SampledImage 168 169
+             175:  162(ivec4) ImageSampleImplicitLod 171 174
+                              Store 164(@sampleResultShadow) 175
+             178:    177(ptr) AccessChain 164(@sampleResultShadow) 43
+             179:     40(int) Load 178
+             180:    177(ptr) AccessChain 176(@sampleStructTemp) 41
+                              Store 180 179
+             181:    177(ptr) AccessChain 164(@sampleResultShadow) 49
+             182:     40(int) Load 181
+             183:    6(float) ConvertSToF 182
+             184:    177(ptr) AccessChain 176(@sampleStructTemp) 48 43
+                              Store 184 183
+             185:    177(ptr) AccessChain 164(@sampleResultShadow) 53
+             186:     40(int) Load 185
+             187:    6(float) ConvertSToF 186
+             188:    177(ptr) AccessChain 176(@sampleStructTemp) 48 49
+                              Store 188 187
+             189:    177(ptr) AccessChain 164(@sampleResultShadow) 58
+             190:     40(int) Load 189
+             191:    177(ptr) AccessChain 176(@sampleStructTemp) 57
+                              Store 191 190
+             192:   159(s4_t) Load 176(@sampleStructTemp)
+                              Store 161(s4) 192
+             202:         199 Load 201(g_tTex2s5)
+             203:          28 Load 30(g_sSamp)
+             205:         204 SampledImage 202 203
+             209:  196(ivec4) ImageSampleImplicitLod 205 208
+                              Store 198(@sampleResultShadow) 209
+             212:    211(ptr) AccessChain 198(@sampleResultShadow) 43
+             213:     42(int) Load 212
+             214:    211(ptr) AccessChain 210(@sampleStructTemp) 41
+                              Store 214 213
+             215:    211(ptr) AccessChain 198(@sampleResultShadow) 49
+             216:     42(int) Load 215
+             217:    211(ptr) AccessChain 210(@sampleStructTemp) 48
+                              Store 217 216
+             218:   193(s5_t) Load 210(@sampleStructTemp)
+                              Store 195(s5) 218
+             220:    10(s1_t) FunctionCall 13(fn1(t2-tx-struct0-1;) 89(g_tTex2s1)
+                              Store 219(r0) 220
+             222:    16(s2_t) FunctionCall 19(fn1(t2-tx-struct1-1;) 113(g_tTex2s2)
+                              Store 221(r1) 222
+             225:    10(s1_t) FunctionCall 13(fn1(t2-tx-struct0-1;) 224(g_tTex2s1a)
+                              Store 223(r2) 225
+                              ReturnValue 227
+                              FunctionEnd
diff --git a/Test/hlsl.texture.struct.frag b/Test/hlsl.texture.struct.frag
new file mode 100644 (file)
index 0000000..461469c
--- /dev/null
@@ -0,0 +1,55 @@
+struct s1_t {
+    float  c0;
+    float2 c1;
+    float  c2;
+};
+
+struct s2_t {
+    float  c0;
+    float3 c1;
+};
+
+struct s3_t {
+    float2  c0;
+    float1  c1;
+};
+
+struct s4_t {
+    int  c0;
+    int2 c1;
+    int  c2;
+};
+
+struct s5_t {
+    uint c0;
+    uint c1;
+};
+
+SamplerState g_sSamp;
+Texture2D <s1_t>   g_tTex2s1;
+Texture2D <s2_t>   g_tTex2s2;
+Texture2D <s3_t>   g_tTex2s3;
+Texture2D <s4_t>   g_tTex2s4;
+Texture2D <s5_t>   g_tTex2s5;
+
+Texture2D <s1_t>   g_tTex2s1a; // same type as g_tTex2s1, to test fn signature matching.
+
+// function overloading to test name mangling with textures templatized on structs
+s1_t fn1(Texture2D <s1_t> t1) { return t1 . Sample(g_sSamp, float2(0.6, 0.61)); }
+s2_t fn1(Texture2D <s2_t> t2) { return t2 . Sample(g_sSamp, float2(0.6, 0.61)); }
+
+float4 main() : SV_Target0
+{
+    s1_t s1 = g_tTex2s1 . Sample(g_sSamp, float2(0.1, 0.11));
+    s2_t s2 = g_tTex2s2 . Sample(g_sSamp, float2(0.2, 0.21));
+    s3_t s3 = g_tTex2s3 . Sample(g_sSamp, float2(0.3, 0.31));
+    s4_t s4 = g_tTex2s4 . Sample(g_sSamp, float2(0.4, 0.41));
+    s5_t s5 = g_tTex2s5 . Sample(g_sSamp, float2(0.5, 0.51));
+
+    s1_t r0 = fn1(g_tTex2s1);
+    s2_t r1 = fn1(g_tTex2s2);
+    s1_t r2 = fn1(g_tTex2s1a);
+
+    return 0;
+}
+
index 9e057d5..56fd410 100644 (file)
@@ -11,7 +11,7 @@ Texture2D <float4> g_tTex2df4;
 
 SamplerState g_sSamp;
 
-float4 main()
+float4 main() : SV_Target0
 {
     uint MipLevel;
     uint WidthU;
index b94f915..b5b91f5 100644 (file)
@@ -80,7 +80,19 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
     bool   combined : 1;  // true means texture is combined with a sampler, false means texture with no sampler
     bool    sampler : 1;  // true means a pure sampler, other fields should be clear()
     bool   external : 1;  // GL_OES_EGL_image_external
-    unsigned int vectorSize : 3;  // return vector size.  TODO: support arbitrary types.
+    unsigned int vectorSize : 3;  // vector return type size.
+
+    // Some languages support structures as sample results.  Storing the whole structure in the
+    // TSampler is too large, so there is an index to a separate table.
+    static const unsigned structReturnIndexBits = 4;                        // number of index bits to use.
+    static const unsigned structReturnSlots = (1<<structReturnIndexBits)-1; // number of valid values
+    static const unsigned noReturnStruct = structReturnSlots;               // value if no return struct type.
+
+    // Index into a language specific table of texture return structures.
+    unsigned int structReturnIndex : structReturnIndexBits;
+
+    // Encapsulate getting members' vector sizes packed into the vectorSize bitfield.
+    unsigned int getVectorSize() const { return vectorSize; }
 
     bool isImage()       const { return image && dim != EsdSubpass; }
     bool isSubpass()     const { return dim == EsdSubpass; }
@@ -90,6 +102,7 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
     bool isShadow()      const { return shadow; }
     bool isArrayed()     const { return arrayed; }
     bool isMultiSample() const { return ms; }
+    bool hasReturnStruct() const { return structReturnIndex != noReturnStruct; }
 
     void clear()
     {
@@ -102,6 +115,9 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
         combined = false;
         sampler = false;
         external = false;
+        structReturnIndex = noReturnStruct;
+
+        // by default, returns a single vec4;
         vectorSize = 4;
     }
 
@@ -160,16 +176,17 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
 
     bool operator==(const TSampler& right) const
     {
-        return type == right.type &&
-                dim == right.dim &&
-            arrayed == right.arrayed &&
-             shadow == right.shadow &&
-                 ms == right.ms &&
-              image == right.image &&
-           combined == right.combined &&
-            sampler == right.sampler &&
-           external == right.external &&
-         vectorSize == right.vectorSize;
+        return      type == right.type &&
+                     dim == right.dim &&
+                 arrayed == right.arrayed &&
+                  shadow == right.shadow &&
+                      ms == right.ms &&
+                   image == right.image &&
+                combined == right.combined &&
+                 sampler == right.sampler &&
+                external == right.external &&
+              vectorSize == right.vectorSize &&
+       structReturnIndex == right.structReturnIndex;            
     }
 
     bool operator!=(const TSampler& right) const
index d7f9e1d..233033e 100644 (file)
@@ -104,11 +104,20 @@ void TType::buildMangledName(TString& mangledName) const
         default: break; // some compilers want this
         }
 
-        switch (sampler.vectorSize) {
-        case 1: mangledName += "1"; break;
-        case 2: mangledName += "2"; break;
-        case 3: mangledName += "3"; break;
-        case 4: break; // default to prior name mangle behavior
+        if (sampler.hasReturnStruct()) {
+            // Name mangle for sampler return struct uses struct table index.
+            mangledName += "-tx-struct";
+
+            char text[16]; // plenty enough space for the small integers.
+            snprintf(text, sizeof(text), "%d-", sampler.structReturnIndex);
+            mangledName += text;
+        } else {
+            switch (sampler.getVectorSize()) {
+            case 1: mangledName += "1"; break;
+            case 2: mangledName += "2"; break;
+            case 3: mangledName += "3"; break;
+            case 4: break; // default to prior name mangle behavior
+            }
         }
 
         if (sampler.ms)
index d28b97c..27452ab 100644 (file)
@@ -291,6 +291,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.structIoFourWay.frag", "main"},
         {"hlsl.structStructName.frag", "main"},
         {"hlsl.synthesizeInput.frag", "main"},
+        {"hlsl.texture.struct.frag", "main"},
         {"hlsl.texture.subvec4.frag", "main"},
         {"hlsl.this.frag", "main"},
         {"hlsl.intrinsics.vert", "VertexShaderFunction"},
index 0e8614c..2f687c5 100755 (executable)
@@ -1189,7 +1189,13 @@ bool HlslGrammar::acceptTextureType(TType& type)
 
         const TBasicType basicRetType = txType.getBasicType() ;
 
-        if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
+        switch (basicRetType) {
+        case EbtFloat:
+        case EbtUint:
+        case EbtInt:
+        case EbtStruct:
+            break;
+        default:
             unimplemented("basic type in texture");
             return false;
         }
@@ -1206,8 +1212,8 @@ bool HlslGrammar::acceptTextureType(TType& type)
             return false;
         }
 
-        if (!txType.isScalar() && !txType.isVector()) {
-            expected("scalar or vector type");
+        if (!txType.isScalar() && !txType.isVector() && !txType.isStruct()) {
+            expected("scalar, vector, or struct type");
             return false;
         }
 
@@ -1244,20 +1250,24 @@ bool HlslGrammar::acceptTextureType(TType& type)
     if (image || dim == EsdBuffer)
         format = parseContext.getLayoutFromTxType(token.loc, txType);
 
+    const TBasicType txBasicType = txType.isStruct() ? (*txType.getStruct())[0].type->getBasicType()
+        : txType.getBasicType();
+
     // Non-image Buffers are combined
     if (dim == EsdBuffer && !image) {
         sampler.set(txType.getBasicType(), dim, array);
     } else {
         // DX10 textures are separated.  TODO: DX9.
         if (image) {
-            sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
+            sampler.setImage(txBasicType, dim, array, shadow, ms);
         } else {
-            sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
+            sampler.setTexture(txBasicType, dim, array, shadow, ms);
         }
     }
 
-    // Remember the declared vector size.
-    sampler.vectorSize = txType.getVectorSize();
+    // Remember the declared return type.  Function returns false on error.
+    if (!parseContext.setTextureReturnType(sampler, txType, token.loc))
+        return false;
 
     // Force uncombined, if necessary
     if (!combined)
index 9bc217d..14de3ba 100755 (executable)
@@ -189,7 +189,14 @@ void HlslParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memb
 //
 TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType)
 {
+    if (txType.isStruct()) {
+        // TODO: implement.
+        error(loc, "unimplemented: structure type in image or buffer", "", "");
+        return ElfNone;
+    }
+
     const int components = txType.getVectorSize();
+    const TBasicType txBasicType = txType.getBasicType();
 
     const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) -> TLayoutFormat {
         if (intermediate.getNoStorageFormat())
@@ -199,7 +206,7 @@ TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const
                components == 2 ? v2 : v4;
     };
 
-    switch (txType.getBasicType()) {
+    switch (txBasicType) {
     case EbtFloat: return selectFormat(ElfR32f,  ElfRg32f,  ElfRgba32f);
     case EbtInt:   return selectFormat(ElfR32i,  ElfRg32i,  ElfRgba32i);
     case EbtUint:  return selectFormat(ElfR32ui, ElfRg32ui, ElfRgba32ui);
@@ -370,7 +377,8 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char*
 
     const TSampler& texSampler = object->getType().getSampler();
 
-    const TType objDerefType(texSampler.type, EvqTemporary, texSampler.vectorSize);
+    TType objDerefType;
+    getTextureReturnType(texSampler, objDerefType);
 
     if (nodeAsBinary) {
         TIntermTyped* rhs = nodeAsBinary->getRight();
@@ -771,7 +779,10 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn
             } else {
                 TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
 
-                load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize));
+                TType sampReturnType;
+                getTextureReturnType(sampler, sampReturnType);
+
+                load->setType(sampReturnType);
                 load->setLoc(loc);
                 load->getSequence().push_back(base);
                 load->getSequence().push_back(index);
@@ -3292,21 +3303,99 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
     if (node == nullptr || !node->getAsOperator())
         return;
 
-    const auto clampReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* {
-        // Sampler return must always be a vec4, but we can construct a shorter vector
+    // Sampler return must always be a vec4, but we can construct a shorter vector or a structure from it.
+    const auto convertReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* {
         result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize()));
 
-        if (sampler.vectorSize < (unsigned)node->getVectorSize()) {
-            // Too many components.  Construct shorter vector from it.
-            const TType clampedType(result->getType().getBasicType(), EvqTemporary, sampler.vectorSize);
+        TIntermTyped* convertedResult = nullptr;
+        
+        TType retType;
+        getTextureReturnType(sampler, retType);
+
+        if (retType.isStruct()) {
+            // For type convenience, conversionAggregate points to the convertedResult (we know it's an aggregate here)
+            TIntermAggregate* conversionAggregate = new TIntermAggregate;
+            convertedResult = conversionAggregate;
+
+            // Convert vector output to return structure.  We will need a temp symbol to copy the results to.
+            TVariable* structVar = makeInternalVariable("@sampleStructTemp", retType);
+
+            // We also need a temp symbol to hold the result of the texture.  We don't want to re-fetch the
+            // sample each time we'll index into the result, so we'll copy to this, and index into the copy.
+            TVariable* sampleShadow = makeInternalVariable("@sampleResultShadow", result->getType());
+
+            // Initial copy from texture to our sample result shadow.
+            TIntermTyped* shadowCopy = intermediate.addAssign(EOpAssign, intermediate.addSymbol(*sampleShadow, loc),
+                                                              result, loc);
+
+            conversionAggregate->getSequence().push_back(shadowCopy);
 
-            const TOperator op = intermediate.mapTypeToConstructorOp(clampedType);
+            unsigned vec4Pos = 0;
 
-            result = constructBuiltIn(clampedType, op, result, loc, false);
+            for (unsigned m = 0; m < unsigned(retType.getStruct()->size()); ++m) {
+                const TType memberType(retType, m); // dereferenced type of the member we're about to assign.
+                
+                // Check for bad struct members.  This should have been caught upstream.  Complain, because
+                // wwe don't know what to do with it.  This algorithm could be generalized to handle
+                // other things, e.g, sub-structures, but HLSL doesn't allow them.
+                if (!memberType.isVector() && !memberType.isScalar()) {
+                    error(loc, "expected: scalar or vector type in texture structure", "", "");
+                    return nullptr;
+                }
+                    
+                // Index into the struct variable to find the member to assign.
+                TIntermTyped* structMember = intermediate.addIndex(EOpIndexDirectStruct,
+                                                                   intermediate.addSymbol(*structVar, loc),
+                                                                   intermediate.addConstantUnion(m, loc), loc);
+
+                structMember->setType(memberType);
+
+                // Assign each component of (possible) vector in struct member.
+                for (int component = 0; component < memberType.getVectorSize(); ++component) {
+                    TIntermTyped* vec4Member = intermediate.addIndex(EOpIndexDirect,
+                                                                     intermediate.addSymbol(*sampleShadow, loc),
+                                                                     intermediate.addConstantUnion(vec4Pos++, loc), loc);
+                    vec4Member->setType(TType(memberType.getBasicType(), EvqTemporary, 1));
+
+                    TIntermTyped* memberAssign = nullptr;
+
+                    if (memberType.isVector()) {
+                        // Vector member: we need to create an access chain to the vector component.
+
+                        TIntermTyped* structVecComponent = intermediate.addIndex(EOpIndexDirect, structMember,
+                                                                                 intermediate.addConstantUnion(component, loc), loc);
+                        
+                        memberAssign = intermediate.addAssign(EOpAssign, structVecComponent, vec4Member, loc);
+                    } else {
+                        // Scalar member: we can assign to it directly.
+                        memberAssign = intermediate.addAssign(EOpAssign, structMember, vec4Member, loc);
+                    }
+
+                    
+                    conversionAggregate->getSequence().push_back(memberAssign);
+                }
+            }
+
+            // Add completed variable so the expression results in the whole struct value we just built.
+            conversionAggregate->getSequence().push_back(intermediate.addSymbol(*structVar, loc));
+
+            // Make it a sequence.
+            intermediate.setAggregateOperator(conversionAggregate, EOpSequence, retType, loc);
+        } else {
+            // vector clamp the output if template vector type is smaller than sample result.
+            if (retType.getVectorSize() < node->getVectorSize()) {
+                // Too many components.  Construct shorter vector from it.
+                const TOperator op = intermediate.mapTypeToConstructorOp(retType);
+
+                convertedResult = constructBuiltIn(retType, op, result, loc, false);
+            } else {
+                // Enough components.  Use directly.
+                convertedResult = result;
+            }
         }
 
-        result->setLoc(loc);
-        return result;
+        convertedResult->setLoc(loc);
+        return convertedResult;
     };
 
     const TOperator op  = node->getAsOperator()->getOp();
@@ -3372,7 +3461,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
             tex->getSequence().push_back(constructCoord); // coordinate
             tex->getSequence().push_back(bias);           // bias
 
-            node = clampReturn(tex, sampler);
+            node = convertReturn(tex, sampler);
 
             break;
         }
@@ -3412,7 +3501,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
             if (argOffset != nullptr)
                 txsample->getSequence().push_back(argOffset);
 
-            node = clampReturn(txsample, sampler);
+            node = convertReturn(txsample, sampler);
 
             break;
         }
@@ -3445,7 +3534,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
             if (argOffset != nullptr)
                 txsample->getSequence().push_back(argOffset);
 
-            node = clampReturn(txsample, sampler);
+            node = convertReturn(txsample, sampler);
 
             break;
         }
@@ -3721,7 +3810,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
                 txfetch->getSequence().push_back(argOffset);
             }
 
-            node = clampReturn(txfetch, sampler);
+            node = convertReturn(txfetch, sampler);
 
             break;
         }
@@ -3752,7 +3841,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
             if (argOffset != nullptr)
                 txsample->getSequence().push_back(argOffset);
 
-            node = clampReturn(txsample, sampler);
+            node = convertReturn(txsample, sampler);
 
             break;
         }
@@ -8756,6 +8845,106 @@ void HlslParseContext::clearUniformInputOutput(TQualifier& qualifier)
 }
 
 
+// Set texture return type.  Returns success (not all types are valid).
+bool HlslParseContext::setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc)
+{
+    // Seed the output with an invalid index.  We will set it to a valid one if we can.
+    sampler.structReturnIndex = TSampler::noReturnStruct;
+
+    // Arrays aren't supported.
+    if (retType.isArray()) {
+        error(loc, "Arrays not supported in texture template types", "", "");
+        return false;
+    }
+
+    // If return type is a vector, remember the vector size in the sampler, and return.
+    if (retType.isVector() || retType.isScalar()) {
+        sampler.vectorSize = retType.getVectorSize();
+        return true;
+    }
+
+    // If it wasn't a vector, it must be a struct meeting certain requirements.  The requirements
+    // are checked below: just check for struct-ness here.
+    if (!retType.isStruct()) {
+        error(loc, "Invalid texture template type", "", "");
+        return false;
+    }
+
+    TTypeList* members = retType.getWritableStruct();
+
+    // Check for too many or not enough structure members.
+    if (members->size() > 4 || members->size() == 0) {
+        error(loc, "Invalid member count in texture template structure", "", "");
+        return false;
+    }
+
+    // Error checking: We must have <= 4 total components, all of the same basic type.
+    unsigned totalComponents = 0;
+    for (unsigned m = 0; m < members->size(); ++m) {
+        // Check for bad member types
+        if (!(*members)[m].type->isScalar() && !(*members)[m].type->isVector()) {
+            error(loc, "Invalid texture template struct member type", "", "");
+            return false;
+        }
+
+        const unsigned memberVectorSize = (*members)[m].type->getVectorSize();
+        totalComponents += memberVectorSize;
+
+        // too many total member components
+        if (totalComponents > 4) {
+            error(loc, "Too many components in texture template structure type", "", "");
+            return false;
+        }
+
+        // All members must be of a common basic type
+        if ((*members)[m].type->getBasicType() != (*members)[0].type->getBasicType()) {
+            error(loc, "Texture template structure members must same basic type", "", "");
+            return false;
+        }
+    }
+
+    // If the structure in the return type already exists in the table, we'll use it.  Otherwise, we'll make
+    // a new entry.  This is a linear search, but it hardly ever happens, and the list cannot be very large.
+    for (unsigned int idx = 0; idx < textureReturnStruct.size(); ++idx) {
+        if (textureReturnStruct[idx] == members) {
+            sampler.structReturnIndex = idx;
+            return true;
+        }
+    }
+
+    // It wasn't found as an existing entry.  See if we have room for a new one.
+    if (textureReturnStruct.size() >= TSampler::structReturnSlots) {
+        error(loc, "Texture template struct return slots exceeded", "", "");
+        return false;
+    }
+
+    // Insert it in the vector that tracks struct return types.
+    sampler.structReturnIndex = unsigned(textureReturnStruct.size());
+    textureReturnStruct.push_back(members);
+    
+    // Success!
+    return true;
+}
+
+// Return the sampler return type in retType.
+void HlslParseContext::getTextureReturnType(const TSampler& sampler, TType& retType) const
+{
+    if (sampler.hasReturnStruct()) {
+        assert(textureReturnStruct.size() >= sampler.structReturnIndex);
+
+        // We land here if the texture return is a structure.
+        TTypeList* blockStruct = textureReturnStruct[sampler.structReturnIndex];
+
+        const TType resultType(blockStruct, "");
+        retType.shallowCopy(resultType);
+    } else {
+        // We land here if the texture return is a vector or scalar.
+        const TType resultType(sampler.type, EvqTemporary, sampler.getVectorSize());
+        retType.shallowCopy(resultType);
+    }
+}
+
+
 // Return a symbol for the tessellation linkage variable of the given TBuiltInVariable type
 TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const
 {
index 9febc07..ab62625 100755 (executable)
@@ -213,6 +213,12 @@ public:
     // Share struct buffer deep types
     void shareStructBufferType(TType&);
 
+    // Set texture return type of the given sampler.  Returns success (not all types are valid).
+    bool setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc);
+
+    // Obtain the sampler return type of the given sampler in retType.
+    void getTextureReturnType(const TSampler& sampler, TType& retType) const;
+
 protected:
     struct TFlattenData {
         TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
@@ -388,6 +394,10 @@ protected:
 
     // Structuredbuffer shared types.  Typically there are only a few.
     TVector<TType*> structBufferTypes;
+
+    // This tracks texture sample user structure return types.  Only a limited number are supported, as
+    // may fit in TSampler::structReturnIndex.
+    TVector<TTypeList*> textureReturnStruct;
     
     TMap<TString, bool> structBufferCounter;