gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.15k stars 888 forks source link

[wgsl-in] 'unpackUnorm4x8' : no matching overloaded function found #4525

Open ghost opened 2 years ago

ghost commented 2 years ago

Hi!

On wgpu 0.13 (naga 0.9), I receive the following panic message:

panicked at 'wgpu error: Validation Error

Caused by:
    In Device::create_render_pipeline
    Internal error in VERTEX shader: ERROR: 0:52: 'unpackUnorm4x8' : no matching overloaded function found
ERROR: 0:52: '=' : dimension mismatch
ERROR: 0:52: 'assign' : cannot convert from 'const mediump float' to 'highp 4-component vector of float'

'

Here's the offending code:

struct Output {
    @builtin(position)
    pos: vec4<f32>,
    @location(0) @interpolate(flat)
    flags: u32,
    @location(1) @interpolate(perspective, center)
    color: vec4<f32>,
    @location(2) @interpolate(perspective, center)
    tex_pos: vec2<f32>,
    @location(3) @interpolate(flat)
    pal_pos: vec2<u32>,
    @location(4) @interpolate(flat)
    tex_page_x: u32
}

fn make_tex_coord(coord: u32, max: f32) -> f32 {
    return f32(coord) / max;
}

fn make_tex_pos(pos: vec2<u32>, bounds: vec2<f32>) -> vec2<f32> {
    return vec2<f32>(
        make_tex_coord(pos.x, bounds.x),
        make_tex_coord(pos.y, bounds.y),
    );
}

fn make_ndc(coord: u32, max: f32) -> f32 {
    return (2.0 * make_tex_coord(coord, max)) - 1.0;
}

@vertex
fn main(
    @location(0) pos: vec2<u32>,
    @location(1) packed: vec2<u32>,
    @location(2) color: u32,
    @location(3) tex_pos: vec2<u32>,
    @location(4) pal_pos: vec2<u32>,
) -> Output {
    let vram_bounds = vec2<f32>(1024.0, 512.0);

    var out: Output;
    out.pos = vec4<f32>(
        // [0, 1024) -> [-1.0, 1.0].
        make_ndc(pos.x, vram_bounds.x),
        // [0, 512)  -> [-1.0, 1.0].
        make_ndc(pos.y, vram_bounds.y) * -1.0,
        0.0,
        1.0,
    );
    out.flags = packed.x;
    out.color = unpack4x8unorm(color);
    out.tex_pos = vec2<f32>(tex_pos);
    out.pal_pos = pal_pos;
    out.tex_page_x = packed.y;
    return out;
}

...of which line 52 is out.tex_pos = vec2<f32>(tex_pos);. That doesn't seem to be where the error is, though. (One-off bug?) Line 51 reads out.color = unpack4x8unorm(color);, which is where I think the error arises. I think my code is correct according to the spec, though; color is a u32, and out.color is a vec4<f32>, which matches the unpack4x8unorm function signature.

For what it's worth, my shader code was previously validated correctly on wgpu 0.12 (naga 0.8).

ghost commented 2 years ago

Nevermind about the "one-off" bug. What I think is happening here is that naga is transpiling my code to GLSL, and compiling the resultant GLSL fails. Thus, the error message seems to be from OpenGL—not naga—so the referenced line number is probably correct w.r.t the GLSL code.

To see what's actually happening, I'll try transpiling manually with the naga CLI and inspecting the GLSL output.

ghost commented 2 years ago

Here's the GLSL output:

#version 310 es

precision highp float;
precision highp int;

struct Output {
    vec4 pos;
    uint flags;
    vec4 color;
    vec2 tex_pos;
    uvec2 pal_pos;
    uint tex_page_x;
};
layout(location = 0) in uvec2 _p2vs_location0;
layout(location = 1) in uvec2 _p2vs_location1;
layout(location = 2) in uint _p2vs_location2;
layout(location = 3) in uvec2 _p2vs_location3;
layout(location = 4) in uvec2 _p2vs_location4;
layout(location = 0) flat out uint _vs2fs_location0;
layout(location = 1) smooth out vec4 _vs2fs_location1;
layout(location = 2) smooth out vec2 _vs2fs_location2;
layout(location = 3) flat out uvec2 _vs2fs_location3;
layout(location = 4) flat out uint _vs2fs_location4;

