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 5×5 large png image and GridNode 3×3. 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);
}
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”.
SpriteBatchgets around this problem by packing as many sprites as possible into a single batch. It only actually draws things inEnd()[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
SpriteBatchto 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(inSpriteBatch.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 separateSpriteBatchobjects within the one loop – asSpriteBatchbasically 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