my application slowing down when using two textures in spritebatch.Draw

Started by
6 comments, last by maldakkak 14 years, 11 months ago
Hi everyone I didn’t post here in a long time but now I have few questions I am trying to make a simple tile based game (like pacman) using XNA Basically I have two textures, one to store 15 tiles which are 24*24 Pixels each, and the other one to store player and enemies’ sprites which are 36*36 each. I am drawing the tile map using 2D array (20*20) and I get 60 frames per second. Now when I tried to draw the player using the other texture the frame count went down to 20. The code looks something like this: spritebatch.Begin(); spritebatch.Draw(texture1,…..); spritebatch.Draw(texture2,…..); spritebatch.End(); When I combined the two textures in one the frame count was 60 again. Now I know that switching between many textures is costly but I was surprised to see the frame rate to go down like this for only using two textures. So my first question here is how do games handle too many textures? And I would think this will be even more problematic in 3D games where there are many models and many textures. Are all tiles and sprites usually saved in one big texture file? Or is this a limitation of XNA and I would not have the same problem if I had used D3D instead? The other question is, for my by luck I found that having two textures in my program caused the problem but I read sometimes that you can actually by using some utilities figure out which part of your code is making the program to slow down. I am not sure how to do this, any help is really appreciated. Thanks for help and sorry for this long post.
Advertisement
Nope, the above sounds fine, something fishy's going on.

Any chance of a block of code to look through?

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

Unfortunately I don't have the actual code in front of me now. But there is nothing else going on in the code at all. If I comment the second spriteBatch.Draw then I get 60 FPS, and when I uncomment it I get 20 FPS or less. I was trying to add collision detection and I though that was the problem first but then I deleted all that code and still had the same issue.
So here is my code

using System;using System.Collections.Generic;using System.Linq;using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Audio;using Microsoft.Xna.Framework.Content;using Microsoft.Xna.Framework.GamerServices;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;using Microsoft.Xna.Framework.Media;using Microsoft.Xna.Framework.Net;using Microsoft.Xna.Framework.Storage;namespace WindowsGame5{    public class Game1 : Microsoft.Xna.Framework.Game    {        int framePerSecond = 0, framePerSecondDisplay = 0;        double start = 0;        int[,] map = {                         {01,05,05,05,05,05,05,05,05,05,07,05,05,05,05,05,05,05,05,05,02 },                         {06,15,15,15,15,15,15,15,15,15,06,15,15,15,15,15,15,15,15,15,06 },                         {06,00,01,05,02,15,01,05,02,15,06,15,01,05,02,15,01,05,02,00,06 },                         {06,15,03,05,04,15,03,05,04,15,11,15,03,05,04,15,03,05,04,15,06 },                         {06,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,06 },                         {06,15,01,05,02,15,14,15,12,05,07,05,13,15,14,15,01,05,02,15,06 },                         {06,15,03,05,04,15,06,15,15,15,06,15,15,15,06,15,03,05,04,15,06 },                         {06,15,15,15,15,15,09,05,13,00,11,00,12,05,08,15,15,15,15,15,06 },                         {03,05,05,05,02,15,06,00,00,00,00,00,00,00,06,15,01,05,05,05,04 },                         {00,00,00,00,06,15,06,00,01,16,16,16,02,00,06,15,06,00,00,00,00 },                         {12,05,05,05,04,15,11,00,06,00,00,00,06,00,11,15,03,05,05,05,13 },                         {00,00,00,00,00,15,00,00,06,00,00,00,06,00,00,15,00,00,00,00,00 },                         {12,05,05,05,02,15,14,00,03,05,05,05,04,00,14,15,01,05,05,05,13 },                         {00,00,00,00,06,15,06,00,00,00,00,00,00,00,06,15,06,00,00,00,00 },                         {01,05,05,05,04,15,11,00,12,05,07,05,13,00,11,15,03,05,05,05,02 },                         {06,15,15,15,15,15,15,15,15,15,06,15,15,15,15,15,15,15,15,15,06 },                         {06,15,12,05,02,15,12,05,13,15,11,15,12,05,13,15,01,05,13,15,06 },                         {06,00,15,15,06,15,15,15,15,15,00,15,15,15,15,15,06,15,15,00,06 },                         {09,05,13,15,11,15,14,15,12,05,07,05,13,15,14,15,11,15,12,05,08 },                         {06,15,15,15,15,15,06,15,15,15,06,15,15,15,06,15,15,15,15,15,06 },                         {06,15,01,05,05,05,10,05,02,15,06,15,01,05,10,05,05,05,02,15,06 },                         {06,15,03,05,05,05,05,05,04,15,11,15,03,05,05,05,05,05,04,15,06 },                         {06,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,06 },                         {03,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,04 },                     };        GraphicsDeviceManager graphics;        SpriteBatch spriteBatch;        SpriteFont gameFont;        Texture2D pacmanTextures, pacmanTexture_1;        public Game1()        {            graphics = new GraphicsDeviceManager(this);            Content.RootDirectory = "Content";        }        protected override void Initialize()        {            graphics.PreferredBackBufferWidth = 800;            graphics.PreferredBackBufferHeight = 600;            graphics.IsFullScreen = true;            graphics.ApplyChanges();            base.Initialize();        }        protected override void LoadContent()        {            spriteBatch = new SpriteBatch(GraphicsDevice);            pacmanTextures = Content.Load<Texture2D>("PacManTextures");            pacmanTexture_1 = Content.Load<Texture2D>("PacManTextures_1");            gameFont = Content.Load<SpriteFont>("score");        }        protected override void UnloadContent()        {                    }        protected override void Update(GameTime gameTime)        {            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)                this.Exit();            if (Keyboard.GetState().IsKeyDown(Keys.Escape))                this.Exit();            base.Update(gameTime);        }        protected override void Draw(GameTime gameTime)        {            start += gameTime.ElapsedGameTime.TotalMilliseconds;            if (start >= 1000)            {                start = 0;                framePerSecondDisplay = framePerSecond;                framePerSecond = 0;            }            framePerSecond += 1;            GraphicsDevice.Clear(Color.Black);            spriteBatch.Begin();            for (int x = 0; x < 24; x++)                for (int y = 0; y < 21; y++)                {                    if (map[x, y] == 0)                        continue;                    spriteBatch.Draw(pacmanTextures, new Rectangle(y * 24, x * 24, 24, 24), new Rectangle(map[x, y] * 25, 0, 24, 24), Color.White);                    spriteBatch.Draw(pacmanTexture_1, new Rectangle(100, 100, 36, 36), new Rectangle(450, 0, 36, 36), Color.White);                }            spriteBatch.DrawString(gameFont, "Frames Per Second= " + framePerSecondDisplay.ToString(), new Vector2(550, 20), Color.White);            spriteBatch.End();            base.Draw(gameTime);        }    }}


