diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-09 11:34:21 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-09 13:44:59 -0700 |
| commit | fcf83dbf9effab3bd98bad2b83b2468b7eb05cfd (patch) | |
| tree | 41047c94883b86ec085a81597391ce3ef557cd43 /tests/bindings | |
| parent | 52e8d4b9a27ab0060f874c3a63ab531847be35c0 (diff) | |
Initial import of code.
Diffstat (limited to 'tests/bindings')
| -rw-r--r-- | tests/bindings/README.md | 29 | ||||
| -rw-r--r-- | tests/bindings/binding0.hlsl | 27 | ||||
| -rw-r--r-- | tests/bindings/binding1.hlsl | 41 | ||||
| -rw-r--r-- | tests/bindings/explicit-binding.hlsl | 55 | ||||
| -rw-r--r-- | tests/bindings/multi-file-extra.hlsl | 60 | ||||
| -rw-r--r-- | tests/bindings/multi-file.hlsl | 64 | ||||
| -rw-r--r-- | tests/bindings/packoffset.hlsl | 40 | ||||
| -rw-r--r-- | tests/bindings/resources-in-cbuffer.hlsl | 68 | ||||
| -rw-r--r-- | tests/bindings/resources-in-structs.hlsl.disabled | 42 | ||||
| -rw-r--r-- | tests/bindings/targets-and-uavs-structure.hlsl | 36 | ||||
| -rw-r--r-- | tests/bindings/targets-and-uavs.hlsl | 28 |
11 files changed, 490 insertions, 0 deletions
diff --git a/tests/bindings/README.md b/tests/bindings/README.md new file mode 100644 index 000000000..ccc9fecb9 --- /dev/null +++ b/tests/bindings/README.md @@ -0,0 +1,29 @@ +Binding Generation Tests +======================== + +These tests ensure that the compiler can correctly add explicit binding information (e.g., HLSL `register` semantics) to code that does not originally have them. + +Example +------- + +Given code like: + + Texture2D ta; + Texture2D tb; + +We expect to produce output like: + + Texture2D ta : register(t0); + Texture2D tb : register(t1); + +The resulting code guarantees that `tb` will always be assigned to the same location, regardless of how these values are (or are not) used in later shader code. + +Methodology +----------- + +These tests currently rely on the ability to run the same HLSL code through the Spire compiler driver and execute either Spire, or HLSL. We write an example like the above by wrapping explicit `register` semantics in a macro: + + Texture2D ta R(: register(t0)); + Texture2D tb R(: register(t1)); + +In the HLSL case, these annotations will manually place things where we want them, while in the Spire case, we define the macro to have an empty expansion, so that the annotations express our expectation for what the compiler will auto-generate.
\ No newline at end of file diff --git a/tests/bindings/binding0.hlsl b/tests/bindings/binding0.hlsl new file mode 100644 index 000000000..3f965bef0 --- /dev/null +++ b/tests/bindings/binding0.hlsl @@ -0,0 +1,27 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry main + +// Let's first confirm that Spire can reproduce what the +// HLSL compiler would already do in the simple case (when +// all shader parameters are actually used). + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +Texture2D t R(: register(t0)); +SamplerState s R(: register(s0)); + +cbuffer C R(: register(b0)) +{ + float c; +} + +float4 main() : SV_Target +{ + return use(t,s) + use(c); +}
\ No newline at end of file diff --git a/tests/bindings/binding1.hlsl b/tests/bindings/binding1.hlsl new file mode 100644 index 000000000..d9e74e918 --- /dev/null +++ b/tests/bindings/binding1.hlsl @@ -0,0 +1,41 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry main + +// We want to make sure that the registers that Spire generates +// are used, even if there are "dead" parameter earlier in the program. +// +// In this case, we declare two each of textures, samplers, and constant +// buffers, and then only use the second one. +// Left to its own devices, the HLSL compiler would usually shift the +// object that was used up to binding slot zero, and eliminate the one +// that wasn't used. +// We expect Spire to generate explicit annotations that stop this from +// happening. + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +Texture2D t0 R(: register(t0)); +Texture2D t1 R(: register(t1)); +SamplerState s0 R(: register(s0)); +SamplerState s1 R(: register(s1)); + +cbuffer C0 R(: register(b0)) +{ + float c0; +} + +cbuffer C1 R(: register(b1)) +{ + float c1; +} + +float4 main() : SV_Target +{ + return use(t1,s1) + use(c1); +}
\ No newline at end of file diff --git a/tests/bindings/explicit-binding.hlsl b/tests/bindings/explicit-binding.hlsl new file mode 100644 index 000000000..ac23c6556 --- /dev/null +++ b/tests/bindings/explicit-binding.hlsl @@ -0,0 +1,55 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry main + +// We need to allow the user to add explicit bindings to their parameters, +// and we can't go and auto-assign anything to use the same locations. + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +// We'll make three textures, but explicit assign the third one +// to the slot `t0`. We expect the others to shift further along +// to "make room". +Texture2D ta R(: register(t1)); +Texture2D tb R(: register(t2)); +Texture2D tc : register(t0); + + +// The explicit binding may "split" the range of register available +// for automatic placement. We use a "first-fit" approach to pack +// things in: +SamplerState sa R(: register(s0)); +SamplerState sb R(: register(s2)); +SamplerState sc : register(s1); + +// It's also okay to use a register that *doesn't* conflict, +// and even to make things non-contiguous. Here we bind +// the third constnat buffer to register `b9` +// +cbuffer CA R(: register(b0)) +{ + float ca; +} +// +cbuffer CB R(: register(b1)) +{ + float cb; +} +// +cbuffer CC : register(b9) +{ + float cc; +} + +float4 main() : SV_Target +{ + // Go ahead and use everything in this case: + return use(ta, sa) + use(ca) + + use(tb, sb) + use(cb) + + use(tc, sc) + use(cc); +}
\ No newline at end of file diff --git a/tests/bindings/multi-file-extra.hlsl b/tests/bindings/multi-file-extra.hlsl new file mode 100644 index 000000000..45837c984 --- /dev/null +++ b/tests/bindings/multi-file-extra.hlsl @@ -0,0 +1,60 @@ +//TEST_IGNORE_FILE: + +// Here we are going to test that we can correctly generating bindings when we +// are presented with a program spanning multiple input files (and multiple entry points) + +// This file provides the fragment shader, and is only meant to be tested in combination with `multi-file.hlsl` + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +// Start with some parameters that will appear in both shaders +Texture2D sharedT R(: register(t0)); +SamplerState sharedS R(: register(s0)); +cbuffer sharedC R(: register(b0)) +{ + float3 sharedCA R(: packoffset(c0)); + float sharedCB R(: packoffset(c0.w)); + float3 sharedCC R(: packoffset(c1)); + float2 sharedCD R(: packoffset(c2)); +} + +// Then some parameters specific to this shader. +// These will be placed *after* the ones from the main file, +// and even after the parameters further down in this file +// that end up being shared between the two files. + +Texture2D fragmentT R(: register(t4)); +SamplerState fragmentS R(: register(s2)); +cbuffer fragmentC R(: register(b2)) +{ + float3 fragmentCA R(: packoffset(c0)); + float fragmentCB R(: packoffset(c0.w)); + float3 fragmentCC R(: packoffset(c1)); + float2 fragmentCD R(: packoffset(c2)); +} + +// And end with some shared parameters again +Texture2D sharedTV R(: register(t2)); +Texture2D sharedTF R(: register(t3)); + + +float4 main() : SV_Target +{ + // Go ahead and use everything here, just to make sure things got placed correctly + return use(sharedT, sharedS) + + use(sharedCD) + + use(fragmentT, fragmentS) + + use(fragmentCD) + + use(sharedTF, sharedS) + ; +}
\ No newline at end of file diff --git a/tests/bindings/multi-file.hlsl b/tests/bindings/multi-file.hlsl new file mode 100644 index 000000000..db193a869 --- /dev/null +++ b/tests/bindings/multi-file.hlsl @@ -0,0 +1,64 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile vs_4_0 -entry main Tests/bindings/multi-file-extra.hlsl -profile ps_4_0 -entry main + +// Here we are going to test that we can correctly generating bindings when we +// are presented with a program spanning multiple input files (and multiple entry points) + +// This file provides the vertex shader, while the fragment shader resides in +// the file `multi-file-extra.hlsl` + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) +{ + // This is the vertex shader, so we can't do implicit-gradient sampling + return t.SampleGrad(s, 0.0, 0.0, 0.0); +} + +// Start with some parameters that will appear in both shaders +Texture2D sharedT R(: register(t0)); +SamplerState sharedS R(: register(s0)); +cbuffer sharedC R(: register(b0)) +{ + float3 sharedCA R(: packoffset(c0)); + float sharedCB R(: packoffset(c0.w)); + float3 sharedCC R(: packoffset(c1)); + float2 sharedCD R(: packoffset(c2)); +} + +// Then some parameters specific to this shader +// (these will get placed before the ones in the `extra` file, +// based on how they get named on the command-line) + +Texture2D vertexT R(: register(t1)); +SamplerState vertexS R(: register(s1)); +cbuffer vertexC R(: register(b1)) +{ + float3 vertexCA R(: packoffset(c0)); + float vertexCB R(: packoffset(c0.w)); + float3 vertexCC R(: packoffset(c1)); + float2 vertexCD R(: packoffset(c2)); +} + +// And end with some shared parameters again +Texture2D sharedTV R(: register(t2)); +Texture2D sharedTF R(: register(t3)); + + +float4 main() : SV_Position +{ + // Go ahead and use everything here, just to make sure things got placed correctly + return use(sharedT, sharedS) + + use(sharedCD) + + use(vertexT, vertexS) + + use(vertexCD) + + use(sharedTV, vertexS) + ; +}
\ No newline at end of file diff --git a/tests/bindings/packoffset.hlsl b/tests/bindings/packoffset.hlsl new file mode 100644 index 000000000..787bbc129 --- /dev/null +++ b/tests/bindings/packoffset.hlsl @@ -0,0 +1,40 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry main + +// Let's make sure we generate correct output in cases +// where there are non-trivial `packoffset`s needed + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +cbuffer CA R(: register(b0)) +{ + float4 ca R(: packoffset(c0)); + float3 cb R(: packoffset(c1.x)); + float cc R(: packoffset(c1.w)); + float2 cd R(: packoffset(c2.x)); + float2 ce R(: packoffset(c2.z)); + + Texture2D ta R(: register(t0)); + SamplerState sa R(: register(s0)); +} + +float4 main() : SV_Target +{ + // Go ahead and use everything in this case: + return use(ta, sa) + + use(ca) + + use(cb) + + use(cc) + + use(cd) + + use(ce) + ; +}
\ No newline at end of file diff --git a/tests/bindings/resources-in-cbuffer.hlsl b/tests/bindings/resources-in-cbuffer.hlsl new file mode 100644 index 000000000..ec35943cc --- /dev/null +++ b/tests/bindings/resources-in-cbuffer.hlsl @@ -0,0 +1,68 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_4_0 -entry main + +// Confirm that resources inside constant buffers get correct locations, +// including the case where there are *multiple* constant buffers +// with reosurces. + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +cbuffer CA R(: register(b0)) +{ + float4 caa R(: packoffset(c0)); + float3 cab R(: packoffset(c1.x)); + float cac R(: packoffset(c1.w)); + float2 cad R(: packoffset(c2.x)); + float2 cae R(: packoffset(c2.z)); + + Texture2D ta R(: register(t0)); + SamplerState sa R(: register(s0)); +} + +cbuffer CB R(: register(b1)) +{ + float4 cba R(: packoffset(c0)); + float3 cbb R(: packoffset(c1.x)); + float cbc R(: packoffset(c1.w)); + float2 cbd R(: packoffset(c2.x)); + float2 cbe R(: packoffset(c2.z)); + + Texture2D tbx R(: register(t1)); + Texture2D tby R(: register(t2)); + SamplerState sb R(: register(s1)); +} + +cbuffer CC R(: register(b2)) +{ + float4 cca R(: packoffset(c0)); + float3 ccb R(: packoffset(c1.x)); + float ccc R(: packoffset(c1.w)); + float2 ccd R(: packoffset(c2.x)); + float2 cce R(: packoffset(c2.z)); + + Texture2D tc R(: register(t3)); + SamplerState scx R(: register(s2)); + SamplerState scy R(: register(s3)); +} + +float4 main() : SV_Target +{ + // Go ahead and use everything in this case: + return use(ta, sa) + + use(tbx, sb) + + use(tby, scx) + + use(tc, scy) + + use(cae) + + use(cbe) + + use(cce) + ; +}
\ No newline at end of file diff --git a/tests/bindings/resources-in-structs.hlsl.disabled b/tests/bindings/resources-in-structs.hlsl.disabled new file mode 100644 index 000000000..05269d823 --- /dev/null +++ b/tests/bindings/resources-in-structs.hlsl.disabled @@ -0,0 +1,42 @@ +//SPIRE_TEST_OPTS:-target dxbc-assembly -profile ps_5_0 -entry main + +// Confirm that resources inside `struct` types work reasonably well, + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } +float4 use(Texture2D t, SamplerComparisonState s) { return t.SampleCmp(s, 0.0, 0.0); } + +struct FooData +{ + float4 f; + Texture2D t; + SamplerState s; + SamplerComparisonState c; +}; + +cbuffer CA R(: register(b0)) +{ + FooData foo R(: register(c0) : register(t0) : register(s0)); +}; + +Texture2D t R(: register(t1)); +SamplerState s R(: register(s2)); + +float4 main() : SV_Target +{ + // Go ahead and use everything in this case: + return use(foo.t, foo.s) + + use(foo.t, foo.c) + + use(t, s) + + use(foo.f) + ; +}
\ No newline at end of file diff --git a/tests/bindings/targets-and-uavs-structure.hlsl b/tests/bindings/targets-and-uavs-structure.hlsl new file mode 100644 index 000000000..dcc053253 --- /dev/null +++ b/tests/bindings/targets-and-uavs-structure.hlsl @@ -0,0 +1,36 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_5_0 -entry main + +// Handle the case where the fragment shader output is +// defined a structure, and the semantics are on the sub-fields + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +struct Foo { float2 v; }; + +// This should be allocated a register *after* the render targets +RWStructuredBuffer<Foo> fooBuffer R(: register(u2)); + +struct Fragment +{ + float4 color : SV_Target0; + float4 extra : SV_Target1; + +}; + +Fragment main() +{ + Fragment output; + output.color = use(fooBuffer[42].v); + output.extra = use(fooBuffer[999].v); + return output; +}
\ No newline at end of file diff --git a/tests/bindings/targets-and-uavs.hlsl b/tests/bindings/targets-and-uavs.hlsl new file mode 100644 index 000000000..e5843bed0 --- /dev/null +++ b/tests/bindings/targets-and-uavs.hlsl @@ -0,0 +1,28 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile ps_5_0 -entry main + +// Render target outputs (`SV_Target`) and UAVs are treated +// as sharing the same binding slots in HLSL, so we need to +// make sure that any `u` registers we allocate don't +// interfere with render targets. + +#ifdef __SPIRE__ +#define R(X) /**/ +#else +#define R(X) X +#endif + +float4 use(float val) { return val; }; +float4 use(float2 val) { return float4(val,0.0,0.0); }; +float4 use(float3 val) { return float4(val,0.0); }; +float4 use(float4 val) { return val; }; +float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); } + +struct Foo { float2 v; }; + +// This should be allocated a register *after* the render target +RWStructuredBuffer<Foo> fooBuffer R(: register(u1)); + +float4 main() : SV_Target +{ + return use(fooBuffer[12].v); +}
\ No newline at end of file |
