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

Author Topic: Drawing 3000 tiles results in 2 fps in debug, 25 fps release  (Read 8934 times)

0 Members and 4 Guests are viewing this topic.

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Hi guys, I must be doing something wrong (hopefully). I'm compiling it with VS 2008.

Here is how I load the tileset and create the sprites
Code: [Select]

    std::vector<std::vector<int> > mapTiles; // contains the id of the tiles
    std::vector<sf::Sprite> map; // contains the tiles itself (3072)
    sf::Rect<int> tilesRects[(TILESET_HORIZONTAL_TILES*TILESET_VERTICAL_TILES)+1]; // contains the subrects of each kind of tile
    // Load tiles (subrects)
    for (int y=0; y<TILESET_VERTICAL_TILES; y++)
    {
        for (int x=0; x<TILESET_HORIZONTAL_TILES; x++)
        {
            sf::Rect<int> rect;
            rect.Top = y * TILE_HEIGHT;
            rect.Bottom = y * TILE_HEIGHT + TILE_HEIGHT;
            rect.Left = x * TILE_WIDTH;
            rect.Right = x * TILE_WIDTH + TILE_WIDTH;
            tilesRects[1+x+y*TILESET_HORIZONTAL_TILES] = rect;
        }
    }

    // Create tiles (3072 sprites)
    sf::Image *tileset = gImageManager.getResource("world.png");
    for (int y=0; y<SCREEN_VERTICAL_TILES; y++)
    {
        for (int x=0; x<SCREEN_HORIZONTAL_TILES; x++)
        {
            sf::Sprite sprite;
            sprite.SetImage(*tileset);
            sprite.SetPosition(x*TILE_WIDTH, y*TILE_HEIGHT);
            sprite.SetSubRect(tilesRects[mapTiles[y][x]]);
            map.push_back(sprite);
        }
    }


Drawing
Code: [Select]
   for (int i=0; i<map.size(); i++)
    {
        window.Draw(map[i]);
    }
    window.Display();


My computer specs are
i5 2.26Ghz
Intel GMA
On dedicated card (Radeon HD 5650) I only get 60FPS (60 fps release, 10fps debug), which I find extremely low for such task.

I've read that SMFL 2 boosts the speed, but is it normal that with SMFL 1.6 it's this slow?

Thanks A LOT in advance.

Edit: Tried it with SMFL 2 and now debug and release have 15 FPS... weird

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #1 on: June 24, 2011, 04:20:14 pm »
Drawing tiles is a heavy task no matter what library you use or no matter what optimizations you do(like tilesets/spritesheet). Imagine that you will be doing 3000 Draw calls to the GPU each frame. Also among that there's a lot of calculations to map the texture to the correct point on the sprite and so on. It is pretty heavy. And most of those tiles are not even being viewed on the display!

I recommend a space partitioning algorithm to decrease the amount of tiles you are drawing by only testing against the tiles in view and only drawing those. Why you need space partitioning is because if you test against every tile you have in the world that will become a bottleneck of the application.
An easy one to get you started are implementing a grid as I have explained here: http://www.sfml-dev.org/forum/viewtopic.php?p=32767&highlight=#32767
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #2 on: June 24, 2011, 04:28:18 pm »
Why are you using 3 completely different containers for essentially the same thing? Couldn't you put the tile ids (int), the sprites (sf::Sprite) and the rectangles (sf::IntRect) in one structure and use a single container?

By the way, you could reuse sprites and subrects for tiles that look the same. Then you don't need a giant image, either.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #3 on: June 24, 2011, 04:43:09 pm »
Quote from: "Nexus"
By the way, you could reuse sprites and subrects for tiles that look the same. Then you don't need a giant image, either.

Well he would still want to have a giant image because it speeds up the draw calls as the image is already loaded and bound.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #4 on: June 24, 2011, 05:14:26 pm »
Quote from: "Groogy"
Drawing tiles is a heavy task no matter what library you use or no matter what optimizations you do(like tilesets/spritesheet). Imagine that you will be doing 3000 Draw calls to the GPU each frame. Also among that there's a lot of calculations to map the texture to the correct point on the sprite and so on. It is pretty heavy. And most of those tiles are not even being viewed on the display!

I recommend a space partitioning algorithm to decrease the amount of tiles you are drawing by only testing against the tiles in view and only drawing those. Why you need space partitioning is because if you test against every tile you have in the world that will become a bottleneck of the application.
An easy one to get you started are implementing a grid as I have explained here: http://www.sfml-dev.org/forum/viewtopic.php?p=32767&highlight=#32767

The 3k tiles are the screen tiles, the map itself is larger, the code there is only drawing the screen size (3072 tiles). Previously with SDL this was much faster so there must be a way to speed this up. I will look into your thread, thanks for the help, but as I am akready drawing the minimum, I dont see how this will help.

