Raw File
buffer-layout.slang
// buffer-layout.slang

// The goal of this test is to make sure that constant and structured
// buffers obey the rules we expect of the each target API.

//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj

//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;

struct A
{
    float x;
    float y;
}

struct S
{
    // The first field in a struct isn't going to be that
    // interesting, because it will always get offset zero,
    // so we just use this to establish a poorly-aligned
    // starting point for the next field.
    //
    //          offset  size    alignment
    //
    //          0       4       4
    //
    float z;

    // The `std140` and D3D constant buffer ruless both
    // ensure a minimum of 16-byte alignment on `struct`
    // types, but differ in that D3D does not round up
    // the total size of a type to its alignment.
    //
    // The `std430` and structured buffer rules don't
    // perform any over-alignment on `struct` types and
    // instead align them using the "natural" rules one
    // might expect of, e.g., a C compiler.
    //
    //          offset  size    alignment
    //
    // cbuffer  16      8       16
    // std140   16      16      16
    //
    // struct   4       8       4
    // std430   4       8       4
    //
    A      a;

    // Now we insert an ordinary `int` field just as
    // a way to probe the offset so far.
    //
    //          offset  size    alignment
    //
    // cbuffer  24      4       4
    // std140   32      4       4
    //
    // struct   12      4       4
    // std430   12      4       4
    //
    int    b;

    // As our next stress-test case, we will insert an
    // array with elements that aren't a multiple of
    // 16 bytes in size.
    //
    // The contant/uniform buffer rules will set the
    // array stride to a multiple of 16 bytes in this case.
    // The only difference between D3D rules and `std140`
    // here is that D3D does not round up the size to
    // the alignment.
    //
    // The structured/std430 rules don't do anything
    // to over-align an array, so it is laid out relatively
    // naturally, but note that D3D still follows its rule
    // of not letting a vector "straddle" a 16-byte boundary,
    // even if it doesn't bump up the alignment of
    // vector types.
    //
    //          offset  size    alignment
    //
    // cbuffer  32      24      16
    // std140   48      32      32
    //
    // struct   16      16      4
    // std430   16      16      8
    //
    float2 c[2];

    // Now we put in one more ordinary `int` field
    // just to probe the offset computed so far.
    //          offset  size    alignment
    //
    // cbuffer  56      4      4
    // std140   80      4      4
    //
    // struct   32      4      4
    // std430   32      4      4
    //
    int    d;
}

//TEST_INPUT:cbuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32]):name=cb
ConstantBuffer<S> cb;

//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32],stride=4):name=sb
RWStructuredBuffer<S> sb;

int test(int val)
{
    val = val+1;
    val = val*16  + cb.b;
    val = val*256 + cb.d;
    val = val*256 + sb[0].b;
    val = val*256 + sb[0].d;
    return val;
}

[numthreads(4, 1, 1)]
void computeMain(
    int3 dispatchThreadID : SV_DispatchThreadID)
{
    int tid = dispatchThreadID.x;

    int inVal = tid;
    int outVal = test(inVal);
    outputBuffer[tid] = outVal;
}
back to top