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

Author Topic: Shape Drawing Speed Problem  (Read 2730 times)

0 Members and 1 Guest are viewing this topic.

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Shape Drawing Speed Problem
« on: June 10, 2013, 03:42:24 pm »
Hi everyone,

I'll make it short: using SFML, I draw 'pixels' on my window. Something like 250x150 as the resolution.
(For the moment I can't draw rectangle, I really want a "pixel map" of my window)

I have a "quite simple" process which choose to draw each pixel or not. I put a counter which would draw me a text to know which are the FPS of my App.

I've put a 60 fps limit on the window. My App runs at 14 fps.

When only commenting the line which draws Pixels (something like App->draw(pixelTab[ i ][ j ]) ) I get 60 fps.

At first I was modifying a rectangle shape each time i wanted to draw it, but as you can see here i create them all at beginning of the program so I can be faster when I want to draw (and by doing it, I went from 13 to 14 fps xD. I feel so useful)

Question: Is there a way I can be faster than that? (Without changing the computer...)
Something about hardware acceleration or I don't know? I'm not feeling like it's a real difficult task here...

Even if the app was running at 60fps without the App->draw something, do you think it's my process fault for being to greedy?

Or am I using the wrong class? (each pixel is a rectangleshape)

Thanks for help/advice guys =).

Have a nice day.
« Last Edit: June 10, 2013, 03:46:17 pm by Cherryblue »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Shape Drawing Speed Problem
« Reply #1 on: June 10, 2013, 03:49:21 pm »
Have you tried setting the pixels of an sf::Image (but not using setPixels(), that is slow) and uploading the data every frame to a texture, which is then drawn by a sprite?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #2 on: June 10, 2013, 04:39:19 pm »
Okay, I understand the idea but if I shouldn't use setPixel for an sf::Image what should I use?

Dude, are you something like a god? ^^ I don't know how to thank you!

