2
votes

I have a Board class in my game. This Board class is responsible for drawing a number of Zone objects, which currently all have the same texture.

So my draw calls go like: Game1.Draw calls Board.Draw which calls Zone.Draw for every zone object, which calls Spritebatch.Draw

Draw method of Game1

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);

    spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform);
    board.Draw(gameTime);
    spriteBatch.End();
}

Draw method in Board class (Board.Draw)

public void Draw(GameTime gameTime)
{
    if (zones != null)
    {

        for (int x = 1; x < xbound-1; x++)
        {
            for (int y = 1; y < ybound-1; y++)
            {
                zones[x, y].Draw(gameTime);

            }
        }
    }
}

Draw method in Zone (Zone.Draw)

public void Draw(GameTime gameTime)
{
    if (Tile != null)
    {
        Game1.spriteBatch.Draw(Tile, new Rectangle((int)pos.X, (int)pos.Y, size, size), Color.White);
        //Game1.spriteBatch.DrawString(font2, pos.X.ToString() + "," + pos.Y.ToString(), pos, Color.Blue);
    }
}

Everything works fine until I start drawing strings. Uncommenting the DrawString call results in a catastrophic FPS drop from consistent 60 to 20-25.

But here's the weird part. I created a different method for drawing the strings, instead of doing it in Zone's Draw. I called this method after Board.Draw finished drawing the Zones.

New seperate method for drawing the strings

public void DrawNumbers(GameTime gameTime)
{
    if (zones != null)
    {
        for (int x = 1; x < xbound - 1; x++)
        {
            for (int y = 1; y < ybound - 1; y++)
            {
                Game1.spriteBatch.DrawString(font2, x.ToString() + "," + y.ToString(), zones[x, y].getPos(), Color.Blue);
            }
        }
    }
}

Now Game1's Draw looks like this

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);

    spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform);
    board.Draw(gameTime);
    spriteBatch.End();

    spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform);
    board.DrawNumbers(gameTime);
    spriteBatch.End();
}

Doing it this way provides no performance hit! I get constant 60FPS again, which sounds counter-intuitive for me...

Any idea why its doing this? Why does calling DrawString right after a Draw call seem to be so costly?

Please edit or inquire if the question isn't clear.

Thanks in advance.

1

1 Answers

1
votes

The fact that you're interspersing Draw() with DrawString() is a bit of a red herring; the relevant fact here is that you're repeatedly swapping textures.

Your zone objects are all on one texture. So when you first draw all the zones, and then draw all of the strings, this is what's happening in the video driver:

  1. OK, we're about to draw polygons using zoneTexture. Set up our device state.
  2. Draw all of the zone polygons.
  3. Now we're going to draw polygons using fontTexture. Set up our device state.
  4. Draw all of the string polygons.
  5. Done.

On the other hand, when you intersperse your text with your zones, it looks more like this:

  1. OK, we're about to draw polygons using zoneTexture. Set up our device state.
  2. Draw the polygons for Zone 1.
  3. Hold on, we've got to draw some text using fontTexture. Set up our device state.
  4. Draw the polygons for the text for Zone 1.
  5. OK, we've still got more zones to draw using zoneTexture. Set up our device state.
  6. Draw the polygons for Zone 2.
  7. Oops, Zone 2 also has text using fontTexture. Set up our device state.
  8. Draw the polygons for the text for Zone 2.
  9. OK, time for the next zone using zoneTexture. Set up our device state.
  10. And on, and on, and on...

As you can see, interspersing Draw() calls which require different device states forces the graphics driver to do a heck of a lot more work! So that's why you're seeing a drop in FPS.