Flecko1

Which is faster

-Add vertices a few at a time to an array, then call VertexBuffer.SetData for all of them at once
-Call VertexBuffer.SetData on a few vertices several times

The array can be statically allocated, but the data is only relevant for one frame, so there's no benefit to keeping it around.

Thanks,
Max


Re: XNA Framework VertexBuffer.SetData cost

Shawn Hargreaves - MSFT

"it depends" (tm)

Generally, doing a smaller number of calls with more data in each will be faster than many small calls.

If this is on Xbox, though, you'd be better off using the DrawUserPrimitive API and not going through a vertex buffer at all. That may be slightly slower on Windows, but on Xbox it's by far the best way to draw dynamic geometry.





Re: XNA Framework VertexBuffer.SetData cost

AndyL

I'm curious... could I ask why DrawUserPrimitive is faster on the XBox is it using the more direct 'cache to GPU' path rather than the usual 'RAM to GPU' path, or is it due to something else

I have been using DrawUserPrimitive  for some dynamic geometry during prototyping, but I was expecting to convert it to vertex buffer usage later on. Maybe I won't!





Re: XNA Framework VertexBuffer.SetData cost

Flecko1

Fascinating, I didn't know about DrawUserPrimitives. I'm focusing on Windows at the moment, but now I'm curious...is there a performance difference on the Xbox for VertexBuffers that are rarely changed I'm working on porting my 2D graphics library from MDX (flecko.net/trans2d if anyone is interested), and by default everything is drawn using VertexBuffers that usually don't change, but there's also the option to use vertex caching and write a bunch of stuff that all uses the same render state, technique, etc. to a VB and draw it all at once. So from the sound of things, if I want to do this caching on the Xbox, I should collect vertices in an array and then call DrawUserPrimitives once it's full. But for the (hopefully uncommon) case where caching isn't possible, what's the best route to use




Re: XNA Framework VertexBuffer.SetData cost

Psycho Potato

I have prior experience in DX9 with C++, to me locking/unlocking VB is the last thing I'll want to do in each frame (I'd use shader if things need to be updated frequently). I guess VertexBuffer.SetData() method is doing roughly the same buffer locking thing. It is surprising that the cost of SetData is not emphasized so much in XNA, maybe it is not doing any buffer lock





Re: XNA Framework VertexBuffer.SetData cost

Shawn Hargreaves - MSFT

If you are going to keep the data around for a long time and draw it many times, it may be faster to keep it in a vertex buffer, but not if you're only going to draw it once or twice.

The fundamental issue with all this kind of thing is about data copying. The CPU and GPU run in parallel, with the GPU usually straggling a bit behind the CPU, so any data that the GPU is going to need must be somehow kept alive until the GPU is finished with it, even after the CPU thinks it is done with the data.

In the case of DrawUserPrimitives on Xbox, the vertex data is kept alive by copying it from your CPU array directly into the main GPU command buffer. That copy isn't free, but it's pretty fast.

I'm not sure exactly how drivers implement this on Windows, but I suspect the principle is similar although there is probably more overhead than on Xbox.

With a vertex buffer, the data is kept alive by copying it into the vertex buffer, and then just writing a pointer to the vertex buffer into the main GPU command buffer. Copying into the vertex buffer takes roughly the same amount of time as copying directly for a DrawUserPrimitives, but obviously now you can draw the data from the vertex buffer as many times as you like without having to repeat the copy. This is great for static geometry, but not so good for dynamic things, because what happens on the next frame when you want to overwrite the existing vertex buffer with some other data

Even when the CPU is drawing the next frame, the GPU might not yet have finished with the data from the previous frame, so it isn't always as simple as just copying new data into the vertex buffer. On Windows, drivers do smart things to make this work if you specify the Discard vertex buffer lock semantic (typically they will allocate a second vertex buffer behind the scenes, and write new data into that one instead of the one that the GPU is still using). On Xbox, though, the driver isn't so smart, and doesn't support the Discard semantic. That means if the GPU is still using your data, the CPU will just have to wait until it is finished. Not so good.

DrawUserPrimitives avoids the need for the CPU to ever stall waiting for the GPU to finish with the previous content of the vertex buffer.