[D3D11] Partially updating dynamic buffers

Started by
2 comments, last by Promethium 12 years, 5 months ago
Hello community :)

My question is rather simple.
Is it possible to update a dynamic buffer partially in Direct3D11?
As an example this "buffer" is given: [ 1 2 3 4 5 ]
And now I want to only update the data from 2 to 4.
I allready now that when you want to map a dynamic buffer the type must be D3D11_MAP_WRITE_DISCARD or D3D11_MAP_WRITE_NO_OVERWRITE.
But this means that I can only append data to the buffer or discard all it´s contents and refill it.

I hope someone can help me.
Thank you :)
Advertisement

I allready now that when you want to map a dynamic buffer the type must be D3D11_MAP_WRITE_DISCARD or D3D11_MAP_WRITE_NO_OVERWRITE.
But this means that I can only append data to the buffer or discard all it´s contents and refill it.


Yeah, you don't really have any other options for dynamic buffers. The reason for this is CPU/GPU synchronization. The CPU needs to ensure that it doesn't write to a buffer that the GPU is reading from, otherwise the GPU will read partially-updated data or just the wrong data entirely. The DISCARD mode allows drivers to avoid this case by giving the CPU a different area of memory to write to each time it Maps a buffer. The semantics of DISCARD means the contents of the memory are invalid, which means the driver can switch memory locations and you can't have any expectations as to the content of that memory. NO_OVERWRITE is similar, except rather than have the driver handle the memory you essentially just promise the runtime that you're not going to overwrite some memory that's currently in use by GPU.

So the point is, there's no way to partially update a buffer AND guarantee that you're not going to overwrite some memory that the GPU is using. Actually there is one way, which is to sync with the GPU every time you update the buffer, but that would cause severe performance problems. The best you can do is keep your own copy of the buffer contents on the CPU, partially update the CPU buffer, and then use the CPU buffer to update the contents of your dynamic GPU buffer.
Thank you very much!
This approche works and has a decent performance.
It's just what I have been looking for.
While MJP's response is totally correct, just to complete the story: It is safe to partially update a dynamic buffer IF you can guarantee that you are not touching any data that is in use by the GPU. In pseudo-code this would typically be something like

int batch_size = ...
int capacity = ...

int offset = capacity;

while( true ) {
if( offset + batch_size > capacity ) {
ptr = buffer->lock( 0, batch_size, DISCARD )
offset = 0;
} else {
ptr = buffer->lock( offset, batch_size, NO_OVERWRITE )
}

copy_data( ptr, batch_size )
buffer->unlock( ptr )

render( buffer, offset, batch_size )
offset += batch_size;
}

This works because DISCARD returns a pointer to a new memory area, so you won't be touching old data. This is potentially faster than DISCARDing on each update since the GPU can continue reading from the buffer while you are updating. The capacity of the buffer must of course be large enough that you can have several batches in-flight at the same time.

This topic is closed to new replies.

Advertisement