The suggestion from the other guy would never speed it up.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #5 on: June 24, 2011, 05:49:37 pm »
This should be much faster with SFML 2. Are you using a recent revision? It's weird that you get the same results in both debug and release...

The 60 FPS are probably due to v-sync which is enabled by default in your driver.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #6 on: June 24, 2011, 07:53:24 pm »
Still how do you check for if the tile is viewed? If you do a per-tile check then you definitely need to do what I wrote on the specified post. Are you assuming that it's the draw that slows down the application or do you actually have data to support that it's the render that does it?
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #7 on: June 24, 2011, 08:39:01 pm »
Quote from: "Laurent"
This should be much faster with SFML 2. Are you using a recent revision? It's weird that you get the same results in both debug and release...

The 60 FPS are probably due to v-sync which is enabled by default in your driver.

I used the snapshot provided at the download section.
Do I have to change anything else at SMFL 2 besides pollEvent and rect.width/height to make it faster? I heard about RenderImage but I don't know what to do with it.
Yes, I also found it weird, that the FPSs are the same. I even deleted the debug DLLs and tried running as debug and it complained the debug DLLs were missing. Then I deleted the release DLLs and tried running the program and it complained the release DLLs were missing. They are also different size, so I don't know what could be it.

Release, linker:
sfml-system.lib
sfml-graphics.lib
sfml-window.lib
sfml-audio.lib
tinyxml.lib

Debug, linker:
sfml-system-d.lib
sfml-graphics-d.lib
sfml-window-d.lib
sfml-audio-d.lib
tinyxml.lib

Thanks alot in advance for your help!

Quote from: "Groogy"
Still how do you check for if the tile is viewed? If you do a per-tile check then you definitely need to do what I wrote on the specified post. Are you assuming that it's the draw that slows down the application or do you actually have data to support that it's the render that does it?

At the example I gave, I'm only adding the tiles of the map that fit the screen (SCREEN_VERTICAL_TILES, SCREEN_HORIZONTAL_TILES), so I'm not even trying or checking if the other tiles are drawable. To actually draw all tiles of the map, without checking if they should be drawn, this would be the code (which makes it even slower, obviously):

Code: [Select]
   for (int y=0; y<mapTiles.size(); y++)
    {
        for (int x=0; x<mapTiles[y].size(); x++)
        {
            sf::Sprite sprite;
            sprite.SetImage(*tileset);
            sprite.SetPosition(x*TILE_WIDTH, y*TILE_HEIGHT);
            sprite.SetSubRect(tilesRects[mapTiles[y][x]]);
            map.push_back(sprite);
        }
    }

So what my code is doing right now, as shown on the first post, is as if I added a map that is exactly the size of the screen.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #8 on: June 24, 2011, 08:59:29 pm »
The libraries are not at fault, you should try and set Vertical sync trough the sf::Window class to false.
http://www.sfml-dev.org/documentation/2.0/classsf_1_1Window.php#a824ae1c61ddf2b45f7fa00472f0b6b4e

Also my point was that you actually do loop trough every tile even if they are not shown. If that is done every frame you will get an FPS drop, especially if you do it in debug with STL containers.

Anyway I seem having a hard time understanding what you are actually doing.
Because the impression I get is that you are never moving the camera? You add the visible tiles once to the map variable and then the variable is never touched other to iterate trough for rendering? And map ONLY contain the tiles that are visible? But the camera, or whatever you have to represent a camera, never moves? How large are your tiles actually?

Also try some lightweight benchmarking, try and comment out parts of code you think is the culprit, like the actual call to sf::Window::Draw and compare how much your FPS go up.

