Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Rendering slows down FPS  (Read 5414 times)

0 Members and 1 Guest are viewing this topic.

Nybble

  • Newbie
  • *
  • Posts: 17
    • View Profile
Rendering slows down FPS
« on: September 26, 2013, 05:17:37 am »
I am so frustrated trying to figure out why every time I render a "tile map" it slows down game play so much, I used a simple nested for loop to draw tiles like so:
Quote
for(int y = 0; y < mapHeight; y++)
for(int x = 0; y < mapWidth; x++)
{
    v.push_back(tile);
// same as v[y]
  • ; you get the point...

}

I thought this was the problem so I copied and pasted the code to for tile map from this LINK: http://www.sfml-dev.org/tutorials/2.0/graphics-vertex-array.php 

and yet again same thing happens, I have a simple question:
is it supposed to slow down the overall game play the more you draw? it makes no sense to me because if I draw a map lets say 40x40 it slows down a little, then if I draw 80x80 it pretty much slows down twice as much and so on so forth...

Is it maybe a bug with my entity update and/or rendering logic? I don't think it is, is simple update/rendering logic.

If you guys want to see some code, I would happily post it, I don't think it is needed, this happens regardless of how I approach it...

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Rendering slows down FPS
« Reply #1 on: September 26, 2013, 05:29:59 am »
I think we're going to have to see code.  All you've really told us is "I did what X said and it doesn't work," which isn't much for us to go on.

In principle of course drawing more stuff is going to slow things down, but a 2x slowdown should be pretty hard to achieve without doing something very wrong.  When you say 40x40 and 80x80, do you mean 1600 tiles and 6400 tiles?  Because that might slow things down a lot, but I have a hard time imagining you really need to draw thousands of tiles on the screen at any one time.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Rendering slows down FPS
« Reply #2 on: September 26, 2013, 05:37:50 am »
You don't seem to understand the tutorial on vertex arrays. Copying and pasting random pieces of code together won't solve your problem. I don't know why you have a push_back inside your rendering loop... or why you need a nested loop to draw your tilemap every frame at all... You don't need to post more code. It is obvious from those few lines why your rendering is slow.

Everything is all explained pretty thoroughly on the vertex array tutorial page. Spend the time and read it and most importantly, understand what is said there. I could just copy and paste pieces of it in this post, but why bother when it is written there already...
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Nybble

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Rendering slows down FPS
« Reply #3 on: September 26, 2013, 05:44:35 am »
Alright so lets just take the code from the "example tile map", lets just say I'm using this code.


Quote
const int level[] =
    {
        0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
        1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3,
        0, 1, 0, 0, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 0, 0,
        0, 1, 1, 0, 3, 3, 3, 0, 0, 0, 1, 1, 1, 2, 0, 0,
        0, 0, 1, 0, 3, 0, 2, 2, 0, 0, 1, 1, 1, 1, 2, 0,
        2, 0, 1, 0, 3, 0, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1,
        0, 0, 1, 0, 3, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
    };

    // create the tilemap from the level definition
    TileMap map;
    if (!map.load("tileset.png", sf::Vector2u(32, 32), level, 16, 8))

even using this small "map" slows gameplay a lot...

Quote
void Render(PencilTool& renderer)
    {
        Window.clear(sf::Color(0, 135, 206, 250));

        for( size_t i = 0 ; i < objectList.size(); i++)
        {
            objectList->Render(renderer);
        }

        Window.display();
    }

and the "PencilTool" is just this:

Quote
void Draw(sf::RenderWindow& window, sf::Sprite& object, const float& x, const float& y, const int16_t& x2, const int16_t& y2, const int16_t& w, const int16_t& h)
{
object.setPosition(x,y);
        object.setTextureRect(sf::IntRect(x2,y2,w,h));

        window.draw(object);
}

pretty generic stuff, that is all it does, and I obviously update object's position etc...
I never said "I did what X said and it doesn't work,"... clearly I said I used the code from here: http://www.sfml-dev.org/tutorials/2.0/graphics-vertex-array.php    after failing badly on my own, but anyways, I appreciate your help.

