Displaying the framerate

Displaying the framerate

  • Comments 29

I was about to write a different article, but then I thought about what would make a good example for my planned topic, and decided a framerate component would be a perfect testbed for it. So before I get started on my next real subject, I'm going to describe how to create a reusable framerate measurement component.

There are many possible ways to measure framerate. Some people directly measure the time taken to draw each individual frame, but the exact timings tend to fluctuate so it can be hard to get a sense of the overall performance that way. Others use various kinds of rolling average to smooth out the timing data over several frames. Personally I like to just count how many times Draw is called, then copy this counter value out into my framerate display once per second. Simple, accurate, and gives a nice steady result.

Enough talk. Here's the code:

    public class FrameRateCounter : DrawableGameComponent
    {
        ContentManager content;
        SpriteBatch spriteBatch;
        SpriteFont spriteFont;

        int frameRate = 0;
        int frameCounter = 0;
        TimeSpan elapsedTime = TimeSpan.Zero;


        public FrameRateCounter(Game game)
            : base(game)
        {
            content = new ContentManager(game.Services);
        }

        
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                spriteBatch = new SpriteBatch(GraphicsDevice);
                spriteFont = content.Load<SpriteFont>("Font");
            }
        }


        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent)
                content.Unload();
        }


        public override void Update(GameTime gameTime)
        {
            elapsedTime += gameTime.ElapsedGameTime;

            if (elapsedTime > TimeSpan.FromSeconds(1))
            {
                elapsedTime -= TimeSpan.FromSeconds(1);
                frameRate = frameCounter;
                frameCounter = 0;
            }
        }


        public override void Draw(GameTime gameTime)
        {
            frameCounter++;

            string fps = string.Format("fps: {0}", frameRate);

            spriteBatch.Begin();

            spriteBatch.DrawString(spriteFont, fps, new Vector2(33, 33), Color.Black);
            spriteBatch.DrawString(spriteFont, fps, new Vector2(32, 32), Color.White);
            
            spriteBatch.End();
        }
    }

To use this, register the component inside your Game constructor:

    Components.Add(new FrameRateCounter(this));

You will also need to add a Font.spritefont file. I got a little clever with mine:

   <?xml version="1.0" encoding="utf-8"?>
   <XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
     <Asset Type="Graphics:FontDescription">
      <FontName>Arial</FontName>
      <Size>14</Size>
      <Spacing>2</Spacing>
      <Style>Regular</Style>
      <CharacterRegions>
        <CharacterRegion><Start>f</Start><End>f</End></CharacterRegion>
        <CharacterRegion><Start>p</Start><End>p</End></CharacterRegion>
        <CharacterRegion><Start>s</Start><End>s</End></CharacterRegion>
        <CharacterRegion><Start>:</Start><End>:</End></CharacterRegion>
        <CharacterRegion><Start> </Start><End> </End></CharacterRegion>
        <CharacterRegion><Start>0</Start><End>9</End></CharacterRegion>
      </CharacterRegions>
     </Asset>
   </XnaContent>

See what I did there? Because my framerate counter is only ever going to display the numbers 0 through 9, plus an "fps:" prefix, I optimized the size of my font by specifying CharacterRegion elements to only bother including the characters I really need.

