-
Notifications
You must be signed in to change notification settings - Fork 344
Description
(Based on #5117 ).
There are three options.
option 1: Snapshot content
During bundle encoder stage, snapshot the content of [[immediate_data]] before each draw/dispatch call. And when calling executeBundle, replay all of the commands and the contents. It might benefit the case that use the single js array to update immediate data and update array contents between draw/dispatch calls :
// data: {1, 2, 3, 4} => update [[immediate_data]] {1, 2, 3, 4}
let data[] = [1, 2, 3, 4];
bundleEncoder.setImmediateData(0, data, dataSize);
// pipeline has layout with 16 byte immediate data range
bundleEncoder.setPipeline(pipeline0);
// shader access {1, 2, 3, 4}, bundle snapshot the content {1, 2, 3, 4}
bundleEncoder.draw(...);
// data: update to {1, 6, 7, 4} => update [[immediate_data]] {1, 6, 7, 4}
data[1] = 6;
data[2] = 7;
bundleEncoder.setImmediateData(0, data, dataSize);
// pipeline has layout with 16 byte immediate data range
bundleEncoder.setPipeline(pipeline0);
// shader access {1, 6, 7, 4}, bundle snapshot the content {1, 6, 7, 4}
bundleEncoder.draw(...)
const bundle = bundleEncoder.finish();
....
delete data[]; // destroy data.
// And the bundle will apply:
// {1, 2, 3, 4} to make first draw call shader could get {1, 2, 3, 4} through immediate data.
// {1, 6, 7, 4} to make second draw call shader could get {1, 6, 7, 4} through immediate data.
passEncoder.executeBundle(bundle);
option2: Record the command but fetch the latest js array content
During bundle encoder stage, just record the command and the address that fetch CPU data. And when calling executeBundle, replay all of the commands but fetch CPU data from the recorded address. It makes developer could modify js array content to generate different rendering result through bundle (Quite similar to BindGroup in bundle). A typical case would be:
// data0: {1, 2, 3, 4} => update [[immediate_data]] {1, 2, 3, 4}
let data0 [] = [1, 2, 3, 4];
bundleEncoder.setImmediateData(0, data, dataSize);
// pipeline has layout with 16 byte immediate data range
bundleEncoder.setPipeline(pipeline0);
// shader access {1, 2, 3, 4}, bundle snapshot the content {1, 2, 3, 4}
bundleEncoder.draw(...);
// data1: {1, 6, 7, 4} => update [[immediate_data]] {1, 6, 7, 4}
let data1[] = {1, 6, 7, 4}
bundleEncoder.setImmediateData(0, data1, dataSize);
// pipeline has layout with 16 byte immediate data range
bundleEncoder.setPipeline(pipeline0);
// shader access {1, 6, 7, 4}, bundle snapshot the content {1, 6, 7, 4}
bundleEncoder.draw(...)
const bundle = bundleEncoder.finish();
// update data0 content to {1, 8, 10, 4}
data0[1] = 8;
data0[2] = 10;
// update data1 content to {5, 6, 7, 4}
data1[0] = 5;
// And the bundle will apply:
// fetch data0 content, which are {1, 8, 10, 4} to make first draw call shader could get {1, 8, 10, 4} through immediate data.
// fetch data1 content {5, 6, 7, 4} to make second draw call shader could get {5, 6, 7, 4} through immediate data.
passEncoder.executeBundle(bundle);
option 3: Don't support SetImmediateData() in GPURenderBundle
We don't support SetImmediateData() command as bundle command to avoid above state things.
I prefer option 2 because it is quite similar for what we do now for uniform buffer in bundles.