@ binary1248  wth are you talking about? I said after I THOUGHT my method was the problem (clearly wasn't the issue) I tried the vertext tut code, no push_back or stl etc and it does the EXACT same thing so how is the push_back the problem when the problem exist even without it?

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Rendering slows down FPS
« Reply #4 on: September 26, 2013, 06:10:30 am »
So... you used push_back in your original rendering code, it was slow, you replaced it with the code from the SFML tutorial and it was also slow, so you deduce that using push_back wouldn't cause your rendering to be slow as well? If it is really the case that your original code and the SFML code run without any difference in performance, then something is really wrong with your game loop. The point is that your original code is supposed to be slow unless you draw so little it doesn't make a difference.

I don't know how you measure performance but as Ixrec already said, the more you draw, the more your GPU has to work, so it will naturally be slower. The question however is, is your application GPU or CPU bound. If it is CPU bound then you need to look elsewhere in your application for the culprit. This is probably the case since drawing using the tutorial code doesn't seem to speed things up.

I'm curious, what is slow for you? You always say "slow" but never really define it in terms of FPS values. 1000 FPS might still be slow for some people, if e.g. they knew that they could run it at 3000 FPS if done right.

Did you try running portions of your code in a sandbox project? It helps to test the performance of individual subsections of your code, as opposed to replacing parts and coming to conclusions using deductive reasoning.

Oh and by the way, try not to pass primitive data types by const reference... it just looks wrong.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Rendering slows down FPS
« Reply #5 on: September 26, 2013, 06:12:42 am »
If all you do is paste/link the vertexarrays tutorial instead of showing us complete code we can test ourselves, all we can do is assume you're either failing to understand the tutorial or making some huge mistake elsewhere.  And the former is far more likely.  So show us your complete code (the version of it that supposedly matches the tutorial) and then we can try to help.

And like binary said, more testing and more precise numbers would help a lot.  You still haven't given us much to work with.

Nybble

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Rendering slows down FPS
« Reply #6 on: September 26, 2013, 04:45:21 pm »
Ok here it is:

Quote
class MyEntity
{
public:
    MyEntity() : sprite(m_texture)
    {
        m_texture.loadFromFile("lucas.png");

        sprite.setTextureRect(sf::IntRect(0,0,40,40));
        sprite.setPosition(0, 0);
    }

    virtual void draw(sf::RenderWindow& target) const
    {
        target.draw(sprite);
    }

    sf::Sprite sprite;
    sf::Texture m_texture;
};

Quote
class TileMap : public sf::Drawable, public sf::Transformable
{
public:

    bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
    {
        // load the tileset texture
        if (!m_tileset.loadFromFile(tileset))
            return false;

        // resize the vertex array to fit the level size

        // populate the vertex array, with one quad per tile
        for (unsigned int i = 0; i < width; ++i)
            for (unsigned int j = 0; j < height; ++j)
            {
                // get the current tile number
                int tileNumber = tiles[i + j * width];
        m_vertices.setPrimitiveType(sf::Quads);
        m_vertices.resize(width * height * 4);

                // find its position in the tileset texture
                int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                // get a pointer to the current tile's quad
                sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                // define its 4 corners
                quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
                quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
                quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);

                // define its 4 texture coordinates
                quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
            }

        return true;
    }

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();
        // apply the tileset texture
        states.texture = &m_tileset;
        // draw the vertex array
        target.draw(m_vertices, states);
    }
    sf::VertexArray m_vertices;
    sf::Texture m_tileset;
};

and main:

