0
\$\begingroup\$

Okay, so this is where I am now. My game largely consists of textures drawn through spritebatch. Now I have to draw a dynamic number of triangles. I cannot say in advance where or how many I have to draw, because I have to generate their positions on the fly. The number will never top 3-400 though, and is often much lower.

When testing though, I noticed that at random moments the game became a bit laggy. I'm quite confident the vertex-drawing was the problem, if I commented it out, the lag was gone.

This is the code I have currently (I removed as much clutter as possible):

// loop through the grid
    VertexPositionColor[] vertices;
    int vertexcounter = 0; 

    RasterizerState state = new RasterizerState();
    state.CullMode = CullMode.None;

    for(int i = startx; i < endx; i++)
        for (int j = starty; j < endy; j++)
        {

            //////
            vertices = new VertexPositionColor[3];
            vertexcounter = 3;
            vertices[0] = new VertexPositionColor(Vector3.Zero, Color.Black);
            vertices[1] = new VertexPositionColor(new Vector3(width / 2, 0, 0), Color.Black);
            vertices[2] = new VertexPositionColor(new Vector3(0, height / 2, 0), Color.Black);
            //////

            // Create a buffer to use
            vertexBuffer = new VertexBuffer(device, typeof(VertexPositionColor), vertexcounter, BufferUsage.WriteOnly);
            vertexBuffer.SetData<VertexPositionColor>(vertices);

            // Draw the triangles
            basicEffect.World = world;
            basicEffect.View = view;
            basicEffect.Projection = projection;
            basicEffect.VertexColorEnabled = true;

            device.SetVertexBuffer(vertexBuffer);
            device.RasterizerState = state;

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexcounter / 3);
            }

            vertexcounter = 0;
            vertexBuffer.Dispose();
        }

Again, I removed as much clutter as possible. The basicEffect and matrices are created in the constructor. The for loop doesn't really make sense probably, but the part between the ////'s used to be for retrieving the vertices from objects in a grid (which is what the coordinates were for).

As you can see I removed that part and instead draw one single triangle. The game still lags though, so I think I'm doing something else wrong. Are you not really supposed to create VertexBuffers on the fly? Or am I forgetting to dispose of certain data?

Also, maybe it is worth noting that this is done in the Update part of the object. This is because the image is drawn to a RenderTarget, and in my project it's just more convenient to do it in the Update method.

Thanks in advance :)

\$\endgroup\$
3
\$\begingroup\$

You are generating a lot of garbage and doing a lot of excess driver calls in those loops.

Things like new VertexPositionColor[3] has to perform a heap allocation that the GC must then clean up. Ensure that every type you call new on in a loop is a struct. Be aware that things like foreach have to create a new enumerator object which may be a class type and heap-allocated (I don't know about the specific types you're using in your loop here; you have to check yourself, or just use integer indices).

If you need a temporary bit of heap-allocated memory, pre-allocate it and store it in a class member for reuse rather than re-allocating every time. For instance, that small array you create inside your loops could easily just be a member of the containing class on only new'd up once.

You're also wasting a lot of driver and hardware time creating new vertex buffers inside of an inner loop. You don't need to recreate vertex buffer (especially one with a fixed size). Create once and reuse it.

You can also combine those draw calls. The draw code you have now likely won't cause intermittent pauses but it will be generally slow as molasses. You're using the same shader and material properties for every triangle. Instead of drawing one triangle at a time, push them all into one single buffer and draw them in one pass. You can have a List<VertexPositionColor> (remember to only create it once and to clear/reuse it each time you need to draw a set of tris) and your loops can just push vertices onto that. Then at the end copy it into a vertex buffer and call draw.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your reply! As I mentioned in the initial post, the shown vertex-generating code is just a simple placeholder. In the actual code, the number of vertices is dynamic. There is a finite amount of variations though, so I could create a finite number of buffers/arrays and use those, but that seems a bit too much, isn't there some way to do this dynamically? Your last paragraph was also helpful, that doing the drawing all at once would probably work better. Again, thanks for your help! \$\endgroup\$ – user39570 Dec 3 '13 at 20:29
  • 2
    \$\begingroup\$ @user39570 Just create a vertex buffer sized for the maximum number of vertices you'll ever draw in a frame. It doesn't matter if part of the buffer goes unused (that's actually much better than deleting and recreating the buffer every frame). \$\endgroup\$ – Nathan Reed Dec 3 '13 at 20:40
  • 1
    \$\begingroup\$ Effect.CurrentTechnique.Passes.GetEnumerator() returns a value type, so no allocation in that particular foreach loop. \$\endgroup\$ – Andrew Russell Dec 4 '13 at 10:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.