Thanks for sharing your comment! If your comment doesn't appear right away, please be patient as it may take a few minutes to publish or may require moderation.
  • I just started messing with XNA and the tutorial works fine, but I do get 2 warnings. Im not sure I understand this error and how can I make it go away? Thanks!

    Warning 1 Member 'FrameRateCounter.LoadGraphicsContent(bool)' overrides obsolete member 'Microsoft.Xna.Framework.DrawableGameComponent.LoadGraphicsContent(bool)'. Add the Obsolete attribute to 'FrameRateCounter.LoadGraphicsContent(bool)'. C:\Documents and Settings\asdf\My Documents\Visual Studio 2005\Projects\WindowsGame1\WindowsGame1\Class1.cs 32 29 WindowsGame1

    Warning 2 Member 'FrameRateCounter.UnloadGraphicsContent(bool)' overrides obsolete member 'Microsoft.Xna.Framework.DrawableGameComponent.UnloadGraphicsContent(bool)'. Add the Obsolete attribute to 'FrameRateCounter.UnloadGraphicsContent(bool)'. C:\Documents and Settings\asdf\My Documents\Visual Studio 2005\Projects\WindowsGame1\WindowsGame1\Class1.cs 42 29 WindowsGame1

  • the warnings mean exactly what they say, LoadGraphicsContent is now obsolete.

    replace the two methods with:

     protected override void LoadContent()

           {

               if (loadAllContent)

               {

                   spriteBatch = new SpriteBatch(GraphicsDevice);

                   //spriteFont = _content.Load<SpriteFont>(@"Fonts\gamefont");

                   //spriteFont = content.Load<SpriteFont>(@"\Fonts\gamefont");

                   spriteFont = content.Load<SpriteFont>(@"Fonts\gamefont");

               }

           }

           protected override void UnloadContent()

           {

               if (unloadAllContent)

                   content.Unload();

           }

  • Hai,

    I try to use your framecounter but the problem is the spritefont-file. Error loading "Font". File not found.

    I'm sure I named everthing alright. But the strange thing is dat the spritefont extension isn't recognized. There's no icon.

    I use XNA 3.1 and VS2008.

    Is this known problem?

    kid regards

    Sjaak

  • Hi,

    I had the same problem as Sjaak, and I could get the loading work by changing :

    public FrameRateCounter(Game game)

               : base(game)

           {

               content = new ContentManager(game.Services);

           }

    to :

    public FrameRateCounter(Game game)

       : base(game)

    {

      content = Game.Content;

    }

    I don't know if it is a bad practice, but it works.

    Best regards,

    Marc

  • Hi,

    Nice little frame rate counter.

    I have used this in a tutorial i followed which uses 3D in the Game class. Using this class however made the 3D drawing go wrong, some triangles that were behind others were visible. I think this is because using a SpriteBatch only works in 2D (screen coordinates) and therefore turns off the depthbuffer in your graphics device.

    I use XNA 3.1 and VS2008 by the way, don't know if the line of code at the end of the post is possible in older versions of XNA.

    I worked around this problem by adding this line at the very end of the FrameRateCounter Draw method:

       Game.GraphicsDevice.RenderState.DepthBufferEnable = true;

  • Seems like my framerate is always capped at 60 f/s.  I disabled vSync (I think):

    _graphics_device_manager.PreferredBackBufferWidth = 1024;

    _graphics_device_manager.PreferredBackBufferHeight = 600;

    _graphics_device_manager.IsFullScreen = false;

    _graphics_device_manager.SynchronizeWithVerticalRetrace = false;

    _graphics_device_manager.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;

    _graphics_device_manager.ApplyChanges();

    But it remains at 60.  Ideas?

  • @Ian Mallet

    try add this before ApplyChanges

    IsFixedTimeStep = false;

    @Shawn

    btw great Frame Counter Thank You. Just ported it to XNA 4 and it works great

  • Can someone post their ported 4.0 version? I can't seem to port this right...

  • Thank you for the fast way to have a frame rate, it will help in finding when the game starts slowing and on what basis.

    As for 4.0 version, the posted versions seems to work just fine by just copying the wanted part in my scene (sort of custom drawable element).

  • This working in XNA 4.0:

    http://pastebin.com/pziMpNwf

    new FrameRateCounter(this, new Vector2(25, 25), Color.White, Color.Black);

    Thanks Shawn.

  • i have an issue with your sample. I load it properly but when i try to load the font i get an error the font doesnt exist BUT but .spritefont is at the top root directory of my content folder.

  • Hi Owen,

    This article explains how to investigate such problems: blogs.msdn.com/.../why-does-contentmanager-load-or-titlecontainer-openstream-say-file-not-found.aspx

  • Hi, this is a good and understandable example. However, I can only seem to get it to max out at 50 frames per second. I have a pretty decent computer, which should be able to run a blank window at sixty frames per second, but still I get 50. Could this be an issue out of my hands, or is there something wrong with my code?

  • Mordi - perhaps your monitor is running at 50hz?

Page 2 of 2 (29 items) 12
Leave a Comment
  • Please add 4 and 2 and type the answer here:
  • Post