Quote
int main()
{

    MyEntity entity;

// create the window
    sf::RenderWindow window(sf::VideoMode(800, 600), "Tilemap");

    // define the level with an array of tile indices
    const int level[] =
    {
        0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
        1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3,
        0, 1, 0, 0, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 0, 0,
        0, 1, 1, 0, 3, 3, 3, 0, 0, 0, 1, 1, 1, 2, 0, 0,
        0, 0, 1, 0, 3, 0, 2, 2, 0, 0, 1, 1, 1, 1, 2, 0,
        2, 0, 1, 0, 3, 0, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1,
        0, 0, 1, 0, 3, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
    };

    // create the tilemap from the level definition
    TileMap map;
    if (!map.load("tileset.png", sf::Vector2u(32, 32), level, 16, 8))
        return -1;
       
    window.setFramerateLimit(60);
    float x = 0, y = 0;
    // run the main loop
    while (window.isOpen())
    {
        // handle events
        sf::Event event;
        while (window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
            x+=1; //y+=1;
            entity.sprite.setPosition(x,y);
        }

        // draw the map
        window.clear();
        window.draw(map);
        entity.draw(window);
        window.display();
    }

    return 0;

}

now if I change     if (!map.load("tileset.png", sf::Vector2u(32, 32), level, 16, 8))

the 16 to say 116 it will draw more of the texture horizontally and slow down the "entity" as it moves compare to when it was 16, same thing if I add vertically etc...

also if I comment out the part that draws the "map" it speeds up the movement of the entity....
« Last Edit: September 26, 2013, 05:00:51 pm by Nybble »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Rendering slows down FPS
« Reply #7 on: September 26, 2013, 05:13:30 pm »
This isn't a performance problem. This is related to the fact that your game world updates are tied to the frame rate and not actual passed time. You need to use sf::Clock to make your application frame rate independent. There are many threads about this already:
https://www.google.com/search?q=SFML+timestep+site:en.sfml-dev.org
http://gafferongames.com/game-physics/fix-your-timestep/
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Nybble

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Rendering slows down FPS
« Reply #8 on: September 26, 2013, 05:27:41 pm »
Well I didn't show the code here but I do use a timestep...  here is the code:

Quote
class Cfps
{
    private:
        int     rate;
        float   startTime;
        float   lastTime;
        int     Fps;
        int     frames;
        float   speed;

        sf::Clock   fpsClock;

    public:
        Cfps();
        Cfps(unsigned int _rate);

        int     getFps();
        float   getSpeed();
        void    update();
};
//==================================================================
/// Cfps
//==================================================================

Cfps::Cfps(unsigned int _rate)
{
    rate        = _rate;
    startTime   = 0;
    lastTime    = 0;
    Fps         = 0;
    frames      = 0;
    speed       = 0;
}

Cfps::Cfps()
{
    rate        = 60;
    startTime   = 0;
    lastTime    = 0;
    Fps         = 0;
    frames      = 0;
    speed       = 0;
}
//----------------------------------------------------------------
int Cfps::getFps()     {return Fps;}
//==================================================================
float Cfps::getSpeed() {return speed;}
//==================================================================
void Cfps::update()
{
    sf::Time ticks = fpsClock.getElapsedTime();

    //one second has passed ( 1000 miliseconds )
    if (startTime + 1000 < ticks.asMilliseconds())
    {
        startTime   = ticks.asMilliseconds();
        Fps         = frames;
        frames      = 0;
    }
    speed           = ( (ticks.asMilliseconds() - lastTime) / 1000 * rate );
    lastTime        = ticks.asMilliseconds();
    frames++;
}
Cfps    appFps(60);

then I do this in the main loop before update:
Quote
appFps.update();

same result.....

I think you are right though, what I need to do is multiply movement by delta time, I think...
« Last Edit: September 26, 2013, 05:35:56 pm by Nybble »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Rendering slows down FPS
« Reply #9 on: September 26, 2013, 05:43:29 pm »
So... what exactly is this Cfps class supposed to do? You update it every frame so that it computes new values but where do you use these values? Also I don't get why you can't just use .getElapsedTime() and/or .restart() instead of all those extra variables. You should also enable conversion warnings. You implicitly convert values all over the place which might not lead to what you would expect.

It doesn't have to be this complicated. Assuming your application will always run at 60 FPS is also something you shouldn't do. As soon as you get frames that take a bit longer every now and then, your updates will all break.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).