https://github.com/shader-slang/slang
Raw File
Tip revision: e698b4ae92b996ac54d023c831170a5467b2d1a0 authored by Sai Praveen Bangaru on 28 September 2023, 05:45:09 UTC
Remove `[NoSideEffect]` from `DiffTensorView.store()` (#3247)
Tip revision: e698b4a
tagged-union.slang
// tagged-union.slang
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
//DISABLED_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute


// The goal of this test is to show that we can generate
// dynamic-dispatch logic from Slang code written using
// interface+generics, entirely from the compiler API side
// and without code changes.

// We are going to define a dummy interface just for testing
// purposes, that can be used to see which implementation
// got invoked at runtime.
//
interface IFrobnicator
{
    int frobnicate(int value);
}

// Now we will define two different implementations that
// "frobnicate" values differently. The first will just
// add to the value from a member variable.
//
struct A : IFrobnicator
{
    int a;
    int frobnicate(int value)
    {
        return value + a;
    }
}

// The second implementation will have an additional field
// of local state, and will do a tiny bit more math.
//
struct B : IFrobnicator
{
    int b;
    int y;
    int frobnicate(int value)
    {
        return value * b + y;
    }
}

[numthreads(4, 1, 1)]
void computeMain
// Now we will define the generic type parameter for our shader,
// which will be constraints to be a type that implements our
// `IFrobnicator` interface.
//
    <T : IFrobnicator>
//
// For the actual test runner, we will instruct it to plug in
// a tagged-union type over the two concrete implemetnations.
// Note that while we are writing this line in the source file,
// it is in comments so that the Slang compiler only knows about
// our intention when it is informed via the API.
//
//TEST_INPUT: type __TaggedUnion(A,B)
    (
// Next we need to pass in the actual parameter data for our
// chosen `IFrobnicator` implementation. The decalration of
// the constant buffer follows the conventional approach for
// using global generic parameters, so there is nothing much
// to say.
//
// Note: We are not using `ParameterBlock<_>` here because
// the `render-test` tool doesn't yet support code that
// uses multiple descriptor tables/sets.
//
    uniform ConstantBuffer<T> gFrobnicator,

// Where things get interesting is when we go to provide the
// data that will be used by the parameter block.
//
// Because we are plugging in a taggd union type, the actual
// data type that we fill in will be something kind of like:
//
//      struct S { union { A a; B b; }; uint tag; };
//
// When compiling for D3D, the size of that union will be
// 8 bytes (for the largest case), and so the tag will come
// as the third 32-bit value. We will initialize our data
// buffer for a `B` value then, which will get the tag `1`
// since it was the second option in our `__TaggedUnion`.
//
// In the Vulkan case the size of both `A` and `B` is 16 bytes
// (because they round up structure sizes to their alignment)
// and so the tag value will be the fifth 32-bit value.
// We will thus set up the same data buffer to look like an `A`
// value to Vulkan!
//
//TEST_INPUT: cbuffer(data=[16 9 1 0 0], stride=4):


//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out
    uniform RWStructuredBuffer<int> gOutputBuffer,
    uint3 dispatchThreadID : SV_DispatchThreadID)
{
    uint tid = dispatchThreadID.x;

    int val = tid;
    val = gFrobnicator.frobnicate(val);

    gOutputBuffer[tid] = val;
}
back to top