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

Author Topic: Automatic batching in sfml2 branch  (Read 30538 times)

0 Members and 3 Guests are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« on: September 24, 2009, 10:09:31 am »
Hi

After several weeks of work, I've finally commited the automatic batching code in the sfml2 branch.

Basically, it doesn't break anything in the public API so that most people won't notice anything except potentially improved performances.

The only modifications are on sf::Drawable and sf::RenderWindow:
- the Drawable::Render function now use a render queue instead of direct OpenGL calls
- drawables rendering nested drawables work better: the color is now combined in addition to transformations
- PreserveOpenGLStates doesn't exist anymore, states are now preserved by default (the rendering happens in one call, so doing it doesn't impact performances anymore)
- there's a new Flush function to manually trigger the actual rendering, for example if you need to draw 3D OpenGL on top of what SFML has drawn so far (otherwise rendering is automatically done in Display())
- RenderImage must now call Display() like RenderWindow
- windows are no longer active by default
- multithreading is potentially easier, as all the OpenGL calls happen in a single function (I haven't looked into that yet)
- rendering is now pixel perfect, all artifacts are gone (hopefully :D)

Regarding the performances, I don't really know if it will really be faster on every computer (the code now uses a little more CPU), so I'll need as much feedback as possible :)
This is the first version, so I'll probably have to adjust/fix a few things.

On my computer, the worst case (drawing sprites with different states) gave the same performances as before, and the best case (all sprites use the same image and states) gave a 300% improvement. Shapes gave a 500% improvement. Strings are slightly slower to render, but it's much more consistent than before; and they will soon be rewritten so it doesn't really matters ;)
The most important is that one can now draw intensive stuff like particle systems, tiles, GUI, etc. with SFML, there's no need to use OpenGL to get decent performances.

The next step will now be to rewrite PostFx to be compatible with the new system (and apply the modifications planned in the task list).

Please note that the quality of text rendering is slightly worse than before, it's a work in progress and it will be fixed soon.

CSFML and SFML.Net are also not up-to-date yet.
Laurent Gomila - SFML developer

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Automatic batching in sfml2 branch
« Reply #1 on: September 24, 2009, 01:39:28 pm »
Sounds great, but doesn't work on my side. Minimal example:

Code: [Select]
#include <SFML/Graphics.hpp>

int main() {
sf::RenderWindow  window( sf::VideoMode( 1024, 768, 32 ), "TEST" );
sf::Event         event;
sf::Image         image;
sf::Sprite        sprite;

image.LoadFromFile( "listbox.png" );
sprite.SetImage( image );

while( window.IsOpened() ) {

while( window.GetEvent( event ) ) {
if( event.Type == sf::Event::Closed ) {
window.Close();
}
}

window.Clear();
window.Draw( sprite );
window.Display();
}
}


My window keeps black. Also all other SFML applications don't render anything at all, just the background.

Tested under Debian GNU/Linux (testing branch).

Mindiell

  • Hero Member
  • *****
  • Posts: 1261
    • ICQ Messenger - 41484135
    • View Profile
Re: Automatic batching in sfml2 branch
« Reply #2 on: September 24, 2009, 02:13:50 pm »
Quote from: "Laurent"
- windows are no longer active by default

You probably have to SetActive your RenderWindow  :wink:
Mindiell
----

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« Reply #3 on: September 24, 2009, 02:33:44 pm »
Quote
You probably have to SetActive your RenderWindow

I was only talking about external OpenGL commands. SFML windows are smart enough to activate theirselves when they render their drawables.

Quote
Sounds great, but doesn't work on my side

Works on Windows for me. I'll try on Linux, although the new system doesn't involve anything which is OS-specific.
Laurent Gomila - SFML developer

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Automatic batching in sfml2 branch
« Reply #4 on: September 24, 2009, 02:49:53 pm »
Maybe it's a difference in the OpenGL implementations or graphics-card dependant (a GTX 260 on my side).

With more sprites (more than 100) I get this:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« Reply #5 on: September 24, 2009, 03:29:16 pm »
The makefiles have also been updated so that SFML is installed to another directory by default. Make sure it doesn't conflict with previous versions.

