Sign in to follow this  
JustChris

Multiple updates to a vertex buffer, in one frame

Recommended Posts

This is a somewhat tricky problem so I hope you can figure out what is happening. I have implemented a rendering system to take advantage of hardware instancing, and using dynamic vertex buffers to update the instances. I've been using it for a few weeks now and largely remaining unchanged. The instances update on rigid body interactions from a physics engine, and also on per-instance frustum culling. But there is one big setback that needs to be overcome. The rendering system cannot handle the creation of additional instances at runtime, at least in the manner that I've tried to put it in. Adding more instances to a mesh corrupts the stack and crashes the program. I've already considered the code to have become messy and buggy, and could use some overhaul. Each renderable object has its own vertex buffer for instance data, and a copy of the raw vertex data as a vector of vertex structs. Updating instances involves updating the vector vertex data and passing that to the vertex buffer. I think the stack corruption is being caused by my code not being able to synchronize the data properly, so it reads data out of vector bounds. And I've become lost in the code to backtrack and find a good way to synchronize the vector with the vertex buffer data. So is it possible to implement such a system without needing redundant vertex data? That is, just having the vertex buffer, locking it and making a temporary vector for update use and then stuffing it back into the buffer when it's done. But then I would have to lock a buffer each time I want to add more instances, making updates with the physics or frustum culling. All these things will usually happen in one frame. I know I have to keep the buffer locking to a minimum. Is it a good idea to leave the vertex buffer locked for an extended period of time? Still within the timespan of one frame, but letting many other functions running in the program between locking and unlocking, when the updates are final. In short I want to be able to do this: -- Lock vertex buffer -- Copy the data to a vector of instance vertices -- Update instance vertices from any direct changes to its position, rotation, etc -- For instances bound to rigid bodies, make any updates given by the physics engine -- Do a frustum culling check on each instance (applying bounding sphere data from another source) -- Re-arrange the instance vertices so the visible ones come first -- Unlock vertex buffer

Share this post


Link to post
Share on other sites
Note: I'll assume you're using D3D9. In general it's a good idea to specify what API you're working with when asking a question.

I'd suggest not locking the vertex buffer for an extended period, for a couple of reasons. First, locking causes synchronisation between CPU and GPU (though this can be reduced by using correct flags and usage pattens -- see below), and so can cause stalls. Secondly, the memory you get for the buffer can be in a memory region that's not cached, and read/write performance would be lower than using your own buffers.

What I'd suggest is that you do all your processing in your own buffer, then lock, copy and release. To reduce CPU/GPU syncing, use discard or no-overwrite flags when locking. Discard basically gives you a new buffer that you can fill, which will later replace the existing one. There's a limit on how many such renamed buffer the driver will be willing to give you before causing a sync. When using no-overwrite you guarantee to D3D that you're not going to change data already in the buffer, so the GPU can continue to use.

I hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by ET3D
What I'd suggest is that you do all your processing in your own buffer, then lock, copy and release. To reduce CPU/GPU syncing, use discard or no-overwrite flags when locking. Discard basically gives you a new buffer that you can fill, which will later replace the existing one. There's a limit on how many such renamed buffer the driver will be willing to give you before causing a sync. When using no-overwrite you guarantee to D3D that you're not going to change data already in the buffer, so the GPU can continue to use.

I hope this helps.


Expanding upon this: The recommended practice is (given a sufficiently large buffer) to lock the chunks you need using no-overwrite flag and then, when the buffer is full or cannot hold the next chunk of data you need to load, lock with discard to obtain a fresh buffer (the old data will still be around, getting streamed up to the card and rendered).

Share this post


Link to post
Share on other sites
That sounds like good idea with using the no-overwrite flag if you know which parts of the buffer you want to update. Normally I just use d3dlock_discard to re-write the whole thing because when it comes to frustum culling, or physics updates, any arbitrary amount of instances might change. Locking only the parts I need would prove tricky so that'll have to wait, at least I'm not seeing any performance hits with large amounts of vertex data.

Quote:

when the buffer is full or cannot hold the next chunk of data you need to load, lock with discard to obtain a fresh buffer (the old data will still be around, getting streamed up to the card and rendered).


Does this mean that the buffer will be replaced by a new buffer of a different size if you provide it with more data? If so, I am guessing there is no need to use CreateVertexBuffer() and have that replace the buffer that the mesh object is currently using, which is the method I was thinking of. It would probably be faster just locking and letting the discard flag do its work than manually creating a new buffer.

Share this post


Link to post
Share on other sites
In general your best bet is to have a contiguous buffer of memory (it can be a std::vector if you want) where every frame you put in your instance data every frame (after culling). Then you can just do a quick Lock, memcpy, and Unlock to fill your instance vertex buffer.

Quote:
Original post by JustChris
Does this mean that the buffer will be replaced by a new buffer of a different size if you provide it with more data? If so, I am guessing there is no need to use CreateVertexBuffer() and have that replace the buffer that the mesh object is currently using, which is the method I was thinking of. It would probably be faster just locking and letting the discard flag do its work than manually creating a new buffer.


He was talking about internal buffers that are managed by the driver when you use a dynamic vertex buffer.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this