-
Notifications
You must be signed in to change notification settings - Fork 329
Description
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.