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

Author Topic: Max blend mode/rendering optimization  (Read 4008 times)

0 Members and 1 Guest are viewing this topic.

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Max blend mode/rendering optimization
« on: November 13, 2012, 07:08:11 pm »
Hello :) I have a few questions.

Is it possible to achieve blend mode that outputs maximum of 2 colors for each color channel?
I've found this topic: http://stackoverflow.com/questions/2143690/is-it-possible-to-achieve-maxas-ad-opengl-blending however this solution doesn't seem to work.

The second question is: is it worth it to use texture atlas? If so, wouldn't it be a nice idea to implement such feature in SFML itself? I mean, when you load a texture you could have possibility to put it in 1 global texture atlas so there wouldn't be unnecessary calls for openGL to change current texture when you draw different sprites.

And the final question: is drawing a tile map using VertexArray more benefitial than drawing every sprite using draw calls individually? If so, then putting everything which has to be rendered to VertexArray and then using 1 draw call is the best solution right? Why do people use draw calls on each sprite rather than make 1 huge VertexArray?

Are there any other useful tricks to optimize rendering? I've noticed that changing current target buffer is very expensive. For example it's better to render all textures to the first FBO and then the others to the second FBO rather than mix these calls.

Thanks in advance

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Max blend mode/rendering optimization
« Reply #1 on: November 14, 2012, 08:02:21 am »
Quote
Is it possible to achieve blend mode that outputs maximum of 2 colors for each color channel?
No.

Quote
The second question is: is it worth it to use texture atlas?
Yes.

Quote
If so, wouldn't it be a nice idea to implement such feature in SFML itself? I mean, when you load a texture you could have possibility to put it in 1 global texture atlas so there wouldn't be unnecessary calls for openGL to change current texture when you draw different sprites.
You'd better combine your images into a single one outside your program, with your preferred image editor.
You can also create a texture atlas easily with SFML (see sf::Image, sf::Image::copy and sf::Texture::loadFromImage).

Quote
And the final question: is drawing a tile map using VertexArray more benefitial than drawing every sprite using draw calls individually?
Of course it is.

Quote
If so, then putting everything which has to be rendered to VertexArray and then using 1 draw call is the best solution right?
It depends on how many vertices you have. If there are a lot (like more than 100000) then you can split the entity into multiple big chunks (1 chunk = 1 vertex array), which allows you to discard chunks that are not visible.

Quote
Why do people use draw calls on each sprite rather than make 1 huge VertexArray?
Because:
- it's new, it didn't exist in SFML 1.6 and old 2.0
- there's no tutorial for it yet
- they don't know how to use it

Quote
Are there any other useful tricks to optimize rendering?
As long as you keep the amount of draw calls low, performances should be ok.

Quote
I've noticed that changing current target buffer is very expensive. For example it's better to render all textures to the first FBO and then the others to the second FBO rather than mix these calls
Yep.
Laurent Gomila - SFML developer

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #2 on: November 14, 2012, 09:56:29 pm »
Thanks for answers.

Performance increase isn't as big as I expected.
100000 sprites per frame. 3 different textures.
Normal rendering: ~1500 ms / frame
Texture atlas: ~1485 ms / frame
VertexArray with texture atlas: ~1470 ms / frame

so actually it's not worth an effort.

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Max blend mode/rendering optimization
« Reply #3 on: November 14, 2012, 10:01:32 pm »
Maybe your hardware is just too good? You get 666 frames with normal rendering, that's crazy for that amount of sprites with few textures.
Back to C++ gamedev with SFML in May 2023

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #4 on: November 14, 2012, 10:13:07 pm »
666 frames? 1 frame renders 1.5 sec, which means I have 0.666 frame/second

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Max blend mode/rendering optimization
« Reply #5 on: November 14, 2012, 10:17:12 pm »
Thought they were microseconds. Try doing something more normal maybe ie. 100 or 1000, I doubt someone sane will try to render 100 000 sprites per frame.
Back to C++ gamedev with SFML in May 2023

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Max blend mode/rendering optimization
« Reply #6 on: November 14, 2012, 10:40:10 pm »
You should post the code that you used to do your tests.

You should also tell us what OS / graphics card / drivers you have.
Laurent Gomila - SFML developer

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #7 on: November 15, 2012, 12:10:35 pm »
Here's the code:

#include <SFML/Graphics.hpp>
#include <cstdio>

#define QUANTITY (100000)

