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

Author Topic: [SOLVED] How to do (composed) transparency? shaders?  (Read 10056 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: How to do transparency? shaders?
« Reply #15 on: December 02, 2012, 10:37:48 pm »
When you were drawing to a render-target (RenderTexture or RenderWindow) and then draw to another one, internally SFML has to change the active OpenGL context (there's one for each target). Changing the current context means to reset all the OpenGL states, flush the rendering pipeline, etc. This is extremely expensive.

I can't imagine why you'd need more than 1000 context switches every frame, but this is definitely not a good way to go.
Laurent Gomila - SFML developer

danikaze

  • Newbie
  • *
  • Posts: 38
    • View Profile
    • Email
Re: How to do transparency? shaders?
« Reply #16 on: December 03, 2012, 12:04:18 am »
I was just "stressing" the system to see the different performance ;)
Obviously I hope I won't need to draw 1000 times every frame, but I think I will need to do this several times per frames (drawing sprites composed by several images and applying transparency or other effects to the whole thing as I described in the example of the 1st message).

Nice to know how and why happens this ;)
Thanks Laurent for everything. Keep going!

danikaze

  • Newbie
  • *
  • Posts: 38
    • View Profile
    • Email
Re: How to do transparency? shaders?
« Reply #17 on: December 03, 2012, 12:42:37 am »
Just another test to see about the switching target.. I removed the

window.draw(sf::Sprite(screenBuffer.getTexture()));

line so there's only screenBuffer.draw calls (therefore, shouldn't switch the active OpenGL context, right?), but the performance is still much slower than drawing directly to the screen.

Am I using RenderTextures in the proper way?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: How to do transparency? shaders?
« Reply #18 on: December 03, 2012, 08:08:39 am »
Quote
Am I using RenderTextures in the proper way?
Yes. It's hard to say what's wrong, could you write a complete and minimal code that reproduces the problem, so that we can test it?
Laurent Gomila - SFML developer

danikaze

  • Newbie
  • *
  • Posts: 38
    • View Profile
    • Email
Re: How to do transparency? shaders?
« Reply #19 on: December 04, 2012, 02:22:55 am »
Quote
Am I using RenderTextures in the proper way?
Yes. It's hard to say what's wrong, could you write a complete and minimal code that reproduces the problem, so that we can test it?
Here's a beautiful code to test.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>

using namespace std;

