-
Notifications
You must be signed in to change notification settings - Fork 329
Description
The spec says:
Let p be a new Promise.
...
Enqueue an operation on the default queue’s Queue timeline that will execute the following:
...
Resolve p.
This is a bit unfortunate; it means that mapping is blocked on queue commands which are entirely unrelated to the buffer being mapped. Consider a program like this:
let bufferA = device.createBuffer(...);
let bufferB = device.createBuffer(...);
let commandEncoder1 = device.createCommandEncoder();
commandEncoder1.copyBufferToBuffer(bufferA, 0, someOtherBuffer, 0, 4); // Super small operation. Doesn't touch bufferB
let commandBuffer1 = commandEncoder1.finish();
let commandEncoder2 = device.createCommandEncoder();
populateCommandEncoderWithSuperIntensiveOperationsWith(bufferB); // Doesn't touch bufferA
let commandBuffer2 = commandEncoder1.finish();
device.queue.submit([commandBuffer1, commandBuffer2]);
bufferA.mapAsync(...).then(...); // Requires waiting for the super intensive operation to finish, despite bufferA being idle much earlier than that
When you use a bind group in a render/compute pass, we already have to check the state of all the buffers in that bind group to make sure they're not mapped, so it would seem pretty cheap for each buffer to have a "in-flight count" counter inside it. The count would represent the number of command buffers which have been submitted and not yet finished that reference this buffer. Each command buffer would have to remember all the resources it references, so they can have their counts decremented when the command buffer finishes. Then, the map promise could resolve when the in-flight count for that buffer reaches 0, rather than having to wait for all work on the queue to complete like the spec says today.