Also about RenderImage, what you can do there to speed it up is that if you got a static background(tiles don't animate or change often and so on) then you can render the tiles to the render image at initiation/loading. Then use that image to render as a background in the actual window. So instead of rendering 3k+ Tiles you only render one gigantic image instead.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #9 on: June 24, 2011, 09:57:56 pm »
Quote from: "Groogy"
The libraries are not at fault, you should try and set Vertical sync trough the sf::Window class to false.
http://www.sfml-dev.org/documentation/2.0/classsf_1_1Window.php#a824ae1c61ddf2b45f7fa00472f0b6b4e

Also my point was that you actually do loop trough every tile even if they are not shown. If that is done every frame you will get an FPS drop, especially if you do it in debug with STL containers.

Anyway I seem having a hard time understanding what you are actually doing.
Because the impression I get is that you are never moving the camera? You add the visible tiles once to the map variable and then the variable is never touched other to iterate trough for rendering? And map ONLY contain the tiles that are visible? But the camera, or whatever you have to represent a camera, never moves? How large are your tiles actually?

Also try some lightweight benchmarking, try and comment out parts of code you think is the culprit, like the actual call to sf::Window::Draw and compare how much your FPS go up.

Also about RenderImage, what you can do there to speed it up is that if you got a static background(tiles don't animate or change often and so on) then you can render the tiles to the render image at initiation/loading. Then use that image to render as a background in the actual window. So instead of rendering 3k+ Tiles you only render one gigantic image instead.

Sorry if I wasn't clear Groogy. But you got it, right now I don't have a camera, it's never touched or moved again. All tiles on map are visible. It was just a test to see how fast it can go. I'm going to implement the camera and add all tiles when I get it work faster. The tiles are 16x16. Here are my constants:

const int SCREEN_WIDTH = 1024;
const int SCREEN_HEIGHT = 768;
const int SCREEN_HORIZONTAL_TILES = SCREEN_WIDTH / 16;
const int SCREEN_VERTICAL_TILES = SCREEN_HEIGHT / 16;
const int SCREEN_BPP = 32;
const int FRAMES_PER_SECOND = 30;
const int TILESET_WIDTH = 256;
const int TILESET_HEIGHT = 704;
const int TILESET_HORIZONTAL_TILES = TILESET_WIDTH / 16;
const int TILESET_VERTICAL_TILES = TILESET_HEIGHT / 16;
const int TILE_WIDTH = 16;
const int TILE_HEIGHT = 16;

The Vertical Sync didn't change anything. When I commented draw, FPS went to between 500 and 1000 (to calculate it I'm simply doing 1000.f / window.GetFrameTime())

Would the RenderImage give me a better speed? I will have to move camera in the future though.

Thanks again!

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #10 on: June 24, 2011, 10:47:19 pm »
Hmm sounds really weird that it would go so slow for you to render only 16x16 sized tiles.... hmmm...  Do you have the latest drivers? I don't know why it would be so slow for you to render tiles.

Anyway you can get it to work with render image too with camera but it will be a bit more tricky as you'll have to divide the map into several images as there is a limit to how big a texture on the GPU can be.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #11 on: June 24, 2011, 11:08:15 pm »
Quote from: "Groogy"
Hmm sounds really weird that it would go so slow for you to render only 16x16 sized tiles.... hmmm...  Do you have the latest drivers? I don't know why it would be so slow for you to render tiles.

Anyway you can get it to work with render image too with camera but it will be a bit more tricky as you'll have to divide the map into several images as there is a limit to how big a texture on the GPU can be.

The tiles are static, so this seems perfect. Could you link me to some documentation or tutorial? How big can the images be? Thanks a lot in advance!

So RenderImage works like instead of displaying tiles of 16x16, I group a bunch of tiles together and display tiles of for example 256x256? Sounds awesome. Memory is basically free these days so I'd trade in for performance any day.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #12 on: June 24, 2011, 11:47:33 pm »
It's fairly new to SFML so don't think there's any tutorials, all I can recommend is the documentation at: http://www.sfml-dev.org/documentation/2.0/classsf_1_1RenderImage.php

The max size of an image is based on the GPU and can be discovered by using: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Image.php#acb15b7adf8aa6f2155e6f5ce3c11baf5
But I think you are guaranteed to around 2048x2048
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Clash

  • Newbie
  • *
  • Posts: 9
    • View Profile
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #13 on: June 25, 2011, 11:02:30 am »
Quote from: "Groogy"
It's fairly new to SFML so don't think there's any tutorials, all I can recommend is the documentation at: http://www.sfml-dev.org/documentation/2.0/classsf_1_1RenderImage.php

The max size of an image is based on the GPU and can be discovered by using: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Image.php#acb15b7adf8aa6f2155e6f5ce3c11baf5
But I think you are guaranteed to around 2048x2048

Hi, thanks for the help!

I have a question, RenderImage is NonCopyable, I then tried creating it inside a function and associating it to a sprite, but as soon as the function ends the destructor from the RenderImage is called and the program crashes. As it's NonCopyable I can't add it to a container either. Is RenderImage supposed to be a forever lasting variable like RenderWindow?

BTW I couldn't follow the beginning the tutorial. Error C2039: 'IsAvailable' : is not a member of 'sf::RenderImage'

Edit: So, using dynamic memory (which I do not like) to avoid the destructors and get the code to work, the FPS increased to 166~250, and that is drawing the whole map with 512x512 images, even what's outside the screen. Awesome!

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Drawing 3000 tiles results in 2 fps in debug, 25 fps release
« Reply #14 on: June 25, 2011, 11:59:43 am »
Quote from: "Clash"
Is RenderImage supposed to be a forever lasting variable like RenderWindow?
Neither of them is. They are supposed to be destroyed (manually or automatically) as soon as they aren't used anymore.

Quote from: "Clash"
Edit: So, using dynamic memory (which I do not like) to avoid the destructors
Not calling destructors is not really a solution, since it leads to memory/resource leaks. If the destructor really crashes if you are using the class correctly, then it is likely to be a bug in SFML.

Do you have a minimal code reproducing this problem?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything