Bug in unpack4xU8 or user error?

13 views
Skip to first unread message

Mark Sibly

unread,
Mar 7, 2024, 4:14:49 PMMar 7
to Dawn Graphics
Hi,

Not sure if this is the right place to ask this, perhaps it should be at the webgpu 'matrix' site? Please advise moderators.

My excuse for asking here is it may be a bug and involves C++ which may or may not be relevant to my problem, but I also kind of dislike discord/matrix style sites for support anyway, 90% of the time your question just disappears in an endless stream of discussion, unanswered and perhaps even unread (esp. if it's longish) who knows? And there's no way to even gauge what questions have already been asked - there are no 'topics' or even email threads to browse/search. What am I missing with the appeal of these places?

Anyway, enough grumbling...

Unless I'm using it wrong, I think there's a bug in unpack4xU8. I am using unpack4xU8 to extract joint indices from a vertex, eg:

// C++
struct Vertex {
    Vec3f position;
    Vec3f normal;
    Vec4f color;
    uint8_t joints[4];  // 4 joint indices - each element is used to index an array of joint matrices (not shown here).
    float weights[4];
};
// END C++

// WGSL
struct Vertex {
@location(0) position: vec3f,
    @location(1) normal: vec3f,
    @location(2) color: vec4f,
@location(3) joints: u32,
    @location(4) weights: vec4f,
};

struct Varying {
    ...
};

@vertex fn vertexMain(vertex: Vertex, @builtin(instance_index) instanceId : u32) -> Varying {

    let joints = unpack4xU8(vertex.joints);
   
    // OK, joints.x, joints.y, joints.z and joints.w should now contain the same integral indexes that were passed in the vertex, correct?
   
    var out: Varying...
   
    ...
   
    return out;
}
// END WGSL

However it doesn't seem to work correctly for any vertex joints[] value except the 0th. For example, if I write the vec4<u32> joints value directly to the output fragment color like this...

out.color = vec4f(joints) / 255;

...and return this value as the output fragment color from the fragment shader, I get red for joints values of 255,0,0,0 as expected, but I don't get green or blue for 0,255,0,0 or 0,0,255,0 I just get black. I have tried it with 127, 63 too, still just black. I get red for 255,255,0,0 too, not yellow.

Am I using unpack4xU8 properly?

My vertex buffer attributes are:

// C++
wgpu::VertexAttribute vertexBufferAttribs[]{
{wgpu::VertexFormat::Float32x3, 0, 0}, // Vec3f position
{wgpu::VertexFormat::Float32x3, 12, 1}, // Vec3f normal
{wgpu::VertexFormat::Float32x4, 24, 2}, // Vec4f color
{wgpu::VertexFormat::Uint8x4, 40, 3}, // Vec4ub joints
{wgpu::VertexFormat::Float32x4, 44, 4}, // Vec4f weights
};
static_assert(sizeof(Vertex) == 60);
// END C++

I have since changed the joint system to use float[4]/vec4f instead of uint8_t[4]/u32/unpack4xU8 and everything works as expected, my skinned meshes actually work!

Also works with uint32_t[4]/vec4u.

Bye,
Mark

Gregg Tavares

unread,
Mar 7, 2024, 5:01:26 PMMar 7
to Mark Sibly, Dawn Graphics
{wgpu::VertexFormat::Uint8x4, 40, 3}, // Vec4ub joints

Tells webgpu to unpack for you so there would be no need to call `unpack4xU8`.  

Change 

@location(3) joints: u32,

to this?

@location(3) joints: vec4u,



--
You received this message because you are subscribed to the Google Groups "Dawn Graphics" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dawn-graphic...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dawn-graphics/0fb844f8-a6a4-400b-98b9-557158c9ee26n%40googlegroups.com.

Mark Sibly

unread,
Mar 7, 2024, 7:05:51 PMMar 7
to Gregg Tavares, Dawn Graphics
HI,

> wgpu::VertexFormat::Uint8x4, 40, 3}, // Vec4ub joints

This is the problem, thank you!

I wrote it assuming there'd be an equivalent type in WGSL, but it appears there isn't hence the need for unpack4xU8. Vec4u is Uint32x4 which is16 bytes per vertex, while Uint8x4 is only 4 bytes which is all I need.

But I just tried changing the wgpu::VertexFormat for joints to plain Uint32 and it fixed the unpack4xU8 issue so my bad.

This does make sense, but it makes me think something's not quite getting validated properly here. Should Uint8x4 even be a valid vertex format if it has no equivalent in WGSL?

Bye,
Mark


So, not a bu

Anything, thanks for the hnt,

Gregg Tavares

unread,
Mar 7, 2024, 7:20:11 PMMar 7
to Mark Sibly, Dawn Graphics
attributes are always vec4<X>  Defaults are vec4<X>(0,0,0,1)

What you declare in the pipeline is which parts of those vec4<X> attributes are supplied with data for each location

What you declare in WGSL is which of those vec4<X> attributes you'll read for each location

They aren't required to match except I think f32 vs u32 vs i32.

It's common to supply float32x2 (2d data) in the pipeline but use vec4f in the shader as z,y will be 0, 1 which is what you'd need anyway. Similarly pass in float32x3 (3d positions) but read vec4f in the shader. z defaults to 1

I think this is common in most GPU APIs.

 

Mark Sibly

unread,
Mar 8, 2024, 4:25:19 PMMar 8
to Gregg Tavares, Dawn Graphics
I think I finally have my head around this.

I was aware that shaders would fill in 'missing' vec4 attrib components, but for some reason I had assumed the byte size of attrib components needed to match in C++ and WGSL.

But this is not true, using Uint8x4 (4 bytes) in C++ and vec4u (16 bytes) in WGSL is perfectly valid and works fine without the need for any unpack nonsense, which is great.

Thanks for all the hints and help.




Reply all
Reply to author
Forward
0 new messages