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

Author Topic: Efficient sprite rendering?  (Read 3248 times)

0 Members and 1 Guest are viewing this topic.

lifenoodles

  • Newbie
  • *
  • Posts: 4
    • View Profile
Efficient sprite rendering?
« on: July 28, 2010, 04:49:34 pm »
Hi there, found a few posts on this topic but nothing with the same issue as mine, so thought I'd start a new thread.

I'm reasonably new to C++, although I have a lot of experience with Java/C#. I've gone through the tutorials and have a pretty good handle on pointers/references etc. I'm attempting a learn by doing approach with a project using sfml, but I'm finding the sprite drawing routines to not be as efficient as I would have hoped. I'm sure it's probably something in my code so I was wondering if someone wouldn't mind telling me if I'm doing something wrong.

None of this is final architecture, more of a test run for rendering tiles. If I make an array of 200x200 sprites, (all with the same image instance I think) and draw I get around 10 fps. I'll put in some clipping or whatever to cut out the offscreen ones but my concern is that the same app in xna doing 200x200 gets around 50 fps. Is this something I'll have to live with or is there something I'm doing that's drastically wrong?

Sprite Creation Code:
Code: [Select]
sf::Sprite ** tileMap;
tileMap = new sf::Sprite * [tileCount];
for(int i = 0; i < tileCount; i++)
{
tileMap[i] = new sf::Sprite [tileCount];
}
string strPath = "content" + string(PATH_SEPERATOR);
static sf::Image imageTest;
imageTest.LoadFromFile(strPath + "template.PNG");
imageTest.SetSmooth(false);

for(int i = 0; i < tileCount; i++)
{
for(int j = 0; j < tileCount; j++)
{
sf::Sprite sprite;
sprite.SetImage(imageTest);
tileMap[i][j] = sprite;
}
}


Drawing Code:
Code: [Select]
for(int i = 0; i < tileCount; i++)
{
for(int j = 0; j < tileCount; j++)
{
app.Draw(tileMap[i][j]);
}
}


Obviously if I cut out the app.Draw call it runs at 2000fps or something similar. It's definitely the drawing call that's slowing everything down.

Edit: All with SFML 1.6 and yes I'm testing fps with release build.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Efficient sprite rendering?
« Reply #1 on: July 28, 2010, 04:58:38 pm »
There's basically nothing wrong with your code. The only thing that you can try to get better performances, is to run the same code with SFML 2.
Laurent Gomila - SFML developer

lifenoodles

  • Newbie
  • *
  • Posts: 4
    • View Profile
Efficient sprite rendering?
« Reply #2 on: July 28, 2010, 05:01:39 pm »
Ok, will build 2.0 and see if it improves anything. Thanks Laurent, appreciate the quick response.

lifenoodles

  • Newbie
  • *
  • Posts: 4
    • View Profile
Efficient sprite rendering?
« Reply #3 on: July 28, 2010, 05:50:13 pm »
Built 2.0 dll's and fps up to ~80 for 200x200 grid. So thanks :).

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Efficient sprite rendering?
« Reply #4 on: July 28, 2010, 06:16:16 pm »
Not directly related to your topic, but especially because you come from Java/C#: In C++, you have to free the memory you allocate dynamically. There is no garbage collector. So, each new must have a corresponding delete (the same applies to new[] respectively delete[]).

You could make your life a lot easier by using standard STL containers like std::vector. They manage the memory automatically, and you can just call comfortable member functions to insert/remove elements, get the size, iterate through all elements, and so on. ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

lifenoodles

  • Newbie
  • *
  • Posts: 4
    • View Profile
Efficient sprite rendering?
« Reply #5 on: July 28, 2010, 08:01:05 pm »
Quote from: "Nexus"
Not directly related to your topic, but especially because you come from Java/C#: In C++, you have to free the memory you allocate dynamically. There is no garbage collector. So, each new must have a corresponding delete (the same applies to new[] respectively delete[]).

You could make your life a lot easier by using standard STL containers like std::vector. They manage the memory automatically, and you can just call comfortable member functions to insert/remove elements, get the size, iterate through all elements, and so on. ;)


Yeah getting the hang of interacting with memory more closely is definitely the hardest thing to adapt to. Was aware of the necessity of manually deleting but it is something I know I'll forget to do far too many times, so cheers. :)

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Efficient sprite rendering?
« Reply #6 on: July 29, 2010, 12:37:39 am »
I would forget manual deallocation, too, that's why I like automatic memory management (not garbage collection) that much... ;)

Especially such a situation can be very annoying to do by hand:
Code: [Select]
int Function()
{
    // Derived1, Derived2 are derived classes from Base
    Base* a = new Derived1;

    // if the Derived2() constructor or new throws an exception,
    // the memory of a is irreversibly lost
    Base* b = new Derived2;
   
    // ...

    if (condition)
    {
        // We must free the memory of a and b, but then
        // we can't access a anymore, so we have to store it before
        return a->GetXY();
    }
    else if (otherCondition)
    {
        // Again, we have to make sure everything is freed correctly
        throw anyException();
    }

    // In fact, we have to monitor every point where a function can leave
    return -1;
};

A correct handling would look like this:
Code: [Select]
int Function()
{
    Base* a = new Derived1;

    Base* b;
    try
    {
        b = new Derived2;
    }
    catch (...)
    {
        // Free memory and rethrow exception
        delete a;
        throw;
    }

    // ...

    if (condition)
    {
        int result = a->GetXY();
        delete a;
        delete b;
        return result;
    }
    else if (otherCondition)
    {
        delete a;
        delete b;
        throw anyException();
    }

    delete a;
    delete b;
    return -1;
};

This code is not only tedious to write, but also confusing to read and hard to maintain. In C++, we can use the destructor to free memory when an object goes out of scope. Some classes taking advantage of this technique are called smart-pointers – intelligent pointer-like objects that bear responsibility for memory ownership management. Using them, a proper solution might look like this:
Code: [Select]
int Function()
{
    // scoped_ptr is an example of a simple smart-pointer, that
    // deletes the owned object when leaving the scope
    scoped_ptr<Base> a(new Derived1);
    scoped_ptr<Base> b(new Derived2);
   
    // ...

    if (condition)
    {
        return a->GetXY();
    }
    else if (otherCondition)
    {
        throw anyException();
    }

    return -1;
};

Containing not a single delete or try-catch, this code is still safe and correct. The destructor scoped_ptr::~scoped_ptr() takes care of the whole deallocation. The big advantage is, we can add a third smart-pointer c or another exit point of the function, without making the code uglier and more error-prone.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything