Uniform Buffer Object (UBO) and WebGPU

I am currently porting a scientific application from WebGL to WebGPU:
A simulation of an ultrasound phased array, for the ones interested:

After finding out that I can continue using GLSL as a shading language, I try to touch these later, after get most of the stuff running.
I am currently struggling getting a Uniform Buffer up and running. Because I am working for a while on this, I do already have a playground that more or less isolates the problem:
(from UniformBuffer.addUniform: Arguments unclear)

It shows a cube that is rendered using a custom material that consumes a Uniform Buffer. When switching this playground to WebGPU, I get the following error:

glslang.js:34 ERROR: 0:20: 'binding' : uniform/buffer blocks require layout(binding=X) 

I tried modifying the playground to:

  • Add a binding=1 to the layout qualifier of the UBO declaration in the shader.
  • Add shaderMaterial.getEffect().bindUniformBlock('myBuffer', 1)

Looks like this is not enough. I get other cryptic error messages.

Does anyone know how to fix it and make the playground work or is there a playground with a working example of a UBO working with WebGPU?

Bonus question: Is a UBO still state of the art? I see that they are disabled by default on Mac and I remember from the desktop days that there is “Shader Storage Buffers”. Any comments on this?

Best regards and thanks to everyone,

We only support a subset of the syntax used to declare an ubo in the shader when converting from WebGL to WebGPU.

See how I fixed your PG:

If you want more freedom, you can write the shader directly in WGSL (but this will only work with WebGPU, of course!).

Yes, ubo are still the fastest way to pass data to the shader, but they are limited to a few kilobytes of data (around 64k). If you want to pass more data, you will have to use a texture or a storage buffer (available only in WebGPU). It’s disabled on Mac because of a Safari bug (I’m not sure it’s disabled for all versions, though)…

1 Like

Thank you. So I see two big differences:

  1. You made the shader declaration a bit simpler, removing the layout at all and removed the struct.
  2. You set the buffer on every bind of the shader. Is this necessary? or is it just a bridge solution?

So my strategy will be: After now having all building (AFAIK), I will start porting my shaders to WGSL and then see :slight_smile:.

In fact, that’s what you did (shader.onBind is called each time a mesh is drawn), but I removed it. I simply do shaderMaterial.setUniformBuffer('myBuffer', buffer); once to set the ubo.

Right, I read the diff in the wrong direction, sorry for that.