greggman / webgpu-utils

Some helpers for webgpu
https://greggman.github.io/webgpu-utils/
MIT License
180 stars 9 forks source link

setting a value in a uniform that's an array of structures #11

Open jowens opened 2 days ago

jowens commented 2 days ago

Respectfully requesting enhancing the makeStructuredView with an example of setting a structure (or a partial structure) that's part of a member of structures. "Views" are complicated, and I don't have my mind wrapped around them yet, but I did this wrong many many ways before doing it by hand, and I bet there's a much cleaner way to do it.

const uniformsCode = /* wgsl */ `
  const MAX_LEVEL = 10;
  struct Level {
    f: u32, e: u32, v: u32, t: u32,
  };
  struct MyUniforms {
    uni1: f32,
    uni2: f32,
    @align(16) levelCount: array<Level, MAX_LEVEL>,
    @align(16) levelBasePtr: array<Level, MAX_LEVEL>,
  };
  @group(0) @binding(0) var<uniform> myUniforms: MyUniforms;`;

I'd then like to set levelCount, which I'm (sadly) doing as:

for (let j = 0; j <= mesh.maxLevel; j++) {
  uni.views.levelCount[j].f[0] = mesh.levelCount[j].f;
  uni.views.levelCount[j].e[0] = mesh.levelCount[j].e;
  uni.views.levelCount[j].v[0] = mesh.levelCount[j].v;
  uni.views.levelCount[j].t[0] = mesh.levelCount[j].t;
}

Surely this can be done with less code.

An example of how to set a structure (or a piece of structure) when that structure is within an array would be helpful.

greggman commented 1 day ago

You can set the whole thing like this

const v = makeStructuredView(defs.uniforms.myUniforms);
v.set({
  uni1: 123,
  uni2: 456,
  levelCount: [
    { f: 1, e: 2, v: 3, t: 4 },
    { f: 5, e: 6, v: 9, t: 2 },
    ...
  ],
  levelBasePtr: [
    { f: 1, e: 2, v: 3, t: 4 },
    { f: 5, e: 6, v: 9, t: 2 },
    ...
  ],
});

You can set portions. Example

const v = makeStructuredView(defs.uniforms.myUniforms);
v.set({
  uni2: 456,
});

v.set({
  levelBasePtr: [
    { f: 1, e: 2, v: 3, t: 4 },
    { f: 5, e: 6, v: 9, t: 2 },
    ...
  ],
});

If you want to set arrays of structs sparcely it gets harder as you need to make the input sparce to match

v.set({
  levelBasePtr: [
    ,
    ,
    { f: 1, e: 2, v: 3, t: 4 },
  ],
});

Set's only levelBasePtr[2]

Looking at your code above, it looks like you could do this

v.set({ levelCount: mesh.levelCount });
greggman commented 1 day ago

Checking, you can also set sparse arrays like this

// Sets f and t of levelBasePtr[9]
setStructuredView({ f: 112233, t: 445566 }, v.views.levelBasePtr[9]);
jowens commented 1 day ago

This is splendid. Thank you. My frantic "try everything" was not nearly as successful as your knowledge-based suggestions. Perhaps good additions to the docs?