int main()
{
        // define and init stuff
        int iterations = 10000;

        sf::RenderWindow window(sf::VideoMode(640, 480), "RenderWindow vs RenderTexture performance test");

        sf::Texture texture;
        texture.loadFromFile("img/hotel2.png");

        sf::Sprite sprite(texture);

        sf::RenderTexture screenBuffer;
        screenBuffer.create(window.getSize().x, window.getSize().y);

        sf::Clock clock;
        sf::Event event;
        sf::CircleShape shape(100.f);

        int time1, time2;

        // drawing directly to the RenderWindow
        cout << "RenderWindow.draw x " << iterations << " = ";
        clock.restart();
        for(int i=0; i<iterations; ++i)
        {
                window.clear();
                sprite.setColor(sf::Color(255, 255, 255, 100));
                sprite.setPosition(20, 10);
                window.draw(sprite);
                sprite.setPosition(60, 10);
                window.draw(sprite);
                window.display();
        }
        time1 = clock.getElapsedTime().asMilliseconds();
        cout << time1 << " ms." << endl;

        // drawing to the RenderTexture
        cout << "RenderTexture.draw x " << iterations << " = ";
        clock.restart();
        for(int i=0; i<iterations; ++i)
        {
                screenBuffer.clear();
                sprite.setColor(sf::Color(255, 255, 255, 255));
                sprite.setPosition(20, 10);
                screenBuffer.draw(sprite);
                sprite.setPosition(60, 10);
                screenBuffer.draw(sprite);
                screenBuffer.display();

                sf::Sprite sp(screenBuffer.getTexture());
                sp.setColor(sf::Color(255, 255, 255, 100));

                window.clear();
                window.draw(sp);
                window.display();
        }
        time2 = clock.getElapsedTime().asMilliseconds();
        cout << time2 << " ms." << endl;

        // display results
        if(time1 < time2)
        {
                cout << endl << "RenderWindow is " << time2/static_cast<double>(time1) << " times faster than RenderTexture." << endl;
        }
        else
        {
                cout << endl << "RenderWindow is " << time1/static_cast<double>(time2) << " times slower than RenderTexture." << endl;
        }

        // wait for key pressed and close screen
        cout << endl << "Push any key to exit..." << endl;
        while(window.isOpen())
        {
                while (window.pollEvent(event))
                {
                        if(event.type == sf::Event::KeyPressed || event.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                }
        }

        return 0;
}
 

BUT! If you comment the 62nd line (window.display(); after window.draw(sp);), that is, the 2nd display in the 2nd test, the times are equals.

So, in this new test everything seems right, I don't know why in the old code was 15 times slower... maybe because of using and drawing shapes? :-/

At least, the effect of transparency works fine :D

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: How to do transparency? shaders?
« Reply #20 on: December 04, 2012, 08:20:54 am »
Quote
So, in this new test everything seems right, I don't know why in the old code was 15 times slower...
Everything is right only without the call to display(), or even with it? If it's slower with it, is it approximately as slow as in your app (x15)?

What's your graphics card? Are your drivers up-to-date?
Laurent Gomila - SFML developer

danikaze

  • Newbie
  • *
  • Posts: 38
    • View Profile
    • Email
Re: How to do transparency? shaders?
« Reply #21 on: December 04, 2012, 04:16:09 pm »
Quote
So, in this new test everything seems right, I don't know why in the old code was 15 times slower...
Everything is right only without the call to display(), or even with it? If it's slower with it, is it approximately as slow as in your app (x15)?

What's your graphics card? Are your drivers up-to-date?

This is the output of the test program:
Code: [Select]
RenderWindow.draw x 10000 = 1720 ms.
RenderTexture.draw x 10000 = 3591 ms.

RenderWindow is 2.08779 times faster than RenderTexture.

Press any key to exit...

Which is totally legit, because in the RenderTexture part we need to call twice to .display() (one for the RenderTexture and one for the RenderWindow), while in the RenderWindow part we only need to call it once.

My graphic card is a nVidia GTX 460 with updated drivers
sf::ContextSettings context = window.getSettings();
cout << "Currently using OpenGL: " << context.majorVersion << "." << context.minorVersion << endl;
 
displays Currently using OpenGL: 4.2

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: How to do transparency? shaders?
« Reply #22 on: December 04, 2012, 04:25:12 pm »
Quote
Which is totally legit, because in the RenderTexture part we need to call twice to .display() (one for the RenderTexture and one for the RenderWindow), while in the RenderWindow part we only need to call it once.
Hmm yeah, you should probably test the exact same code for each type of target.
Laurent Gomila - SFML developer

danikaze

  • Newbie
  • *
  • Posts: 38
    • View Profile
    • Email
Re: How to do transparency? shaders?
« Reply #23 on: December 04, 2012, 06:49:44 pm »
So, the thing that consumes time is actually the display :)

By the way, regarding to the original question of this post, I'll mark as solved this post and write here the solution to my problem:

// prepare everything:
sf::Texture texture1, texture2;
texture1.loadFromFile("img1.png");
texture2.loadFromFile("img2.png");

sf::Sprite sprite1(texture1);
sf::Sprite sprite2(texture2);

sf::RenderTexture buffer;
buffer.create(w, h);

// draw things with 255 alpha into RenderTexture
buffer.draw(sprite1);
buffer.draw(sprite2);
// and then, draw the buffer with the desired alpha into the screen
sf::Sprite bufferSp(buffer.getTexture());
bufferSp.setColor(sf::Color(255, 255, 255, alpha));
window.draw(buffer);
window.display();