   Drawing optimisations
  I've been working on my terrain object and trying to optimise it.It's a 256 x 256 dataset. Originally I was drawing it as a trianglestrip with one row per column. It wasn't drawing right, the row would stop halfway and bridge the last polygon with the first. I broke the vertex buffer up into subgrids and it drew fine, but it could only handle a 4x4 or 8x8 divisions of 64x64 and 32x32 before it slowed down too much.I switched to a trianglelist so that I could draw each subgrid in one draw call as opposed to one draw call per row. Not an enormous speed increase but now it's easier to LOD, so that's cool.To try to optimise things even further I joined all the vertex buffers together into one big buffer and drew each subgrid using the offset property in one pass. Big speed hit.What's the right way to be thinking about this? Is there some sort of speed advantage to be had in splitting up the vertex buffer and sending it in smaller pieces?   
  I believe what you want to search for is clip-maps.  Never done it myself.[edit: for example http://www.ziggyware.com/readarticle.php?article_id=220]There was a post here a while ago about priming the vertex buffer, which I can't seem to find.  In essence, you draw a 'fake' triangle and then send the vertices in strips of about 15.  This keeps the previous vertices in the graphics card cache so you're only ever sending each vertex once.  Damn, I fail at finding these things.  Sorry.[Edited by - jdindia on February 24, 2009 7:58:30 PM];Quote:Original post by jdindiaI believe what you want to search for is clip-maps.  Never done it myself.There was a post here a while ago about priming the vertex buffer, which I can't seem to find.  In essence, you draw a 'fake' triangle and then send the vertices in strips of about 15.  This keeps the previous vertices in the graphics card cache so you're only ever sending each vertex once.  Damn, I fail at finding these things.  Sorry.I'm going to have to look that up since I'm finding it hard to picture what you mean. Having googled it, it seems to relate to: a. mipmap texture optimisation or b. using mipmap selection to use different textures over distance. Looks cute, but it's not remotely related to my question. This is specifically about the best way to supply a vertex buffer to the GPU.At the moment I'm setting the vertex buffer once per frame. Previously I was setting the same vertex buffer in 16 pieces, once each per frame. That's where the big performance difference showed. The second option was faster, which I didn't expect.It would probably help if I posted my draw call to illustrate the final draw routine I've ended up with. This is in XNA. Engine.Graphics.GraphicsDevice.Vertices[0].SetSource(VertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); Engine.Graphics.GraphicsDevice.Indices = IndexBuffer; int VertexStep = Parent.TerrainFragmentWidth * Parent.TerrainFragmentHeight; for (int f = 0; f < Parent.WorldSize; f++) {Engine.Graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, f * VertexStep, 0, VertexStep, 0, VertexStep * 2); }[Edited by - nih on February 24, 2009 7:11:12 PM];Quote:Original post by nihAt the moment I'm setting the vertex buffer once per frame. Previously I was setting the same vertex buffer in 16 pieces, once each per frame. That's where the big performance difference showed. The second option was faster, which I didn't expect.Right.  What I'm saying is that the graphics card has an internal cache of vertices.  I don't know how big it is, but not big.  Maybe 16-32ish.  If you index something in the cache, it doesn't need to get recalculated.  If you cram a 256x256 vertex mesh in, and index it the obvious way, you'll blow the internal cache.  If you index it such that you used each vertex in the current triangle within the last 16-32(?) vertices already, you'll get a performance boost.  Bleh.  I need to draw a picture.  English fails and a simple picture makes all clear.  Anyway, I suspect that's what you're seeing.  I could be wrong.Search for "priming the vertex cache".[edit: for example, http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=316777&reply_id=2588637][Edited by - jdindia on February 24, 2009 8:56:13 PM];Quote:Original post by jdindiaRight.  What I'm saying is that the graphics card has an internal cache of vertices.  I don't know how big it is, but not big.  Maybe 16-32ish.  If you index something in the cache, it doesn't need to get recalculated.  If you cram a 256x256 vertex mesh in, and index it the obvious way, you'll blow the internal cache.  If you index it such that you used each vertex in the current triangle within the last 16-32(?) vertices already, you'll get a performance boost.  Bleh.  I need to draw a picture.  English fails and a simple picture makes all clear.  Anyway, I suspect that's what you're seeing.  I could be wrong.Search for "priming the vertex cache".[edit: for example, http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=316777&reply_id=2588637]Aha! Now we're on the same page.I'm not supplying duplicate vertices in the vertex buffer at all. The index buffer can re-reference the same vertex up to six times in a regular trianglelist. I re-use my index buffer as well since it's identical for each sub-grid element. (Although now I'm storing similar but lower detail index buffers as well for LOD.)The linked article talks about using trianglestrips, which according to the XNA devs will be as fast as or slower than a trianglelist, despite sending less indices in the index buffer. Both methods send the same number of vertices in the vertex buffer. I did read after switching to trianglelist that you can use degenerate triangles to wind around to the next row, reducing the number of draw calls, but by this stage I didn't want to look back. I also haven't tried ordering my vertex buffer in any way other than right to left, top to bottom.I'm guessing filling the vertex cache could be a possible cause of the slowdown. I need to know more about how it works and how to optimise for it.The max primitive count in a single draw call for my video card is 8388607. I worked out the most I'm sending it without LOD is 131072. When I break up the draw calls by subgid, I'm sending 8192 primitives per call.I've read that a good target is 5k-10k polygons per draw call, but it didn't provide an explanation why.I'm guessing in the end filling the cache is as good as reason as any for smaller vertex buffers to be more efficient.   ;  So I think we both have to be careful with the words we're using.  It's not the size of the vertex buffer that's the problem.  That actually shouldn't matter since you're way below the maximum.  It's not even the ordering of the vertex buffer.  It's how many times you index each vertex.  By indexing with a certain order, you can maximize use of the internal cache (reread that article, if I remember correctly it explains it quite well).  And I wouldn't even bother with triangle strips, I'd just use triangle lists.I think the confusion stems from the assumption that the graphics card takes the big wad of vertices you gave it in the vertex buffer and transforms them all at once.  My understanding is, it only transforms the ones you index, so the way you index matters.  And uhm, I'm actually not an expert on this.  I just read a few things about it and thought it was interesting.  I have a feeling some of this kind of stuff will change as graphics cards simply overpower these kind of techniques.  You'll just send big wads of vertices and nothing else will matter.   ;Quote:Original post by jdindiaSo I think we both have to be careful with the words we're using.  It's not the size of the vertex buffer that's the problem.  That actually shouldn't matter since you're way below the maximum.  It's not even the ordering of the vertex buffer.  It's how many times you index each vertex.  By indexing with a certain order, you can maximize use of the internal cache (reread that article, if I remember correctly it explains it quite well).  And I wouldn't even bother with triangle strips, I'd just use triangle lists.I think the confusion stems from the assumption that the graphics card takes the big wad of vertices you gave it in the vertex buffer and transforms them all at once.  My understanding is, it only transforms the ones you index, so the way you index matters.  And uhm, I'm actually not an expert on this.  I just read a few things about it and thought it was interesting.  I have a feeling some of this kind of stuff will change as graphics cards simply overpower these kind of techniques.  You'll just send big wads of vertices and nothing else will matter.Sending big wads definitely sounds like what I'm trying to do now.My winding order is pretty basic. For the first triangle:2-3|1For the second:  5 /|4 6Continuing along each column until the end of the row. Then you advance the row and repeat.Edit: Fixed my indexing problem so deleted it. It was just a dumb mistake. Didn't want to leave bad code up.[Edited by - nih on February 25, 2009 12:06:42 AM]