shader-slang / slang

Making it easier to work with shaders
http://shader-slang.com
Other
2.51k stars 198 forks source link

WGSL target doesn't increase location id for attributes #5633

Open lmariscal opened 20 hours ago

lmariscal commented 20 hours ago

Simple rasterization pipeline shader doesn't increase the location id for the different inputs.

struct VertexOutput {
    float4 position : SV_Position;
    float4 color : F_COLOR;
}

struct VertexInput {
    float2 position : V_POSITION;
    float4 color : V_COLOR;
}

[shader("vertex")]
VertexOutput vert(VertexInput input) {
    var output: VertexOutput;
    output.position = float4(input.position, 0.0, 1.0);
    output.color = input.color;
    return output;
}

struct FragmentInput {
    float4 color : F_COLOR;
}

[shader("fragment")]
float4 frag(FragmentInput input) : SV_Target
{
    return input.color;
}

Output:

struct VertexOutput_0
{
    @builtin(position) position_0 : vec4<f32>,
    @location(0) color_0 : vec4<f32>,
};

struct VertexInput_0
{
    @location(0) position_1 : vec2<f32>,
    @location(0) color_1 : vec4<f32>,
};

@vertex
fn vert( input_0 : VertexInput_0) -> VertexOutput_0
{
    var output_0 : VertexOutput_0;
    output_0.position_0 = vec4<f32>(input_0.position_1, 0.0f, 1.0f);
    output_0.color_0 = input_0.color_1;
    return output_0;
}

struct pixelOutput_0
{
    @location(0) output_0 : vec4<f32>,
};

struct FragmentInput_0
{
    @location(0) color_0 : vec4<f32>,
};

@fragment
fn frag( input_0 : FragmentInput_0) -> pixelOutput_0
{
    var _S1 : pixelOutput_0 = pixelOutput_0( input_0.color_0 );
    return _S1;
}

I would expect the location ids inside VertexInput_0 to increase, so position_1 has @location(0) while color_1 has @location(1).

Have already tried playing with the semantics defined, renaming them, but the output remains the same.

As per the documentation inside "WGSL specific functionalities":

Parameters without semantics are given automatic location indices. (See the @location attribute.)

I would believe they shouldn't even need a user defined semantics.
But if I remove the defined semantics I get the following result:

struct VertexOutput {
    float4 position : SV_Position;
    float4 color : F_COLOR;
}

struct VertexInput {
    float2 position;
    float4 color;
}

[shader("vertex")]
VertexOutput vert(VertexInput input) {
    var output: VertexOutput;
    output.position = float4(input.position, 0.0, 1.0);
    output.color = input.color;
    return output;
}

struct FragmentInput {
    float4 color : F_COLOR;
}

[shader("fragment")]
float4 frag(FragmentInput input) : SV_Target
{
    return input.color;
}

generated:

struct VertexOutput_0
{
    @builtin(position) position_0 : vec4<f32>,
    @location(0) color_0 : vec4<f32>,
};

struct VertexInput_0
{
     position_1 : vec2<f32>,
     color_1 : vec4<f32>,
};

@vertex
fn vert( input_0 : VertexInput_0) -> VertexOutput_0
{
    var output_0 : VertexOutput_0;
    output_0.position_0 = vec4<f32>(input_0.position_1, 0.0f, 1.0f);
    output_0.color_0 = input_0.color_1;
    return output_0;
}

struct pixelOutput_0
{
    @location(0) output_0 : vec4<f32>,
};

struct FragmentInput_0
{
    @location(0) color_0 : vec4<f32>,
};

@fragment
fn frag( input_0 : FragmentInput_0) -> pixelOutput_0
{
    var _S1 : pixelOutput_0 = pixelOutput_0( input_0.color_0 );
    return _S1;
}

Where the attributes inside VertexInput_0 no longer generate @location.

First time diving into slang so I might be missing something.

Commit: fdf061e278720ec066a1fac8f1f35a22e817bf2d OS: Linux

jkwak-work commented 17 hours ago

That seems to be a bug in Slang. I expect that color in VertexInput to have 1 not 0.

csyonghe commented 15 hours ago

