这是indexloc提供的服务,不要输入任何密码
Skip to content

Add @builtin(renderbundle_index) #5158

@greggman

Description

@greggman

Imagine you want to draw a render bundle twice in 2 different places. Your options are

Use a submit per draw

// update the buffer with data for the first draw
device.queue.writeData(bufferRenderBundleUses, 0, data1); 

{
  const encoder = device.createCommandBufferEncoder();
  const pass = encoder.beginRenderPass(...);
  pass.executeBundle([renderBundle]);
  pass.end();
  device.queue.submit([encoder.finish()]);
}

// update the buffer with data for the second draw
device.queue.writeData(bufferRenderBundleUses, 0, data2); 

{
  const encoder = device.createCommandBufferEncoder();
  const pass = encoder.beginRenderPass(...);
  pass.executeBundle([renderBundle]);
  pass.end();
  device.queue.submit([encoder.finish()]);
}

Use 1 or more source buffers to copy to a buffer the render bundle uses

This requires a pass per call to executeBundles so you can update the buffer the bundle
is using between passes

device.queue.writeData(dataForPlace1Buffer, 0, data1);
device.queue.writeData(dataForPlace2Buffer, 0, data2);

const encoder = device.createCommandBufferEncoder();

// update the buffer with data for the first draw
encoder.copyBufferToBuffer(dataForPlace1Buffer, 0, bufferRenderBundleUses); 
{
  const pass = encoder.beginRenderPass(...);
  pass.executeBundle([renderBundle]);
  pass.end();
}

// update the buffer with data for the second draw
encoder.copyBufferToBuffer(dataForPlace2Buffer, 0, bufferRenderBundleUses); 
{
  const pass = encoder.beginRenderPass(...);
  pass.executeBundle([renderBundle]);
  pass.end();
}

device.queue.submit([encoder.finish()]);

@builtin(renderbundle_index)

What if we introduced @builtin(renderbundle_index). Then you could write WGSL like

struct BundleData {
  matrix: mat4x4f,
};
@binding(0) @group(0) var<storage> perBundleData: array<BundleData>;

@vertex fn vs(@builtin(renderbundle_index) bundle_ndx: u32, 
              @location(0) position: vec4f) -> @builtin(position) vec4f {
  return perBundleData[bundle_ndx].matrix * position;
}

And you could execute it by filling out a buffer 2 or more BundleData structs and then

const encoder = device.createCommandBufferEncoder();
const pass = encoder.beginRenderPass(...);
pass.executeBundle([renderBundle, renderBundle]);
pass.end();

This would execute renderBundle 2 times but each time it would have a different value for bundle_ndx. It would be 0 outside of a render bundle.

I'm throwing this out there (I think @toji might have mentioned it before) to have it written down as a topic. It seems simple to implement without too many side effects.

There might be other more generic solutions like being able to update a binding or via immediate data or something else that is not reset between bundles but I just thought we should consider this simple solution as yet another possible way forward.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiWebGPU API

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions