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

Author Topic: SFML 2 inside out - Performances & optimisations  (Read 5502 times)

0 Members and 1 Guest are viewing this topic.

nitrix

  • Newbie
  • *
  • Posts: 27
    • View Profile
SFML 2 inside out - Performances & optimisations
« on: December 05, 2011, 08:54:02 am »
Hi everyone,

my team and I just decided SFML would be the way to go for our future projects. I'm a programmer-analyst so I'm in charge to make all the strategic decisions about our work-in-progress engine.

I'd like to make sure I know SFML inside-out, along with the good practices and common pitfalls. Also any tips from the top of your head / experience is very welcomed.

I switched to SFML knowing its OpenGL core has a lot more to offer than SDL, yet with an extreme simplicity.

Note: The game we're working on is using a 2D, top-view, tile based engine. Tiles are 32x32 pixels large and the character is a playing entity of the game (meaning most likely the Camera will be centered on him and the world shall move around). Oh and the world is loaded in chunks.

Here are my starting questions:

1 - I have an SDL background where using dirty rectangles is almost necessary; from what I read on the forums, clearing the entire screen and drawing all the (only camera visible) tile sprites, then calling display() is the natural way of doing things.

  • Is this a concern for the GPU to redraw the entire screen every frames?
  • If not, it would allow me to have a camera centered on the player and easily move the world around when he moves + without any tearings?
  • Consider the fact I'm doing a multiplayer game, I might have to update a SINGLE tile once in a while, but rarely redraw the entire screen (unless there's a map change, or -like previously said- the camera is centered on the player).


2 - I also heard about RenderTexture, what's the gain?
  • If I understood it right, I think the rendering loop will display the RenderTexture easily, and my job is to draw/blit the sprite on that texture to make it efficient?


3 - When it comes to drawing the tiles (they are layered btw), it's better to group the tiles with the same textures together as there's less need to switch from one texture to another from the graphic driver.
  • True or not? When using a RenderTexture, this should get rid of this problem, right?


So yeah, sorry for bothering you guys. I think I just drank too much of the optimisation kool-aid, but honestly, I'm not a fan of wasting CPU/GPU cycles EVEN if today's computers are generally all very efficient anyway.

Big thanks in advance to anyone that can point me the best way to go from there if I'm planning to create an engine from scratch. I'm not a slacker, if there's an optimal way, it'll be mine.

I also wish Laurent can see this. If you do, thanks for your time and feel free to answer in french or english, whatever is your primary language :]

Alex.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
SFML 2 inside out - Performances & optimisations
« Reply #1 on: December 05, 2011, 09:43:02 am »
Quote
from what I read on the forums, clearing the entire screen and drawing all the (only camera visible) tile sprites, then calling display() is the natural way of doing things.

It is mandatory with modern architectures. GPUs are designed to be used this way. As far as I know, OpenGL doesn't even define the concept of dirty rectangles.

Quote
I also heard about RenderTexture, what's the gain?

If you have a static background made of several tiles, it may be faster to pre-render it to a single texture and use a single sprite to display it.
But with the new graphics API (currently being tested), this trick won't be necessary anymore, you'll be able to define your whole level as a single drawable entity (and thus draw it with a single OpenGL call, which is very fast).

Quote
When it comes to drawing the tiles (they are layered btw), it's better to group the tiles with the same textures together as there's less need to switch from one texture to another from the graphic driver.

True, if SFML implements a texture cache (most drivers don't make a difference if you bind the same texture of another one). But again, things will be different with the new graphics API.

So if you're really concerned with optimizations, and how things work internally, I suggest that you take a look at the new graphics API first (there are two recent threads in the General forum about it).
Laurent Gomila - SFML developer

nitrix

  • Newbie
  • *
  • Posts: 27
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #2 on: December 05, 2011, 10:51:39 am »
Wow, awesome work on the new branch!

So the new mesh/map thing is what I draw the entire map once, then do "dirty rectangles/region" updates like I'm used to by applying "tileset sprites".

Oh and display the whole thing in a window.

When the player is moving, I can move the map, and if he's too far on one side, I can crop a part of the map to load another chunk.

actually its like working with a RenderTexture but at a lower level and cleaner?

If so I just love your new approach :D

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
SFML 2 inside out - Performances & optimisations
« Reply #3 on: December 05, 2011, 11:04:32 am »
Quote
So the new mesh/map thing is what I draw the entire map once, then do "dirty rectangles/region" updates like I'm used to by applying "tileset sprites".

I'm not sure that I understand this correctly.

Here is what a typical tilemap would look like with the new API:
Code: [Select]
const int size = 32;

// load the texture containing all the tiles
sf::Texture tileset;
tileset.LoadFromFile("tileset.png");

// create the map
sf::VertexArray map(sf::Quads, width * height * 4);
for (int x = 0; x < width; ++x)
    for (int y = 0; y < height; ++y)
    {
        int current = (x + y * width) * 4;

        // define the position of the 4 points of the current tile
        map[current + 0].Position = sf::Vector2f((x + 0) * size, (y + 0) * size);
        map[current + 1].Position = sf::Vector2f((x + 0) * size, (y + 1) * size);
        map[current + 2].Position = sf::Vector2f((x + 1) * size, (y + 1) * size);
        map[current + 3].Position = sf::Vector2f((x + 1) * size, (y + 0) * size);

        // define the texture coordinates of the 4 points of the current tile
        int tx = /* X index of the tile in the tileset */;
        int ty = /* Y index of the tile in the tileset */;
        map[current + 0].TexCoords = sf::Vector2i((tx + 0) * size, (ty + 0) * size);
        map[current + 1].TexCoords = sf::Vector2i((tx + 0) * size, (ty + 1) * size);
        map[current + 2].TexCoords = sf::Vector2i((tx + 1) * size, (ty + 1) * size);
        map[current + 3].TexCoords = sf::Vector2i((tx + 1) * size, (ty + 0) * size);
    }

// draw the map
window.Draw(map, &tileset);


If you need to change a tile, you just have to update the texture coordinates of the 4 corresponding vertices in the vertex array.

In your case, you would have such a vertex array for each chunk.

So it's not similar to RenderTexture, it's a new approach. There are generally two kind of techniques in graphics rendering: geometry-based, and image-based. RenderTexture is the image-based technique, it pre-draws stuff so that it's available as a single texture. VertexArray is the geometry-based technique, it gathers several quads/triangles into a unique, more complex graphical entity; so you get as many polygons as before, but you draw them with only a few OpenGL calls (which is what killed performances in SFML before).
Laurent Gomila - SFML developer

nitrix

  • Newbie
  • *
  • Posts: 27
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #4 on: December 05, 2011, 04:03:04 pm »
Matrices, vectors and shaders. The speedy fast hardware stuff (: I'll play with it and I can't thank you enough! Gotta looove the new API :]

nitrix

  • Newbie
  • *
  • Posts: 27
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #5 on: December 05, 2011, 08:00:55 pm »
Okay, the sf::VertexArray is absolutely awesome! It's really easy yet flexible.

I've been toying with some points coordinates and observing the texture getting distorted, it's genious! Also the color-per-point as well, you can have gradients :D

Eheheh! Quick question tho: I'm done coding the basics and up to the "Camera" class. Am I stuck with a static camera or it's possible to move the VertexArray?

I was thinking of something along "loop through every vertex and change their position".. is it ideal or there's a sf::Transform implementation somewhere I missed?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
SFML 2 inside out - Performances & optimisations
« Reply #6 on: December 05, 2011, 08:10:01 pm »
Quote
I'm done coding the basics and up to the "Camera" class. Am I stuck with a static camera or it's possible to move the VertexArray?

I was thinking of something along "loop through every vertex and change their position".. is it ideal or there's a sf::Transform implementation somewhere I missed?

Cameras (ie. moving the whole scene) are usually implemented with sf::View.

To move a single vertex array, use a sf::Transform with a translation inside.
Laurent Gomila - SFML developer

jone

  • Newbie
  • *
  • Posts: 12
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #7 on: January 23, 2012, 06:53:47 pm »
Quote from: "Laurent"

To move a single vertex array, use a sf::Transform with a translation inside.


I apologize for threadjacking, but how would I do this? Do I need to use sf::Transform::GetMatrix and use that on the vertex array, or is there a more direct way that I am missing? I'm using a version of SFML2 that I  grabbed from the git repo on 22.1.

jone

  • Newbie
  • *
  • Posts: 12
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #8 on: January 23, 2012, 09:32:25 pm »
Quote from: "jone"
Quote from: "Laurent"

To move a single vertex array, use a sf::Transform with a translation inside.


I apologize for threadjacking, but how would I do this? Do I need to use sf::Transform::GetMatrix and use that on the vertex array, or is there a more direct way that I am missing? I'm using a version of SFML2 that I  grabbed from the git repo on 22.1.


Of course, I can also iterate through all the vertices in the vertex array and perform the transformation on them individually... :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
SFML 2 inside out - Performances & optimisations
« Reply #9 on: January 23, 2012, 09:53:59 pm »
Code: [Select]
sf::Transform transform;
transform.Translate(x, y);
window.Draw(vertexArray, transform);
Laurent Gomila - SFML developer

jone

  • Newbie
  • *
  • Posts: 12
    • View Profile
SFML 2 inside out - Performances & optimisations
« Reply #10 on: January 24, 2012, 07:48:55 am »
Quote from: "Laurent"
Code: [Select]
sf::Transform transform;
transform.Translate(x, y);
window.Draw(vertexArray, transform);


Ah, I see. Thank you!