shader-slang / slang

Making it easier to work with shaders
MIT License
2.05k stars 175 forks source link

Incorrect initializers when using interfaces #4464

Closed tomas-davidovic closed 2 months ago

tomas-davidovic commented 3 months ago

Another interface problem.

When this slang program is compiled, it has conformances issues. InitializerTestsInterface.cs.slang.txt When conformances are provided as: conformances.add("Test0", "ITest", 0); conformances.add("Test1", "ITest", 1); conformances.add("TestAny", "ITest", 2); the following HLSL code is produced, which seems to have duplicate ID for both Test0 and Test1 (see lines 50 and 76 in Tuple_0 makeTest0_0() and Tuple_0 makeTest1_0() respectively). 1.hlsl.txt

When no conformances are provided, all three structs seem to have the same ID 0. This manifests in the test itself failing, mostly in the Test1 part of it.

When conformances are provided without explicit IDs (i.e., ID is uint(-1)), then it does not auto-assign IDs and will fail to compile on the dxc level, complaining that it has two cases with 4294967295U, viz: UndefinedID.hlsl.txt

Trying to limit the code only to a small case, the code fails to compile when conformances aren't provided (cannot figure them out on its own), but succeeds when conformance is provided (possibly because it compiles out all the other implementations, so duplicate assignment of ID is not an issue). InitializerTestsFails.cs.slang.txt

jkwak-work commented 3 months ago

The given code is attempting to test multiple factors. I made it simpler.

//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=VK):-vk -compute
//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=VK):-vk -compute -xslang -DREPRO
interface ITest
{
    uint getValue();
};

struct Test0 : ITest
{
    uint getValue() { return 1; }
};

struct Test1 : ITest
{
    uint getValue() { return 2; }
};

ITest make0() { return Test0(); }
ITest make1() { return Test1(); }

uint getValue<Test : ITest>(Test t)
{
    return t.getValue();
}

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

[numthreads(4, 1, 1)]
void computeMain(int3 dispatchThreadID: SV_DispatchThreadID)
{
#if defined(REPRO)
    ITest t0 = make0();
    ITest t1 = make1();
#else
    Test0 t0;
    Test1 t1;
#endif
    outputBuffer[0] = getValue(t0) + getValue(t1);
    //VK:3
}

It seems like a trouble happens when up-casting from a concrete type to an interface type like ITest = Test0();.