slang
slang copied to clipboard
Interface with 2 implementations from separate compiled slang-modules -> crash
So I have this simple interface and the following simple shader:
// emitter.slang
public interface IEmitter<Real : __BuiltinFloatingPointType> {
[Differentiable] vector<Real, 3> illuminate(vector<Real, 3>, vector<Real, 3>);
[Differentiable] vector<Real, 3> sample();
}
import emitter;
StructuredBuffer<IEmitter<float>> emitters;
RWStructuredBuffer<float> outputBuffer;
[shader("compute")]
[numthreads(1, 1, 1)]
void main(uint3 dispatchThreadID: SV_DispatchThreadID)
{
vector<float, 3> P = { 0.0, 0.0, 0.0 };
vector<float, 3> N = { 0.0, 1.0, 0.0 };
outputBuffer[0] = emitters[0].illuminate(P, N).x;
}
I compile two different implementations (PointLight and SpotLight) of this interface to two slang-modules, which then get added when compiling the main shader above. If I only use one implementation it compiles but when using two, it results in a crash.
Directly compiling to spirv gives me "Unhandled global inst in spirv-emit: witness_table %1 : %2(%PointLight);" Compiling to glsl gives me an internal error 99999
So the problem comes from the last line where the compiler has an kIROp_swizzle with kIROp_WitnessTable as operand0, which then in the func defaultEmitInstExpr can not be handled and results in the error.
https://github.com/fknfilewalker/dyslang contains the code
tests/load_plugins_one works but tests/load_plugins_two crashes (only tried it on windows)
DYSLANG_SLANG_FROM_SUBMODULE TRUE uses the latest github code.
Seems to be a problem with generics in interfaces. Removing them fixes the problem.
I got this error as well. But I can trigger it without a generic interface and without using multiple modules. This is as close to a minimal example as I could get.
RWStructuredBuffer<float> buffer;
void doSomethingToBuffer() {
buffer[0] += 0.0;
}
interface Processor {
void process();
}
struct Layer<let SIZE : uint> : Processor {
void process() {
doSomethingToBuffer();
}
}
struct Wrapper {
Processor inner;
void run() {
inner.process();
}
}
void eval() {
Wrapper(Layer<1>()).run();
}
[shader("compute")]
[numthreads(64, 1, 1)]
void computeMain()
{
eval();
}
Has this error when compiling:
(0): error 99999: Slang compilation aborted due to an exception of class Slang::InternalError: unimplemented: Unhandled global inst in spirv-emit:
witness_table %1 : %2(%Layer);
I think I've ran into the same problem as well, on the CPU target as well as SPIR-V, with a slightly different approach.
interface IThingy
{
void message();
}
struct SpecificThingy: IThingy
{
void message() { printf("Specific\n"); }
};
struct GenericThingy<T>: IThingy
{
void message() { printf("Generic\n"); }
};
// For CPU
export __extern_cpp int main()
{
IThingy thingies[1];
thingies[0] = GenericThingy<int>();
//thingies[0] = SpecificThingy();
thingies[0].message();
return 0;
}
// For SPIR-V
[shader("fragment")]
float4 fragMain(float4 fragCoord : SV_Position) : SV_Target
{
IThingy thingies[1];
thingies[0] = GenericThingy<int>(10);
//thingies[0] = SpecificThingy();
thingies[0].message();
return float4(0, 0, 0, 1);
}
If thingies is not an array or SpecificThingy is used instead of GenericThingy, this compiles just fine on both the CPU and SPIR-V targets. The SPIR-V error is the same as the ones posted before on this issue:
(0): error 99999: Slang compilation aborted due to an exception of N5Slang13InternalErrorE: unimplemented: Unhandled global inst in spirv-emit:
witness_table %1 : %2(%GenericThingy);
The CPU one is interesting too:
gcc 13.3: test.slang(16): error : ‘_S4’ was not declared in this scope; did you mean ‘_S3’?
16 | export __extern_cpp int main()
| ^
| _S3
The part of the intermediate C++ that causes this is:
int32_t main()
{
#line 16
Tuple_0 _S3 = { Vector<uint32_t, 2> (0U, 0U), (&_S4) };
#line 22
_S1(_S3);
return int(0);
}
There indeed is no _S4.
EDIT: Debug notes in case I don't end up having the time to fix this myself.
- IR in BEFORE-LOWER-GENERICS is identical (bar some [export()] lines) between SpecificThingy & GenericThingy
- IR in AFTER-LOWER-GENERICS has differences. A WitnessTable is left in the output for GenericThingy, but not for SpecificThingy. It probably shouldn't be there anymore.
- IR starts to differ in
specializeRTTIObjects(slang-ir-lower-generics.cpp), SequentialIDDecoration not set on witness table of GenericThingy - SequentialIDDecoration is not added for GenericThingy's witness table because LinkageDecoration is missing in
ensureWitnessTableSequentialIDs - I see two ways to fix this:
- Add another special case to
ensureWitnessTableSequentialIDsto add the ID in these cases - Make
addLinkageDecorationnot look for the outermost generic or make it possible to optionally skip that.
- Add another special case to
Fixed by https://github.com/shader-slang/slang/pull/6129