Just tried (using setPixel since I don't know any other way around) and I got my 60fps.

Why is "filling sf::Image into sf::Texture into sf::Sprite and display it" faster than "display each pixel"? Just for my own curiosity :p.

Something else: why is there no constructor for loading directly something in a texture? (Just so I can remove 1 line in my program xD)

(Btw i'm using SFML 2.0)

Again, thanks for your quick help!

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Shape Drawing Speed Problem
« Reply #3 on: June 10, 2013, 04:46:19 pm »
Okay, I understand the idea but if I shouldn't use setPixel for an sf::Image what should I use?
I think it's update(), but check out the documentation.

Why is "filling sf::Image into sf::Texture into sf::Sprite and display it" faster than "display each pixel"? Just for my own curiosity :p.
Because you have one draw call and not thousands. Issuing a function call to the graphics card can be expensive, especially when doing so all the time.

Something else: why is there no constructor for loading directly something in a texture?
Because loading may fail.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Shape Drawing Speed Problem
« Reply #4 on: June 10, 2013, 04:48:21 pm »
Quote
Okay, I understand the idea but if I shouldn't use setPixel for an sf::Image what should I use?
Not an sf::Image at all, just a raw array of sf::Uint8.

std::vector<sf::Uint8> pixels(width * height * 4); // x4 because a pixel has 4 components (RGBA)

// writing pixel (x, y):
pixels[x + width * height + 0] = color.r;
pixels[x + width * height + 1] = color.g;
pixels[x + width * height + 2] = color.b;
pixels[x + width * height + 3] = color.a;

// --> if you overwrite the whole pixel buffer it's easier, you don't have to compute the index, just iterate sequentially

// updating the texture:
texture.update(pixels);

Quote
Why is "filling sf::Image into sf::Texture into sf::Sprite and display it" faster than "display each pixel"? Just for my own curiosity :p.
Draw each pixels like you did, was in fact drawing a huge amount of small entities. So, compared to drawing a single sprite + updating a texture, it's much faster.
Laurent Gomila - SFML developer

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #5 on: June 10, 2013, 05:02:10 pm »
Really interesting, thank you guys!

Problem (quickly) solved  :)

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #6 on: June 13, 2013, 08:54:16 am »
Hi, me again.

Using the Image/texture/sprite idea from Nexus was great, but I still need to be faster and thus wanted to try what you proposed Laurent.

But I'm not succeeding  ;D

Tell me, you use std::vector but; I already know the constant size of it, so why not just declare it like:
"uint8_t pixels[NbPixelX*NbPixelY*4];"? (And btw, is there any difference between sf::uint8 and uint8_t?)
Anyway, I tried both (used yours in static since I can't pass by constructor immediatly in a class..) and I get a really awful result.

When I want to draw a pixel, I use this:
Code: [Select]
void view::drawPixel(uint8_t i, uint8_t j){
    //scrImg.setPixel(i,j,sf::Color::Black);
    int tmp = j*NbPixelX+i;
    pixels[tmp]   = sf::Color::Black.r;
    pixels[tmp+1] = sf::Color::Black.g;
    pixels[tmp+2] = sf::Color::Black.b;
    pixels[tmp+3] = sf::Color::Black.a;
}
(Later I use sf::texture.update() like you proposed)

I can fill the texture with white with a simple loop, but when it comes to draw one pixel with the function above, I got some "random" colors. Therefore I assume I'm not at the right adress of pixels[] ?
Where am I wrong?

Thanks for any help in advance  :)
« Last Edit: June 13, 2013, 09:24:02 am by Cherryblue »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Shape Drawing Speed Problem
« Reply #7 on: June 13, 2013, 09:29:28 am »
Quote
why not just declare it like:
"uint8_t pixels[NbPixelX*NbPixelY*4];"?
Because it would be declared on the stack, and the stack is not that big (--> stack overflow). If you declare it as a global variable it would work, though. But NbPixelX/Y would have to be constants.

Quote
(And btw, is there any difference between sf::uint8 and uint8_t?)
No, both are 8 bits unsigned integers. There's one from SFML and one from the C++11 standard library.

Quote
I can fill the texture with white with a simple loop, but when it comes to draw one pixel with the function above, I got some "random" colors. Therefore I assume I'm not at the right adress of pixels[] ?
Where am I wrong?
Yep, you must multiply the index by 4. Sorry it's my fault, my example was wrong.
Laurent Gomila - SFML developer

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #8 on: June 13, 2013, 09:52:42 am »
In my case NbPixelX & Y are constants all along, so that's okay  :).

No it's fine even if your example was wrong, you did help me there and I'm not sure I'd have seen this without you. So really, thanks.

That said, I use your library since some time already, and i'm interested in improving my skills with it.

Here you taught me how to improve performance for pixels. Is it possible to do similar things for sprites/shapes?
Let's say I've got my game with elements, background and characters.

Is it faster to copy them into a sf::renderTexture and then draw it? Or any other way?

http://hpics.li/fb2e870
Here you can see my pixel map, and on the sides I draw rectangle shapes; each are independant. Is there a way to draw them faster by putting them altogether? Fact is i'm aiming for 50 or 60 FPS, I have 3 modes allowing me to do some work more or less heavy. First advice on this topic allowed me to do the easiest work from 13fps to 230. So i'm already pretty happy. If you tell me I cannot be faster than that on this one (which is the heaviest process) I'll go back look at the process instead of improving my SFML drawings.
« Last Edit: June 13, 2013, 09:54:35 am by Cherryblue »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Shape Drawing Speed Problem
« Reply #9 on: June 13, 2013, 01:12:14 pm »
Static entites that share the same texture (or none) can be grouped into a single vertex arrays, and can be drawn in a single call. Have a look at the corresponding tutorial to know more about it.
Laurent Gomila - SFML developer

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #10 on: June 14, 2013, 08:26:55 am »
Hello Laurent,

I tried to do as written in your tutorial in order to draw pretty much everything in my app, and here is the result:
http://hpics.li/19269be

This is exactly what I had so I'm pretty happy with it; but I don't see any performance overhaul; I feel like it's the contrary. I'm forced to setFramerateLimit to 120 in order for my app to work at 60fps. (Which wasn't the case before; when i was limitting it at 60, it would run at 60..)

Before, to do the exact same thing, I was drawing each square independantly thanks to a rectangle shape. And each line was drawn one by one.

Now I have two arrays, one VertexArray of Quads which contains all quads on the image, and one std::vector<sf::Vertex> which contains each line (because the number of line isn't constant, i clear it and fill it each loop).

So I only draw twice in the loop. Yet it seems like the performance dropped...  :(

No Idea?
« Last Edit: June 14, 2013, 08:30:44 am by Cherryblue »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Shape Drawing Speed Problem
« Reply #11 on: June 14, 2013, 08:39:35 am »
I'd say that you do something wrong, but without seeing your code, it's hard to tell ;)
Laurent Gomila - SFML developer

Cherryblue

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Shape Drawing Speed Problem
« Reply #12 on: June 14, 2013, 09:22:01 am »
Here is the main code (would be too long to show you everything):
Code: [Select]
    // Check if state changed
    if(Periph->state_changed){
        Periph->state_changed = false;
        geometry::initialization(Periph->state);
    }

    // First Drawing Call
    geometry::drawContext(App);

    // Depending on View Type
    switch(Periph->state){
        case VIEW_EMPTY:
            geometry::drawTitle(App);
            break;
        case VIEW_FULLSCREEN_LIGHT:
        case VIEW_LIGHT:
            for(uint8_t i=0;i<NbEm;i++)             // For each diode of the Bezel
                for(uint8_t j=0;j<NbPd;j++)         // For each group of 8 OPD ( 8 OPD per Bezel Module )
                    if( (Device->USBData.projection[diodeX3::whichCycle[i]][j/8]&obstacle::NumberToPd[j%8]) != 0 && pdRange::areLinked(i,j) ) geometry::addLine(i,j);
            geometry::drawLine(App);
            break;
        case VIEW_FULLSCREEN_OBSTACLE:
        case VIEW_OBSTACLE:
            for(uint8_t i=0;i<NbEm;i++)             // For each diode of the Bezel
                for(uint8_t j=0;j<NbPd;j++)         // For each OPD ( 8 OPD per Bezel Module )
                    if( (Device->USBData.projection[diodeX3::whichCycle[i]][j/8]&obstacle::NumberToPd[j%8]) == 0 && pdRange::areLinked(i,j) ) geometry::addLine(i,j);
            geometry::drawLine(App);
            break;
        case VIEW_FULLSCREEN_PROCESS:
        case VIEW_PROCESS:
            geometry::clearPixels();
            processPixels(PROCESS_MODE_AVERAGE);
            geometry::drawPixels(App);
            break;
        default:
            break;
    }

    // Refresh Screen
    App->display();

As you can see, every thing about drawing is in a class used in static called geometry.
Here is the code for add and draw:
Code: [Select]
void geometry::addBezel(){
    // Filling Screen first (order in which it's filled is really important, else it does not work properly)
    ArrayQuad[4].position = sf::Vector2f(ScreenRef.x, ScreenRef.y);
    ArrayQuad[5].position = sf::Vector2f(ScreenRef.x+ScreenSize.x, ScreenRef.y);
    ArrayQuad[6].position = sf::Vector2f(ScreenRef.x+ScreenSize.x, ScreenRef.y+ScreenSize.y);
    ArrayQuad[7].position = sf::Vector2f(ScreenRef.x, ScreenRef.y+ScreenSize.y);
    for(uint8_t i=0;i<4;i++) ArrayQuad[i].color = sf::Color::White;

    // Filling Bezel second
    ArrayQuad[0].position = BezelRef;
    ArrayQuad[1].position = sf::Vector2f(BezelRef.x+BezelSize.x,BezelRef.y);
    ArrayQuad[2].position = sf::Vector2f(BezelRef.x+BezelSize.x,BezelRef.y+BezelSize.y);
    ArrayQuad[3].position = sf::Vector2f(BezelRef.x,BezelRef.y+BezelSize.y);
    for(uint8_t i=0;i<4;i++) ArrayQuad[i].color = sf::Color(230,216,174);
}

void geometry::addEm(){
    // Processing Positions
    initEm();
    // Filling each emitters
    for(uint8_t i=0;i<66;i++){
        ArrayQuad[(2+i)*4].position = sf::Vector2f(TabEm[i].x-SIZE_EmX/2,TabEm[i].y-SIZE_EmY/2);
        ArrayQuad[(2+i)*4+1].position = sf::Vector2f(TabEm[i].x+SIZE_EmX/2,TabEm[i].y-SIZE_EmY/2);
        ArrayQuad[(2+i)*4+2].position = sf::Vector2f(TabEm[i].x+SIZE_EmX/2,TabEm[i].y+SIZE_EmY/2);
        ArrayQuad[(2+i)*4+3].position = sf::Vector2f(TabEm[i].x-SIZE_EmX/2,TabEm[i].y+SIZE_EmY/2);
        for(uint8_t j=0;j<4;j++) ArrayQuad[(2+i)*4+j].color = sf::Color::Red;
    }
}

void geometry::addRcv(){
    // Processing Positions
    initRcv();
    // Filling each recivers
    for(uint8_t i=0;i<176;i++){
        ArrayQuad[(2+66+i)*4].position = sf::Vector2f(TabPd[i].x-SIZE_PdX/2,TabPd[i].y-SIZE_PdY/2);
        ArrayQuad[(2+66+i)*4+1].position = sf::Vector2f(TabPd[i].x+SIZE_PdX/2,TabPd[i].y-SIZE_PdY/2);
        ArrayQuad[(2+66+i)*4+2].position = sf::Vector2f(TabPd[i].x+SIZE_PdX/2,TabPd[i].y+SIZE_PdY/2);
        ArrayQuad[(2+66+i)*4+3].position = sf::Vector2f(TabPd[i].x-SIZE_PdX/2,TabPd[i].y+SIZE_PdY/2);
        for(uint8_t j=0;j<4;j++) ArrayQuad[(2+66+i)*4+j].color = sf::Color::Blue;
    }
}

void geometry::initialization(uint8_t state){
    initConstants(state);
    addBezel();
    addEm();
    addRcv();
}

// Draw Bezel, Screen, Emitters and Receivers
void geometry::drawContext(sf::RenderWindow *App){ App->draw(ArrayQuad); }

// Draw a "Welcome" Text on default view
void geometry::drawTitle(sf::RenderWindow *App){ App->draw(Title); }

// Add a line to draw in the array of Line
void geometry::addLine(uint8_t Em, uint8_t Pd){
    ArrayLine.push_back(sf::Vertex(TabEm[Em],sf::Color::Blue));
    ArrayLine.push_back(sf::Vertex(TabPd[Pd],sf::Color::Blue));
}

// Draw every line in the array
void geometry::drawLine(sf::RenderWindow *App){ App->draw(&ArrayLine[0], ArrayLine.size(), sf::Lines); ArrayLine.clear(); }

All above "initialization" is used only when initialization is called (so not at each loop cycle)

Let's say my view is the one i showed you last: then it's VIEW_OBSTACLE.
Meaning only things called are drawContext(App); addLine(i,j); and drawLines(App);

I insist on the fact that only geometry has been modified since I posted here; so my loss in performance can only be there.
Is the bottleneck the fact I clear & fill std::vector each loop? Should I use another structure?
« Last Edit: June 14, 2013, 09:26:57 am by Cherryblue »

 

anything