Does the Clear() function work (try a different color than black) ?
Laurent Gomila - SFML developer

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Automatic batching in sfml2 branch
« Reply #6 on: September 24, 2009, 03:31:37 pm »
Quote from: "Laurent"
The makefiles have also been updated so that SFML is installed to another directory by default. Make sure it doesn't conflict with previous versions.

SFML files are only present in /usr/local/lib/. But that Makefiles changes were not introduced in the last commit.

Quote
Does the Clear() function works (try a different color than black) ?

Yes, the Clear() function works perfectly (see screenshot above).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« Reply #7 on: September 24, 2009, 03:46:59 pm »
It should work now.
Laurent Gomila - SFML developer

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Automatic batching in sfml2 branch
« Reply #8 on: September 24, 2009, 03:57:26 pm »
Thank you, it's working now. :)

Quote
Please note that the quality of text rendering is slightly worse than before, it's a work in progress and it will be fixed soon.

Indeed, the quality decreased a lot. ;)

I'll comment on performance soon when I'm ready to do some tests with a huge tilechat together with 3D models (regarding to old PreserveOpenGLStates()).

Keep it up!

K-Bal

  • Full Member
  • ***
  • Posts: 104
    • View Profile
    • pencilcase.bandcamp.com
    • Email
Automatic batching in sfml2 branch
« Reply #9 on: September 25, 2009, 02:30:34 pm »
I can't get pure OpenGL to work with SFML2. Minimal example:

Code: [Select]
#include <SFML/Graphics.hpp>
#include <GL/freeglut.h>

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    sf::RenderWindow myWindow(sf::VideoMode::GetDesktopMode(), "Ogl with SFML2");
    myWindow.UseVerticalSync(true);

    while(myWindow.IsOpened())
    {
        sf::Event event;
        while(myWindow.GetEvent(event))
        {
            switch(event.Type)
            {
                case sf::Event::Closed:
                {
                    myWindow.Close();
                    break;
                }
                default:
                {
                    break;
                }
            }

            myWindow.Clear();

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

            glBegin(GL_POLYGON);
            {
                glColor3f(1.0,1.0,1.0);
                glVertex3f(0.25, 0.25, 0.0);
                glVertex3f(0.75, 0.25, 0.0);
                glVertex3f(0.75, 0.75, 0.0);
                glVertex3f(0.25, 0.75, 0.0);
            }
            glEnd();
            myWindow.Flush();

            myWindow.Display();
        }
    }


    return 0;
}
Listen to my band: pencilcase.bandcamp.com

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« Reply #10 on: September 25, 2009, 02:44:36 pm »
Look at the OpenGL sample from the SDK to see the changes.

Here is your corrected code:

Code: [Select]
#include <SFML/Graphics.hpp>
#include <GL/freeglut.h>

int main(int argc, char** argv)
{
    glutInit(&argc, argv); // ????
    sf::RenderWindow myWindow(sf::VideoMode::GetDesktopMode(), "Ogl with SFML2");
    myWindow.UseVerticalSync(true);

    while(myWindow.IsOpened())
    {
        sf::Event event;
        while(myWindow.GetEvent(event))
        {
            switch(event.Type)
            {
                case sf::Event::Closed:
                {
                    myWindow.Close();
                    break;
                }
                default:
                {
                    break;
                }
            }

            myWindow.Clear();

            myWindow.SetActive(); // <--- activate your window before OpenGL rendering

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

            glBegin(GL_POLYGON);
            {
                glColor3f(1.0,1.0,1.0);
                glVertex3f(0.25, 0.25, 0.0);
                glVertex3f(0.75, 0.25, 0.0);
                glVertex3f(0.75, 0.75, 0.0);
                glVertex3f(0.25, 0.75, 0.0);
            }
            glEnd();
            // myWindow.Flush(); <--- not needed

            myWindow.Display();
        }
    }


    return 0;
Laurent Gomila - SFML developer

K-Bal

  • Full Member
  • ***
  • Posts: 104
    • View Profile
    • pencilcase.bandcamp.com
    • Email
Automatic batching in sfml2 branch
« Reply #11 on: September 25, 2009, 02:52:31 pm »
Okay, thank you ;)
Listen to my band: pencilcase.bandcamp.com

