-
Notifications
You must be signed in to change notification settings - Fork 329
Description
Edit: this proposal originates in #156 known as "buffer views"
I tried really hard to make some proposal for buffer partitioning that makes sense but the best I could get is what's below. It has major flaws and I wouldn't want it as part of WebGPU but I'm posting it because it was promised, and because maybe someone will inspiration for a better idea.
Feel free to not read if you're not interested in my rambling.
Buffer partitioning
This is a proposal for how buffers could be split in such a way that one piece of the buffer if mapped while another is in use by the GPU.
The basic requirement was that UBOs could be ring-allocated in a mappable buffer, such that a part of the buffer is in use as a UBO by the GPU while the other is being populated by that application. Doing this is important because a single bind-group could be used to address the whole ringbuffer with a dynamic offset.
Basics
GPUBuffer
gains three internal slots:
[[is partition]]
a boolean that defaults to false.[[partitions]]
a list of partitions for this buffer (always empty if[[is partition]]
).[[parent buffer]]
the parent of the buffer (always null if not[[is partition]]
)
Buffer partitioning is done through a method of GPUBuffer
:
partial interface GPUBuffer {
GPUBuffer partition(offset, size);
};
buffer.partition(offset, size)
creates a new Buffer representing the range [offset, offset + size)
of the buffer
. A validation error happens and an error GPUBuffer
is returned if one of these conditions isn't respected:
offset
andsize
must be aligned to 256.buffer.[[is partition]]
is true.buffer
must not be in thedestroyed
ormapped
state. It can already be partitioned.- the range must not intersect the range of any other partition of
buffer
that's not in the destroyed state.
Upon success a new partition of the buffer
, result
is returned. The steps are roughly:
buffer
is put in thepartitioned
state.- a new
GPUBuffer
calledresult
is created. result
is inserted in buffer's[[partitions]]
result
's[[is partition]]
is set to true.result
's[[parent buffer]]
is set tobuffer
result
is put in theunmapped
state.result
's data store represents the correct range ofbuffer
's data store' (hands waving).
Interactions with other WebGPU features
Interaction with destroy()
- Calling destroy on a partitioned buffer recursively destroys all its partitions.
- Calling destroy on a partition removes it from it's parent's list of partitions, and if the list of partition is empty the parent is put in the
unmapped
state.
Interaction with dynamic offset
The intent was that you would be able to make a dynamic UBO on the parent buffer in the bind group and somehow choosing an offset that is in a correct (unmapped) partition at submit time would be allowed.
But this requires, at submit time, to check dynamic offsets are in a correct partition if the dynamic uniform buffer is partitioned. It doesn't look very tractable.
Interaction with GPUQueue.submit()
It is an error to have a partitioned buffer used in the command buffers, except as dynamic UBO / storage buffers. If that case happens, the dynamic offset must be such that [offset, offset + binding size)
is entirely contained in a single unmapped parition.
Interaction with mapping.
And this proposal breaks down even more. The different partitions of a large ring buffer will be mapReadAsync
ed independently, but then we might want to stitch them together to make bigger partitions that are all in the mapped
state. That and splitting a large mapped
region into two sub-regions one that's going to be used as a UBO on the GPU and one that stays mapped for the next frame.