int main()
{
    sf::RenderWindow window;
    window.create(sf::VideoMode(1024, 768, 32), "test", sf::Style::Default);

    int type;
    printf("0 - normal\n");
    printf("1 - atlas\n");
    printf("2 - VA\n");
    scanf("%d", &type);

    sf::Clock _clock;

    if(type == 0) {
        sf::Texture tex[3];
        sf::Sprite spr[3];

        tex[0].loadFromFile("test1.png");
        tex[1].loadFromFile("test2.png");
        tex[2].loadFromFile("test3.png");

        spr[0].setTexture(tex[0]);
        spr[1].setTexture(tex[1]);
        spr[2].setTexture(tex[2]);

        sf::Time prevTime;
        while(1) {
            sf::Time time = _clock.getElapsedTime();
            printf("normal time: %.2lf ms\n", (time.asMicroseconds()-prevTime.asMicroseconds())/1000.0);
            prevTime = time;

            for(int i=0; i<QUANTITY; ++i) {
                int x = rand()%1024;
                int y = rand()%768;
                spr[i%3].setPosition(x, y);
                window.draw(spr[i%3]);
            }

            window.display();
            window.clear();
        }
    }
    else if(type == 1) {
        sf::Texture tex;
        sf::Sprite spr[3];

        tex.loadFromFile("atlas.png");

        spr[0].setTexture(tex);
        spr[0].setTextureRect(sf::IntRect(0, 0, 100, 100));
        spr[1].setTexture(tex);
        spr[1].setTextureRect(sf::IntRect(100, 0, 100, 100));
        spr[2].setTexture(tex);
        spr[2].setTextureRect(sf::IntRect(200, 0, 100, 100));

        sf::Time prevTime;
        while(1) {
            sf::Time time = _clock.getElapsedTime();
            printf("atlas time: %.2lf ms\n", (time.asMicroseconds()-prevTime.asMicroseconds())/1000.0);
            prevTime = time;

            for(int i=0; i<QUANTITY; ++i) {
                int x = rand()%1024;
                int y = rand()%768;
                spr[i%3].setPosition(x, y);
                window.draw(spr[i%3]);
            }

            window.display();
            window.clear();
        }
    }
    else {
        sf::Texture tex;
        sf::Sprite spr[3];

        tex.loadFromFile("atlas.png");

        spr[0].setTexture(tex);
        spr[1].setTexture(tex);
        spr[2].setTexture(tex);

        sf::Time prevTime;
        while(1) {
            sf::Time time = _clock.getElapsedTime();
            printf("VA time: %.2lf ms\n", (time.asMicroseconds()-prevTime.asMicroseconds())/1000.0);
            prevTime = time;

            sf::VertexArray VA(sf::Quads, QUANTITY*4);
            for(int i=0; i<QUANTITY; ++i) {
                int x = rand()%1024;
                int y = rand()%768;
                int w = 100;
                int h = 100;

                VA[i*4].position = sf::Vector2f(x, y);
                VA[i*4+1].position = sf::Vector2f(x+w, y);
                VA[i*4+2].position = sf::Vector2f(x+w, y+h);
                VA[i*4+3].position = sf::Vector2f(x, y+h);

                VA[i*4].texCoords = sf::Vector2f((i%3)*w, 0);
                VA[i*4+1].texCoords = sf::Vector2f((i%3)*w+w, 0);
                VA[i*4+2].texCoords = sf::Vector2f((i%3)*w+w, h);
                VA[i*4+3].texCoords = sf::Vector2f((i%3)*w, h);
            }
            window.draw(VA, &tex);

            window.display();
            window.clear();
        }
    }
}
 
(yep, textures dimensions are hardcoded)

and textures used:
test1.png
test2.png
test3.png
atlas.png

with these textures i have ~725 ms for normal rendering and ~710 ms for VA
nvidia geforce 9600M GT, windows 7 32 bit
« Last Edit: November 15, 2012, 12:13:17 pm by ison »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Max blend mode/rendering optimization
« Reply #8 on: November 15, 2012, 12:17:42 pm »
Two things:

1. Don't create your vertex array at every iteration; if the contents are dynamic then at least construct the sf::VertexArray instance (i.e. allocate the memory) before entering the main loop

2. Are you sure that the calls to rand() are not slowing down the tests significantly? Can you run the same tests with static contents (i.e. only call the draw function in the main loop)?
Laurent Gomila - SFML developer

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #9 on: November 15, 2012, 12:33:59 pm »
1. Didn't help even if I put everything related to filling VA outside loop. I guess that GPU is bottleneck here so filling VA on CPU doesn't really matter.
2. Every test calls equal amount of rand().
rand() calls take 3 ms per frame.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Max blend mode/rendering optimization
« Reply #10 on: November 15, 2012, 01:13:47 pm »
Quote
2. Every test calls equal amount of rand().
But if rand() takes 10x more time that everything else, then there will only be slight differences between tests (and that's what you get). And we also try to understand why rendering is so slow on your machine.
So it is important.

By the way, are your graphics drivers up-to-date?

Quote
rand() calls take 3 ms per frame.
How do you know that?
« Last Edit: November 15, 2012, 01:32:43 pm by Laurent »
Laurent Gomila - SFML developer

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #11 on: November 15, 2012, 01:27:33 pm »
I don't know if my graphics card drivers are up to date but I think that automatic windows update handles this. I'll check.

while(1) {
            sf::Time time = _clock.getElapsedTime();
            printf("rand time: %.2lf ms\n", (time.asMicroseconds()-prevTime.asMicroseconds())/1000.0);
            prevTime = time;

            for(int i=0; i<QUANTITY; ++i) {
                int x = rand()%1024;
                int y = rand()%768;
                if(x == 0 && y == 0) {
                      putchar('.');
                }
            }
        }
 
The x == 0 thing prevents compiler from optimizing it and not calling rand().

ison

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Max blend mode/rendering optimization
« Reply #12 on: November 16, 2012, 10:09:32 pm »
Even if performance increase is low I decided to rewrite whole project using VAs ;) However I encountered an annoying problem. It seems that texture smoothing doesn't like texture atlases - because sometimes when drawing tile map, black lines appear between tiles. I have 2 pix space between textures in texture atlas, I tried to fill this space with sf::Color::Transparent but smoothing still blends border colors with black color. Is there any solution for this?

//edit
ok, problem solved
I had to fill space between textures in texture atlas with the nearest color to avoid texture bleeding
« Last Edit: November 17, 2012, 03:25:59 pm by ison »