As I said earlier, if I delete or comment this line: spriteBatch.Draw(pacmanTexture_1, new Rectangle(100, 100, 36, 36), new Rectangle(450, 0, 36, 36), Color.White);
then I get 60 frames per second, but if I leave it there then I get 20 frames per second, may be I am not calculating Frames Per Second correctly, any advice.

Thanks
Your sending a gameTime structure to your Draw function, how are you determining game time? are you doing something like GetTickCount() outside your draw loop?
and your adding it to the "start" variable, is this a global? does it get killed everytime your Draw function goes out of scope?

<- is not familiar with XNA
I have a question.

            for (int x = 0; x < 24; x++)                for (int y = 0; y < 21; y++)                {                    if (map[x, y] == 0)                        continue;                    spriteBatch.Draw(pacmanTextures, new Rectangle(y * 24, x * 24, 24, 24), new Rectangle(map[x, y] * 25, 0, 24, 24), Color.White);                    spriteBatch.Draw(pacmanTexture_1, new Rectangle(100, 100, 36, 36), new Rectangle(450, 0, 36, 36), Color.White);                }


Why do you have the second Draw call in the loop? It's drawing to the same location every time, so there seems to be no point in drawing it over and over inside the loop.

            for (int x = 0; x < 24; x++)            {                for (int y = 0; y < 21; y++)                {                    if (map[x, y] == 0)                        continue;                    spriteBatch.Draw(pacmanTextures, new Rectangle(y * 24, x * 24, 24, 24), new Rectangle(map[x, y] * 25, 0, 24, 24), Color.White);                }            }            spriteBatch.Draw(pacmanTexture_1, new Rectangle(100, 100, 36, 36), new Rectangle(450, 0, 36, 36), Color.White);


This should fix it. Also, it's generally good practice to put braces around blocks of code like inside loops.

Edit: To give a bit more detail about what was going on, you had two different textures in two different draw calls inside a for loop. What this means is there was a lot of texture swapping going on in the GPU, which was slowing it down a lot. In general you want to batch textures together as much as possible. Eg- Draw all tiles using this texture, then draw all sprites using this texture, etc.
Yep, that looks like your problem. since you're drawing the batches over and over, you re-bind textures twice per loop... so 24 x 21 x 2 is 504 times, which is 502 times more than you need.

throw table_exception("(? ???)? ? ???");

Yep that was the problem.
Thank you very much for help.

This topic is closed to new replies.

Advertisement