   [.net] XNA Vertex Buffers
  In XNA Unleashed there is a section entitled "Vertex buffers", which describes manually rendering geometry.  This involves creating an array of the appropriate vertex type, creating and setting the VertexDeclaration, and calling DrawUserPrimitives() (or some variant thereof).  No problem.The problem I have is that the "Vertex buffers" section never mentions the VertexBuffer class.  Is the approach described above fast? I'm coming from OpenGL, so is it more equivalent to immediate mode (glBegin/glEnd) rendering, or to vertex arrays, or actually to OGL VBOs?  I suspect that it's more like immediate mode rendering, but nobody actually says that anywhere.What does the VertexBuffer class do if it isn't used in the section called "Vertex buffers"?What is the best way to draw static geometry for a large mesh?  Does the Mesh class optimize that stuff? Should I use MeshBuilder for simple meshes?Thanks! Sorry for all of the questions.   
  From my limited understanding of OpenGL, I think XNA's vertexbuffers are similar to VBOs. Basically a vertexbuffer will allow you to store vertices in driver/runtime managed memory (ResourceManagementMode.Automatic) or in graphics card memory (ResourceManagementMode.Manual). The ResourceManagementMode enum corresponds to the DirectX Pool enum, where Automatic means the Managed pool and Manual means the Default pool. If you have the DX SDK installed, the docs on this Pool enum can probably tell you all you want to know. Bottom line is that vertexbuffers are the most efficient way to store and use static vertex data.I can't imagine a book having a section called "Vertex buffers" and not go into vertex buffers, but if this is truly the case then it might not be the best book out there... Anyway, DrawUserPrimitives() does not use vertexbuffers but sends the user data to the graphics card on-the-fly each time it is called (so probably each frame). There are some similarities to immediate mode, but from what little I know about that this approach still is quite different. Getting back to your question, for larger static geometry you'll want to use vertexbuffers instead to avoid trafficking your data to the GPU each frame1.I'm not aware of a built-in MeshBuilder class in XNA, but a Mesh essentially is just a vertexbuffer and an indexbuffer with some additional information about subsets that use varying materials (the ModelParts). So efficiency-wise it doesn't really matter whether you use a properly constructed index/vertexbuffer or go with a Mesh. For complex geometry though, using the Model/Mesh class may be a lot more convenient.1 For dynamic geometry that changes regularly however, using DrawUserPrimitives() actually seems to be preferred over creating a dynamic vertexbuffer and changing the data there. This deviates a bit from DirectX common practices, but apparently this is due to some XBox memory quircks (and possibly not to confuse the XNA audience with the finer details of locking).   ;  Cool, that's about what I expected.  I have only casually noticed the presence of the MeshBuilder class.  Apparently it's part of the content pipeline library, and is intended to facilitate the development of importers for different model file formats.Thanks.   ;  You can pull off some efficiency tricks with vertex buffers.For example, if your geometry only changes every fifth frame, a vertex buffer would allow you to only send your data over the bus when neccessary (or even distribute the upload over those 5 frames).You can also update only a portion of the vertex buffer or maybe use two vertex buffers, one holding the positions and the other holding the texture coordinates, so you would only send half the data when the vertices are moved but the texture coordinates stay untouched (think cpu-based character animation).I think internally, there's some kind of low-level vertex buffer underneath the vertex buffers exposed by the API. If you lock a vertex buffer with LockMode.Discard, this low-level buffer will be replaced with a new one and D3D will delete the old one as soon as the GPU is finished with the vertices it contains. My speculation is that DrawPrimitiveUp() creates just such a low-level buffer, hands it to the GPU and immediately marks it for deletion.-Markus-   ;Quote:Original post by CygonI think internally, there's some kind of low-level vertex buffer underneath the vertex buffers exposed by the API. If you lock a vertex buffer with LockMode.Discard, this low-level buffer will be replaced with a new one and D3D will delete the old one as soon as the GPU is finished with the vertices it contains. My speculation is that DrawPrimitiveUp() creates just such a low-level buffer, hands it to the GPU and immediately marks it for deletion.That's correct, going from this archived post. Unfortunately I can't find where I read it (so many XNA gems are lost in blog archives [headshake]), but it seems that on the XBox360 DrawUserPrimitives actually performs quite a bit better than using a buffer you lock often, probably due to the unified memory architecture. So for very dynamic geometry like particles DrawUserPrimitives might be a better choice, if you care about 360 deployment that is. If anyone knows where this was explained in more detail, please do post the link [smile];Quote:Original post by remigiusUnfortunately I can't find where I read it (so many XNA gems are lost in blog archives [headshake]), but it seems that on the XBox360 DrawUserPrimitives actually performs quite a bit better than using a buffer you lock often, probably due to the unified memory architecture. Of course it could also be because SetData forces a bunch of extra calls into the API, as well as security checks all over the place, which create large amounts of CPU overhead.Again just speculation, of course. XNA does not seem terribly friendly to patterns involving complex buffer manipulation to me.   ;Quote:Original post by PromitAgain just speculation, of course. XNA does not seem terribly friendly to patterns involving complex buffer manipulation to me.That's my feeling as well. Last time I tried to be clever about updating my vertex buffers, I found that the SetData(vertices, startindex, count) overload would not work on the XBox360 at all and that your only option was to rewrite the whole darn thing using SetData(vertices) (this seems to be fixed in XNA 1.0 Refresh, however).-Markus-;Quote:Original post by PromitOf course it could also be because SetData forces a bunch of extra calls into the API, as well as security checks all over the place, which create large amounts of CPU overhead.Again just speculation, of course. XNA does not seem terribly friendly to patterns involving complex buffer manipulation to me.For the Windows/DirectX version of the framework this certainly holds true. A quick look with reflector shows that the SetData method in the XNA assembly for Windows does quite a lot of work. But as I recall the article explicitly stated that DrawUserPrimitives would be more efficient on the 360 due to its memory architecture. Unfortunately reflector doesn't show me what the 360 version of SetData does, but I guess it's safe to assume it has to go out of its way to mimic the SetData copy behavior. With the unified memory architecture it would be a matter of updating some internal pointer and checking bounds, but this doesn't satisfy the (maybe overly) generic SetData 'contract'. This contract enforces that the data used by the CPU and GPU are seperate copies to match the PC architecture, so to ensure consistent behavior across platforms the 360 has to do a memcopy that's typically unnecessary. DrawUserPrimitives doesn't have to worry about this since it's basically a one-shot read-only method, so it can just quickly reference the data with this pointer approach.Out of curiosity, exactly what complex buffer manipulations did you have in mind? Any manipulations I can think of that don't fit into XNA's SetData(verts, index, count) pattern don't seem to go well with sequential data writes anyway, so they'd be undesirable on the PC to begin with for efficiency's sake, no?   ;  There's this dynamic vertex buffer best practices document somewhere in the DirectX documentation that recommends to create a large vertex buffer for dynamically generated vertices and to fill it sequentially with D3DLOCK_NOOVERWRITE (eg. lock 0-1024, render, lock 1024-2048, render, and so on). When the end of the vertex buffer is reached, do a single D3DLOCK_DISCARD lock.Edit: Found the document I was referring:Performance Optimizations: Using Dynamic Vertex and Index Buffers (MSDN)I don't know whether this is just done to keep the GPU busy or what the motivation behind this recommendation was, but that's what made me to try the SetData(verts, index, count) overload. I can't really think of any other use case where you'd want to write only a small part of the vertex buffer except when you're rendering and modifying a one-million-vertex-model in a CAD-like application.-Markus-(Edit2: Fixed a stupid typo ;))[Edited by - Cygon on August 25, 2007 6:53:10 AM];  I did stumble across something interesting in the XNA docs actually:Quote:optionsOption that specifies whether existing data in the buffer will be kept after this operation. Discard is not valid on Xbox 360, but dynamic geometry may be rendered on the Xbox 360 by using DrawUserPrimitives or DrawUserIndexedPrimitives instead of setting the data for the vertex buffer. ...In the Draw method of an Xbox 360 game, vertex buffers, index buffers, and textures should not be written using when they are intended to be used for rendering. This condition may lead to graphics corruption or crashes. To avoid this potential issue, use DrawUserPrimitives or DrawUserIndexedPrimitives as the preferred alternative to VertexBuffer.SetData for dynamic vertex generation. This is because, in cases where the size of the back buffer and depth stencil buffer exceed the size of the Xbox 360 10 MB of embedded memory (EDRAM), predicated tiling is utilized on this platform to compensate for the additional memory requirements. Predicated tiling is a process by which scene rendering is performed multiple times on subsections of the final render target dimensions. When predicated tiling has been triggered, the drawing commands contained in the Draw function are not submitted until Present is called. (Note that Draw implicitly calls Present at the end of this method.) In this case, these resources are not available for modification until the GPU is finished with presenting the entire frame. Which makes rather a lot of sense if you think about it. A lot of clever buffer writing patterns on PC will make a huge mess of predicated tiling. This kind of swings back to the problem of XNA being an Xbox API I guess, but this kind of seemingly boneheaded approach actually works best on 360. Gotta love leaky abstractions sometimes.   