Sign in to follow this  
freeworld

got a curious question about how vertex buffers and draw primitive work

Recommended Posts

Ok this might seem like a dumb question or just strange, but I was thinking last night when I couldn't sleep and now I just have to ask. When I bind a vertexbuffer to a stream and use drawprimitive, does that vertexbuffer become unavailable until the drawprimitive call is done? Take for example. 1: Fill vertexbuffer and set it 2: DrawPrimitive, using the vertexbuffer. 3: Lock vertexbuffer and refill it. Do I have to wait for step 2 and the GPU to finish before I can move onto step 3? I'm assuming you have to wait, but I'm not sure how the process works really.

Share this post


Link to post
Share on other sites
Yes and no. That's what the flags to Lock() are for.

With a static vertex buffer (One created without the D3DUSAGE_DYNAMIC flag), when you Lock() with no flags: The driver assumes you need read/write access. So it'll wait for the GPU to finish using it, and then allow the Lock().
With a static vertex buffer, locking with the D3DLOCK_READONLY flag: If the vertex buffer is in D3DPOOL_MANAGED, then locking it will just give you a pointer to the system memory copy, so no touching of the driver/GPU involved. If it's created in D3DPOOL_DEFAULT, then you'll probably get a stall as the GPU shuffles things around to let you access it, and transfers the contents to the CPU (Data going the "wrong way" across the AGP/PCI-E bus is slow).

With a dynamic vertex buffer, things get a bit more confusing. When you lock the buffer, you should pass either D3DLOCK_NOOVERWRITE or D3DLOCK_NOOVERWRITE as the flags. When you use D3DLOCK_NOOVERWRITE, you're making a promise to the GPU that you're not going to modify any vertices in the buffer that it might be using (Which means any vertices since the buffer was created, or the last time it was locked with D3DLOCK_NOOVERWRITE). That allows D3D and the driver to let you write to one part of the buffer while the GPU is reading from another - which is very quick.
When you use the D3DLOCK_DISCARD flag, you're telling the driver that you want to throw away the buffer and start again. Internally, that creates another copy of the buffer - the GPU continues to use the "old" copy until it's done, and you get given back a brand new copy - which the GPU isn't using, so there's no stalls to access it.

In general:
1. NEVER read from a vertex buffer if you can help it. Reading is extremely slow - keep a copy of the vertices in system memory (I.e. in memory allocated with malloc/new) if you need to read them.
2. Read This for more details about efficiently using dynamic vertex buffers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Yes and no. That's what the flags to Lock() are for.

With a static vertex buffer (One created without the D3DUSAGE_DYNAMIC flag), when you Lock() with no flags: The driver assumes you need read/write access. So it'll wait for the GPU to finish using it, and then allow the Lock().
With a static vertex buffer, locking with the D3DLOCK_READONLY flag: If the vertex buffer is in D3DPOOL_MANAGED, then locking it will just give you a pointer to the system memory copy, so no touching of the driver/GPU involved. If it's created in D3DPOOL_DEFAULT, then you'll probably get a stall as the GPU shuffles things around to let you access it, and transfers the contents to the CPU (Data going the "wrong way" across the AGP/PCI-E bus is slow).

With a dynamic vertex buffer, things get a bit more confusing. When you lock the buffer, you should pass either D3DLOCK_NOOVERWRITE or D3DLOCK_NOOVERWRITE as the flags. When you use D3DLOCK_NOOVERWRITE, you're making a promise to the GPU that you're not going to modify any vertices in the buffer that it might be using (Which means any vertices since the buffer was created, or the last time it was locked with D3DLOCK_NOOVERWRITE). That allows D3D and the driver to let you write to one part of the buffer while the GPU is reading from another - which is very quick.
When you use the D3DLOCK_DISCARD flag, you're telling the driver that you want to throw away the buffer and start again. Internally, that creates another copy of the buffer - the GPU continues to use the "old" copy until it's done, and you get given back a brand new copy - which the GPU isn't using, so there's no stalls to access it.

In general:
1. NEVER read from a vertex buffer if you can help it. Reading is extremely slow - keep a copy of the vertices in system memory (I.e. in memory allocated with malloc/new) if you need to read them.
2. Read This for more details about efficiently using dynamic vertex buffers.


Thank you steve, I was just curious because the 2D renderer I'm working on rebuilds the vertex buffers all the time ,they rarely stay the same so i was just wandering how it all worked, and the type of impact I'm making with my current method of rendering.

Share this post


Link to post
Share on other sites
Quote:
Original post by freeworld
Thank you steve, I was just curious because the 2D renderer I'm working on rebuilds the vertex buffers all the time ,they rarely stay the same so i was just wandering how it all worked, and the type of impact I'm making with my current method of rendering.
That's generally perfectly fine. If the data is changing all the time, you have to get it from the CPU to the GPU at some point, and dynamic resources are pretty much the most efficient way to do that. ID3DXSprite uses a dynamic vertex buffer internally for all of its drawing.

So long as you only lock a buffer once per frame (Which may mean keeping a system memory copy of the data, then doing a Lock(), memcpy() and Unlock()), it should be good.

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