Avency

  • Full Member
  • ***
  • Posts: 113
    • View Profile
Automatic batching in sfml2 branch
« Reply #12 on: September 26, 2009, 10:22:28 pm »
Now that I've had some time to test the new revision, I found some problems.
For me, performance has decreased a lot.
FPS have dropped from around ~6900 to ~900 (using the same OpenGL-code) or ~700 (the OpenGl code replaced with RenderQueue-code) when rendering a 2D tilemap + a few sprites.
For some odd reason the cpu usage stays at ~10-15% (instead of 25%), with drops to 1-2% which cause massive framedrops.
Older binaries linked aganst sfml 1.5 still work fine, as the previous revision of sfml2 did.
I've tried a few things like manually using the immediate mode renderer or getting rid of saving and restoring the GL-states.
I really don't know whats causing that slowdown...even if the batch renderer was slower, the GL code shouldn't be affected that much from the changes (I've looked through all files that changed in that revision and couldn't find any hint).
Even profiling with Valgrind gave no results.

Something else:
Why is the stack of render states (myStatesStack) of sf::RenderQueue fixed 16 elements?
It will cause the following code to segfault (I know that it is an artificial test case, but still)
Code: [Select]
#include <SFML/Graphics.hpp>
#include <iostream>

class TestDrawable : public sf::Drawable
{
public:
TestDrawable(int id) : mId(id)
{
}

void Render(sf::RenderTarget& target, sf::RenderQueue& queue) const
{
std::cout << mId << std::endl;

if (mId < 15)
{
TestDrawable nestedDrawable(mId + 1);

target.Draw(nestedDrawable);
}
}

private:
int mId;
};

int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600, 32), "SFML Window");

TestDrawable test(0);

window.Draw(test);
window.Display();
}

I hope that those initial problems can be sorted out, since I really like the new batch rendering interface.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Automatic batching in sfml2 branch
« Reply #13 on: September 27, 2009, 11:17:30 am »
Quote
FPS have dropped from around ~6900 to ~900 (using the same OpenGL-code) or ~700

This doesn't mean anything... Here you're talking about less than 1 ms, which is the same difference as between 50 and 52 FPS.
Benchmarks done at such high framerates are not relevant at all, as the rendering part only represents a small percentage of the whole frame. The contribution of the event handling, window management, memory transfers, etc. is not negligible.

Quote
Why is the stack of render states (myStatesStack) of sf::RenderQueue fixed 16 elements?

This part of the code is very critical, and even a slight modification has a huge impact on performances. And in this case, using a fixed-size array is faster than using a dynamic one.

Quote
It will cause the following code to segfault (I know that it is an artificial test case, but still)

Absolutely :)
But nobody will ever have 16 levels of nested drawables; and if it happens, I can easily increase the limit (it just takes a little more memory).

Quote
I hope that those initial problems can be sorted out

Honestly, I don't think that having 900 FPS instead of 6900 can be called a "problem". It doesn't mean anything, and it might even give different results when you'll have more data to render.
How many drawables do you render in this program?
Laurent Gomila - SFML developer

Avency

  • Full Member
  • ***
  • Posts: 113
    • View Profile
Automatic batching in sfml2 branch
« Reply #14 on: September 27, 2009, 12:43:42 pm »
The FPS are not the problem (I usually cap them and use VSync if possible), but the framedrops definitely are. They occur at random times.
I wonder why it doesn't take full cpu. I know that this could be scheduler related, but it didn't happen witholder revisions.
I noticed that same happens with the example applications (the cpu stays at about 10% on a quad). Although the framedrops are not noticable as they are when scrolling a map, they also occur (this can be noticed best in the opengl sample).

Quote
This part of the code is very critical, and even a slight modification has a huge impact on performances. And in this case, using a fixed-size array is faster than using a dynamic one.

I thought so. There should be a note in the docs or even range checking if the performance penalty isn't too high.