Search code examples
c++allegroallegro5

Allegro framerate issue


So i've been having some issues with Allegro recently. I have no idea what's causing it, but i will try to detail the problem below as best i can.

In my main function, i have something like this:

int main()
{
    Game *game = new Game();
    game->init(800, 600, 60); //width, height, framerate

    PlayState *playState = new PlayState(); //extends abstract class GameState
    game->setDefaultState(playState);

    game->startGame();

    gMemoryTracker.reportAllocations(cout);
    system("pause");
    return 0;
}

This works fine, and printing the elapsed time at the end of each frame shows about 16.7ms per frame. However, since i would like the Game class to eventually act as a fully-fledged GameState manager (currently it only supports one GameState), i would like the init function of the Game class to call each GameState's own individual init function. Obviously, this would mean registering each GameState before calling the Game's init function, so i changed the main function to look like this:

int main()
{
    Game *game = new Game();
    //this is where the call to init used to be

    PlayState *playState = new PlayState();
    game->setDefaultState(playState);

    game->init(800, 600, 60); //now this is called after we create a GameState and set it as default

    game->startGame();

    gMemoryTracker.reportAllocations(cout);
    system("pause");
    return 0;
}

The problem is that now each frame takes around 1100ms to render, even though the Game class reports that the framerate is still set to 60fps. In an attempt to debug this issue, i made one last change to main:

int main()
{
    Game *game = new Game();   

    PlayState *playState = new PlayState();
    game->init(800, 600, 60); //now init is being called after we create a new GameState, but before we set it as default
    game->setDefaultState(playState);

    game->startGame();

    gMemoryTracker.reportAllocations(cout);
    system("pause");
    return 0;
}

But this results in the same issue as before, with each frame taking about 1100ms to render. It seems that this issue only happens when i call init after creating a new GameState, so i looked at the constructor for the PlayState class and the init function of the Game class to see if i could find something that would cause this behavior, but i have still not been able to find the cause. You can find the two aforementioned functions below:

bool Game::init(int width, int height, float frameRate)
{
    mFrameRate = frameRate;
    bool result = mpGraphics->init(width, height); //initialize the graphics system

    //this calls the init function for the default GameState. commented-out for debugging purposes
    //result = result && mpDefaultState->init();

    return result; //were all inits successful?
}



PlayState::PlayState() : GameState("play_state")
{
    //create required graphics buffers and fonts
    bgBuffer = new GraphicsBuffer(DISPLAY_SIZE.getX(), DISPLAY_SIZE.getY());
    woodsBuffer = new GraphicsBuffer(ASSET_PATH + "Woods.png");
    smurfBuffer = new GraphicsBuffer(ASSET_PATH + "smurf_sprites.png");
    font = new Font(ASSET_PATH + "cour.ttf", 12);

    smurfAnimation = new Animation(60, true); //create new animation for smurf walk cycle. args are animation framerate (must be <= game framerate) and loop animation

    //load sprites from spritesheet
    for (int y = 0; y < (int)SPRITE_SHEET_SIZE.getY() / (int)SPRITE_SIZE.getY(); y++)
    {
        for (int x = 0; x < (int)SPRITE_SHEET_SIZE.getX() / (int)SPRITE_SIZE.getX(); x++)
        {
            //there was already a class named Rectangle, so i had to get creative
            UnequalSquare uSquare(x * (int)SPRITE_SIZE.getX(), y * (int)SPRITE_SIZE.getY(), (int)SPRITE_SIZE.getX(), (int)SPRITE_SIZE.getY());
            smurfAnimation->addSprite(Sprite(*smurfBuffer, uSquare));
        }
    }
}

One thing i also noticed is that the game runs at the proper framerate if i comment out all of the rendering calls within PlayState's render function, but obviously this is not a viable solution. I will post the render function below. Its not very efficient at the moment (creating new sprite objects every frame), but this does not explain why it works perfectly if Game.init() is called before creating the instance of PlayState.

void PlayState::render(GraphicsSystem* graphics, const Timer& frameTimer)
{
    // Create background
    Sprite bgSprite(*bgBuffer);
    graphics->fill(*bgBuffer, Color(255, 0, 0));

    // Create image
    Sprite woodsSprite(*woodsBuffer);
    Vector2D woodsLocation((DISPLAY_SIZE.getX() - (woodsSprite.getWidth() * WOODS_SCALE)) / 2.0, (DISPLAY_SIZE.getY() - (woodsSprite.getHeight() * WOODS_SCALE)) / 2.0);

    // Draw Text
    int fontWidth = font->getTextWidth(TEXT_STRING);
    int fontHeight = font->getFontHeight();

    for (int i = 0; i <= DISPLAY_SIZE.getY() / fontHeight; i++)
    {
        for (int j = 0; j <= DISPLAY_SIZE.getX() / fontWidth; j++)
        {
            graphics->drawText(*bgBuffer, Vector2D(j * fontWidth, i * fontHeight), TEXT_STRING, *font, Color());
        }
    }

    //update the animation
    smurfAnimation->update();

    // Draw sprites to backbuffer
    graphics->drawSpriteToBackbuffer(gZeroVector2D, bgSprite);
    graphics->drawSpriteToBackbuffer(woodsLocation, woodsSprite, WOODS_SCALE);
    graphics->drawSpriteToBackbuffer(gZeroVector2D, smurfAnimation->getCurrentSprite());
}

Can anyone see any reason why i might be experiencing this issue? I've been at it for a couple of hours now and i can't figure it out for the life of me.


Solution

  • I found the problem. From the Allegro 5 documentation:

    Unless you set the ALLEGRO_MEMORY_BITMAP flag, the bitmap is created for the current display. Blitting to another display may be slow.

    I was attempting to create the bitmaps before i created the display, thus resulting in poor performance. Setting the ALLEGRO_MEMORY_BITMAP flag improves the framerate considerably, but it still takes around 100ms-200ms per frame. I suppose it's just a weakness of Allegro that i will need to take into consideration from now on.

    Source: https://www.allegro.cc/manual/5/al_create_bitmap