Question

I do not know where I make mistake. I have seen some demos on youtube which render about 1 milion particles in realtime (amazing). But when I want to render only 2500 small sqares (Texture2D), the system falls on the knees - everything is going slow and jerky. Here I present the loop as it is - simple tile to tile rendering. The grid is 50 x 50 and the Texture2D Tile is only 5x5 large png image and GridNode 3x3. I am very new in XNA, so please do not beat me too much... :-)

Can anybody tell me, what do I do wrong?

Thanx a lot

for (x = FromCol; x <= ToCol; x++)
            {
                for (y = FromRow; y <= ToRow; y++)
                {
                    Color aColor = new Color((byte)(x * 20), (byte)(y * 15), (byte)(60 + x));

                    CoordX = DisplayArea.Left + (int)Math.Round((x - FromCol) * zoomWidth - (restCol * ZoomingX) - indent_x);//
                    CoordY = DisplayArea.Top + (int)Math.Round((y - FromRow) * zoomHeight - (restRow * ZoomingY) - indent_y);//

                    dodraw = ((CoordX) > DisplayArea.Left) & (CoordX < (DisplayArea.Right - indent_x)) & ((CoordY) > DisplayArea.Top) & (CoordY < (DisplayArea.Bottom-indent_y));


                    l = CoordX + indent_x;
                    t = CoordY + indent_y; 
                    r = l + (int)Math.Round(ColWidth * ZoomingX);
                    b = t + (int)Math.Round(RowHeight * ZoomingY);

                    if (l < DisplayArea.Left) l = DisplayArea.Left;
                    if (t < DisplayArea.Top)  t = DisplayArea.Top;
                    if (r > (DisplayArea.Left + DisplayArea.Width)) r = DisplayArea.Left + DisplayArea.Width;
                    if (b > DisplayArea.Top + DisplayArea.Height) b = DisplayArea.Top + DisplayArea.Height;

                    SpriteBatch.Draw(Tile, new Rectangle(l, t, r - l, b - t), aColor);

                    if (dodraw) SpriteBatch.Draw(GridNode, new Vector2(CoordX, CoordY), Color.White);
                }
Was it helpful?

Solution

Seth's answer is almost correct. When you send a batch to the GPU - when you draw something - it takes up a relatively large amount of CPU time. Effectivly you're limited to sending a few hundred batches per frame - your "batch limit".

SpriteBatch gets around this problem by packing as many sprites as possible into a single batch. It only actually draws things in End()[1]. However it can only batch sprites together if they share a texture.

You've pretty much got the worst-case scenario here: It looks like you're interleaving textures, forcing SpriteBatch to start a new batch for each sprite.

So the first thing to do is to check if this is actually the cause of your problem. A quick way to do this is to set SpriteSortMode.Texture (in SpriteBatch.Begin) and see if performance improves. This will do exactly what it sounds like - grouping your sprites by texture in the draw order, reducing the number of texture changes and therefore batches.

Then you can start working on fixing the issue. If you can continue using SpriteSortMode.Texture, then that's fine. You could also convert your loop into two separate loops. Or you could fill two separate SpriteBatch objects within the one loop - as SpriteBatch basically acts as a buffer[1].

Or, if you really need those textures interleaved, then use a sprite sheet.

Finally, I've written this rather popular answer on the GameDev site which covers this topic in more detail.


[1] Except when using SpriteSortMode.Immediate

OTHER TIPS

You are making 2500 calls to the Draw method. Every time you tell the CPU to give an instruction to GPU, there is a huge processing overhead. That is why your performance is worse than a game which draws a million particles in a single draw call.

Drawing 1000 triangles once is much, much faster than drawing 1 triangle 1000 times.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top