float make_tex_coord(uint coord, float max) {
    return (float(coord) / max);
}

vec2 make_tex_pos(uvec2 pos_1, vec2 bounds) {
    float _e4 = make_tex_coord(pos_1.x, bounds.x);
    float _e7 = make_tex_coord(pos_1.y, bounds.y);
    return vec2(_e4, _e7);
}

float make_ndc(uint coord_1, float max_1) {
    float _e3 = make_tex_coord(coord_1, max_1);
    return ((2.0 * _e3) - 1.0);
}

void main() {
    uvec2 pos = _p2vs_location0;
    uvec2 packed = _p2vs_location1;
    uint color = _p2vs_location2;
    uvec2 tex_pos = _p2vs_location3;
    uvec2 pal_pos = _p2vs_location4;
    Output out_ = Output(vec4(0.0), 0u, vec4(0.0), vec2(0.0), uvec2(0u), 0u);
    vec2 vram_bounds = vec2(1024.0, 512.0);
    float _e12 = make_ndc(pos.x, vram_bounds.x);
    float _e15 = make_ndc(pos.y, vram_bounds.y);
    out_.pos = vec4(_e12, (_e15 * -1.0), 0.0, 1.0);
    out_.flags = packed.x;
    out_.color = unpackUnorm4x8(color);
    out_.tex_pos = vec2(tex_pos);
    out_.pal_pos = pal_pos;
    out_.tex_page_x = packed.y;
    Output _e30 = out_;
    gl_Position = _e30.pos;
    _vs2fs_location0 = _e30.flags;
    _vs2fs_location1 = _e30.color;
    _vs2fs_location2 = _e30.tex_pos;
    _vs2fs_location3 = _e30.pal_pos;
    _vs2fs_location4 = _e30.tex_page_x;
    gl_Position.yz = vec2(-gl_Position.y, gl_Position.z * 2.0 - gl_Position.w);
    return;
}

Line 52 is out_.color = unpackUnorm4x8(color);.

JCapucho commented 2 years ago

The code looks perfectly fine and glslangValidator agrees, can we get some more information about the platform you're trying to run this in, and can you also test if it happens in others?

VincentJousse commented 1 year ago

Hello, same problem here, I use wgpu and I target wasm, so WebGL.

ghost commented 1 year ago

The code looks perfectly fine and glslangValidator agrees, can we get some more information about the platform you're trying to run this in, and can you also test if it happens in others?

Sorry; I forgot to respond. Yes, I also encountered this while targeting WASM. I will look at this later today.

Wumpf commented 1 year ago

Isn't the actual issue here that OpenGL ES 3.0 / WebGL2 flavored GLSL doesn't have unpackUnorm4x8 and friends? According to this they are introduced in 4.00 whereas, ES3/WebGL2 are based on 3.30 https://registry.khronos.org/OpenGL-Refpages/gl4/html/unpackUnorm.xhtml

(EDITS: Had some misconceptions about shader & webgl version matching)

bconnorwhite commented 1 year ago

@Wumpf I'm able to use unpack2x16unorm and unpack2x16snorm despite the Kronos page showing them as not in 3.3. Only unpack4x8unorm and unpack4x8snorm give the error

teoxoy commented 10 months ago

are only available starting with GLSL ES 3.10, so WebGL 2 won't have these.

We should error in this case ourselves to avoid confusion.

Links

https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf https://registry.khronos.org/OpenGL/specs/es/3.1/GLSL_ES_Specification_3.10.pdf

cwfitzgerald commented 10 months ago

Shouldn't we polyfill them, these are already some of the ones that we polyfill for hlsl, and they're trivially polyfillable.

wainwrightmark commented 9 months ago

Just for reference I'm having a similar issue trying to use extractbits

I get the error message 'bitfieldExtract' : no matching overloaded function found when targeting wasm (it works fine otherwise).

I imagine this would be easy to polyfill.