Yes, this is a known problem and we are working to address this issue.

aleino-nv commented 10 hours ago

Interestingly, the issue of repeated locations seems to only happen to stage inputs. For example, if I add localPosition between vertex and fragment stages, then its location is numbered correctly for the vertex output, but not for the fragment input.

struct VertexOutput {
    float4 position : SV_Position;
    float2 localPosition : V_LOCAL_POSITION;
    float4 color : F_COLOR;
}

struct VertexInput {
    float2 position : V_POSITION;
    float4 color : V_COLOR;
}

VertexOutput vertexMain(VertexInput input) {
    var output: VertexOutput;
    output.position = float4(input.position, 0.0, 1.0);
    output.localPosition = input.position;
    output.color = input.color;
    return output;
}

struct FragmentInput {
    float4 localPosition : V_LOCAL_POSITION;
    float4 color : F_COLOR;
}

float4 fragmentMain(FragmentInput input) : SV_Target
{
    return input.color + input.localPosition;
}

Resulting WGSL vertex shader (notice repeated/incrementing location index in input/output):

struct VertexOutput_0
{
    @builtin(position) position_0 : vec4<f32>,
    @location(0) localPosition_0 : vec2<f32>,
    @location(1) color_0 : vec4<f32>,
};

struct VertexInput_0
{
    @location(0) position_1 : vec2<f32>,
    @location(0) color_1 : vec4<f32>,
};

@vertex
fn vertexMain( input_0 : VertexInput_0) -> VertexOutput_0
{
    var output_0 : VertexOutput_0;
    output_0.position_0 = vec4<f32>(input_0.position_1, 0.0f, 1.0f);
    output_0.localPosition_0 = input_0.position_1;
    output_0.color_0 = input_0.color_1;
    return output_0;
}

Resulting WGSL fragment shader (notice repeated location index in input):

struct pixelOutput_0
{
    @location(0) output_0 : vec4<f32>,
};

struct FragmentInput_0
{
    @location(0) localPosition_0 : vec4<f32>,
    @location(0) color_0 : vec4<f32>,
};

@fragment
fn fragmentMain( input_0 : FragmentInput_0) -> pixelOutput_0
{
    var _S1 : pixelOutput_0 = pixelOutput_0( input_0.color_0 + input_0.localPosition_0 );
    return _S1;
}
aleino-nv commented 9 hours ago

I created a small fix that seems to fix the repeated input location issue: https://github.com/shader-slang/slang/pull/5642

Input with explicit semantics:

struct VertexOutput {
    float4 position : SV_Position;
    float4 color : F_COLOR;
}

struct VertexInput {
    float2 position : V_POSITION;
    float4 color : V_COLOR;
}

[shader("vertex")]
VertexOutput vert(VertexInput input) {
    var output: VertexOutput;
    output.position = float4(input.position, 0.0, 1.0);
    output.color = input.color;
    return output;
}

struct FragmentInput {
    float4 color : F_COLOR;
}

[shader("fragment")]
float4 frag(FragmentInput input) : SV_Target
{
    return input.color;
}

Output vertex:

struct VertexOutput_0
{
    @builtin(position) position_0 : vec4<f32>,
    @location(0) color_0 : vec4<f32>,
};

struct VertexInput_0
{
    @location(0) position_1 : vec2<f32>,
    @location(1) color_1 : vec4<f32>,
};

@vertex
fn vertexMain( input_0 : VertexInput_0) -> VertexOutput_0
{
    var output_0 : VertexOutput_0;
    output_0.position_0 = vec4<f32>(input_0.position_1, 0.0f, 1.0f);
    output_0.color_0 = input_0.color_1;
    return output_0;
}

Output fragment:

struct pixelOutput_0
{
    @location(0) output_0 : vec4<f32>,
};

struct FragmentInput_0
{
    @location(0) color_0 : vec4<f32>,
};

@fragment
fn fragmentMain( input_0 : FragmentInput_0) -> pixelOutput_0
{
    var _S1 : pixelOutput_0 = pixelOutput_0( input_0.color_0 );
    return _S1;
}

That still doesn't fix the issue where there is no location attribute generated in case no semantics are specified... working on that now.