SFML community forums

Help => Graphics => Topic started by: Groogy on January 29, 2012, 04:41:38 am

Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 04:41:38 am
I am pretty sure we discussed this somewhere but I couldn't find it when searching for it.

Well anyway the resulting texture from a RenderTexture is flipped in the Y-coordinate. Right and I thought I could just do a flip of the sprite that I worked with.... but that functionality is long gone so how do I solve it? xD
Negative scaling is still not available right?
Title: Flipped RenderTexture
Post by: pdinklag on January 29, 2012, 04:51:15 am
You need to call Display() before actually using it, I had the same problem before. ;)
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 05:10:16 am
I am calling display on it before using it. Though I am rendering on it from a different thread. But you are only allowed access to the texture when the thread is done so display has been called.

I'll see if I can narrow it down a little more.

UPDATE: Happens with the most simple test case as well.

UPDATE: Damn lol I jsut noticed that I forgot to call display and if I do it works xD But still doesn't explain why it doesn't work in my threaded example.. I'll see if I did some stupid mistake instead.

Hmmm this is weird.. Magically it works... I did not change the code in any way.. just did a rebuild of the entire project and that solved it for me.... Darn it...
Title: Flipped RenderTexture
Post by: Laurent on January 29, 2012, 09:19:03 am
Quote
Negative scaling is still not available right?

It is.
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 07:00:37 pm
Actually I saw a very weird behaviour. If I don't call "Display" in the main thread I get the texture flipped actually. But if I do then everything works just like it is expected.

Is this a bug I should write in the issue tracker?
Title: Flipped RenderTexture
Post by: Laurent on January 29, 2012, 07:11:00 pm
Quote
Is this a bug I should write in the issue tracker?

You should first show me a minimal code that reproduces this problem.
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 07:36:42 pm
Code: [Select]
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

struct Synchronizer
{
    sf::RenderTexture* texture;
    bool isAllowedToRun;
    bool isWorking;
    bool isAllowedToStart;
};

void ThreadedRender( Synchronizer* aSynchronizer )
{
    aSynchronizer->texture->SetActive( true );
    sf::Text text( "Hello World!" );
    while( aSynchronizer->isAllowedToRun == true )
    {
        if( aSynchronizer->isAllowedToStart == true )
        {
            aSynchronizer->isWorking = true;
            aSynchronizer->isAllowedToStart = false;

            aSynchronizer->texture->Clear( sf::Color::Red );
            aSynchronizer->texture->Draw( text );
            aSynchronizer->texture->Display();

            aSynchronizer->isWorking = false;
        }
    }
    aSynchronizer->texture->SetActive( false );
}

void WaitForSynch( Synchronizer* aSynchronizer )
{
    while( aSynchronizer->isWorking == true || aSynchronizer->isAllowedToStart == true )
    {
        sf::Sleep( sf::Milliseconds( 1 ) );
    }
}

void CompleteSynch( Synchronizer* aSynchronzier )
{
    aSynchronzier->isAllowedToStart = true;
}

void ExitSynch( Synchronizer* aSynchronizer )
{
    aSynchronizer->isAllowedToRun = false;
}

int main()
{
    sf::ContextSettings settings;
    settings.MajorVersion = 3;
    settings.MinorVersion = 0;

    sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Renderer", sf::Style::Default, settings );
    sf::RenderTexture scene;
    scene.Create( 800, 600, true );
    //scene.Display();   /
    scene.SetActive( false );

    Synchronizer *synchronizer = new Synchronizer();
    synchronizer->texture = &scene;
    synchronizer->isAllowedToRun = true;
    synchronizer->isAllowedToStart = false;
    synchronizer->isWorking = false;

    sf::Thread renderer( ThreadedRender, synchronizer );
    renderer.Launch();

    while( window.IsOpen() == true )
    {
        WaitForSynch( synchronizer );
        sf::Sprite sprite( scene.GetTexture() );
        window.Draw( sprite );
        window.Display();
        CompleteSynch( synchronizer );
       
        sf::Event event;
        while( window.PollEvent( event ) == true )
        {
            if( event.Type == sf::Event::Closed )
            {
                    window.Close();
                    break;
            }
        }
    }
    ExitSynch( synchronizer );
    return 0;
}


Quick question, what happens if I give microseconds to sleep? It will still conform to 1 millisecond since that's the lowest resolution the OS gives right? You should really give us a sf::Yield function ^^
Title: Flipped RenderTexture
Post by: Laurent on January 29, 2012, 07:44:00 pm
Quote
Quick question, what happens if I give microseconds to sleep? It will still conform to 1 millisecond since that's the lowest resolution the OS gives right?

Linux can use microseconds (at least the API allows it), on Windows it's milliseconds.

Quote
You should really give us a sf::Yield function

sf::Sleep(0) is usually enough. What you need here is a more powerful synchronization primitive (a wait condition).

I'll test your code as soon as I can.
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 07:58:02 pm
Quote from: "Laurent"
sf::Sleep(0) is usually enough. What you need here is a more powerful synchronization primitive (a wait condition).
Actually giving sf::Sleep(0) can break on the windows platform under special scenarios and give deadlocks or thread starvation problems. So no it's not acceptable. I've faced it several times and I have in some cases even gotten performance boost by increasing the sleep time to 1 millisecond. I've seen the behaviour on XP, Vista and 7.
Some of the problems are even described on MSDN.

What kind of synchronization primitive are you talking about? I just simplified my renderer and I only want it to return the texture when a frame is done. Do you have a better idea than what I currently have? If that's the case then I certainly want to hear it. The basic idea I have is to create several renderers at the same time. For Deferred rendering I can render several buffers at the same time and combine them together in the end giving me a lot of possibilities with this design ;)

Also do you have any statistics on the speed of copying a texture? I'm thinking like instead of synchronizing on the "GetTexture" function I can have that at synchronization that I copy the texture onto a texture that is always readable. Or maybe I should do this double buffered? Probably a better design.
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 10:13:40 pm
I also observed something else that doesn't seem to work with textures. I tried with copying the texture and it seem to only be able to copy the texture once. I don't know if this is a threaded problem or just something wrong in the Texture implementation but it appeared when I expanded my threaded example. I even added an output to show that both the threads is still running and updating the texture.

Code: [Select]
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <sstream>
#include <iostream>

struct Synchronizer
{
    sf::RenderTexture* texture;
    bool isAllowedToRun;
    bool isWorking;
    bool isAllowedToStart;
};

unsigned int frame = 0;
void ThreadedRender( Synchronizer* aSynchronizer )
{
    aSynchronizer->texture->SetActive( true );
    sf::Text text( "Hello World!" );
    while( aSynchronizer->isAllowedToRun == true )
    {
        if( aSynchronizer->isAllowedToStart == true )
        {
            aSynchronizer->isWorking = true;
            aSynchronizer->isAllowedToStart = false;

            aSynchronizer->texture->Clear( sf::Color::Red );
            frame++;
            std::stringstream stream;
            stream << frame;
            text.SetString( stream.str() );
            aSynchronizer->texture->Draw( text );
            aSynchronizer->texture->Display();

            aSynchronizer->isWorking = false;
        }
    }
    aSynchronizer->texture->SetActive( false );
}

void WaitForSynch( Synchronizer* aSynchronizer )
{
    while( aSynchronizer->isWorking == true || aSynchronizer->isAllowedToStart == true )
    {
        sf::Sleep( sf::Milliseconds( 1 ) );
    }
}

void CompleteSynch( Synchronizer* aSynchronzier )
{
    aSynchronzier->isAllowedToStart = true;
}

void ExitSynch( Synchronizer* aSynchronizer )
{
    aSynchronizer->isAllowedToRun = false;
}

int main()
{
    sf::ContextSettings settings;
    settings.MajorVersion = 3;
    settings.MinorVersion = 0;

    sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Renderer", sf::Style::Default, settings );
    sf::RenderTexture scene;
    scene.Create( 800, 600, true );
    scene.Display();
    scene.SetActive( false );

    Synchronizer *synchronizer = new Synchronizer();
    synchronizer->texture = &scene;
    synchronizer->isAllowedToRun = true;
    synchronizer->isAllowedToStart = false;
    synchronizer->isWorking = false;

    sf::Thread renderer( ThreadedRender, synchronizer );
    renderer.Launch();

    sf::Texture texture;

    while( window.IsOpen() == true )
    {
        WaitForSynch( synchronizer );
        texture = synchronizer->texture->GetTexture();
        sf::Sprite sprite( texture );
        window.Draw( sprite );
        window.Display();
        CompleteSynch( synchronizer );

        std::cout << frame << std::endl;

        sf::Event event;
        while( window.PollEvent( event ) == true )
        {
            if( event.Type == sf::Event::Closed )
            {
                    window.Close();
                    break;
            }
        }
    }
    ExitSynch( synchronizer );
    return 0;
}


You must be thinking right now: "DAMN THAT GROOGY DESTROYING MY CODE!" :P
Title: Flipped RenderTexture
Post by: Laurent on January 29, 2012, 10:20:19 pm
Quote
Actually giving sf::Sleep(0) can break on the windows platform under special scenarios and give deadlocks or thread starvation problems.

That's good to hear.

Quote
What kind of synchronization primitive are you talking about?

When you want a thread to block until a flag is set by another thread, you need a wait condition. A while loop with sleep is an inefficient workaround. I have no idea if it applies to your design, or if it's just your example.

Quote
Also do you have any statistics on the speed of copying a texture?

Nop. And I haven't investigated your example yet so I cannot give you my opinion now ;)

About your texture problems: one thing that I've learnt is that sometimes you need an explicit glFlush after uploading texture data if you want other threads to see the update immediately.
Title: Flipped RenderTexture
Post by: Groogy on January 29, 2012, 10:34:29 pm
Quote from: "Laurent"
That's good to hear.
Thank my teacher, he's the one that told me... I didn't believe him.. Then I spent an entire night tracking down the bug. Great spending time on that when you are to leave in the project for producer estimation 9 o'clock in the morning.

Quote from: "Laurent"
When you want a thread to block until a flag is set by another thread, you need a wait condition. A while loop with sleep is an inefficient workaround. I have no idea if it applies to your design, or if it's just your example.
Hmm well I'll get to that point when I need it. The renderer will be aimed specifically for use together with rbSFML(That's why threading here is important, trying to avoid the GIL).

Quote from: "Laurent"
About your texture problems: one thing that I've learnt is that sometimes you need an explicit glFlush after uploading texture data if you want other threads to see the update immediately.

I tried placing out some flushes but got no improvement. It still displays only the first original texture. I wasn't planning on using this design but I just wanted to compare this against using a blocking reference(how I do in the first example) and compare it also against double buffered.

Actually getting quite off-topic here. Should I create a new thread?

NOTE: Verified that it's based on the texture is rendered in a separate thread. Did the same thing with a single thread and it behaved like intended.

Fun fact: I tried out my engine with simple drawings in debug mode on my university computer.... Got 4 000+ FPS on that machine... And the CPU is not maxed out, did you complete the OpenGL call optimizations yet? In any case it's damn fast :D This computer only went for around ~800 Euro. If you haven't then I really want to know what I'll get after that commit. I should start writing out the frame/update time instead of FPS if it's at these speeds. Should look much more stable.
Title: Flipped RenderTexture
Post by: Nexus on January 30, 2012, 09:42:08 am
Just as an aside, the C++11 standard library comes with an advanced threading API. Maybe some parts of it are helpful.
Title: Flipped RenderTexture
Post by: Groogy on February 02, 2012, 12:04:33 am
Hmm there might be an entire issue with the whole OpenGL and threading with SFML2 actually.. Even glew messes out in the second thread if I don't explicitly handles the problem.

Should probably try to fix these issues after SFML 2 has been released. As there seems to be a lot of holes.

For instance here is a new problem:
Code: [Select]
void ym::OpenGL::RendererImplementation::Initialize()
{
    myTarget.SetActive( true );
    /* Code... */
}


This fails for me really. This function is called in the rendering thread and more or less prepares the render texture(myTarget) to be rendered on. Any feature that actually requires glew to be initiated fails. And still sf::Shader::IsAvailable returns true which is weird. And yes the target has been set to not be active in the main thread.

And here's some more stuff I tested, putting glewInit before SetActive dpes nothing which is of course kind of obvious. But setting glewInit afterwards actually solves this problem. I don't know if they solve all problem discussed here:
Code: [Select]
void ym::OpenGL::RendererImplementation::Initialize()
{
    glewInit() // <- Doesn't help
    myTarget.SetActive( true );
    glewInit(); // <- Does help!
    /* Code... */
}


I would say that SFML2 is not safe for parallel environments yet considering all the problems I've found but with some quick dirty fixes you can get it to work just fine so I don't see a reason to hold up SFML2 development for this.
Title: Flipped RenderTexture
Post by: Silvah on February 02, 2012, 01:33:24 pm
Quote from: "Groogy"
Actually giving sf::Sleep(0) can break on the windows platform under special scenarios and give deadlocks or thread starvation problems.
No wonder, yielding is a nice method to provoke all the Heisenbugs related to threading into revealing themselves. In working code, it's harmless. In buggy code, it helps you realizing that the bugs are there. So what's the problem?

And, uhm, the behavior of Sleep(0) is actually well-defined, so if you want something else, then you shouldn't blame Sleep(0) for that.

Quote from: "Groogy"
Some of the problems are even described on MSDN.
Any chance of getting a link?
Title: Flipped RenderTexture
Post by: Groogy on February 02, 2012, 02:24:17 pm
-> http://msdn.microsoft.com/en-us/library/windows/desktop/ms686298%28v=vs.85%29.aspx

The MSDN sleep documentation describes some of them. There are other resources on MSDN that describes more problems. Just "follow the paper
 trail" :P

One example:
Quote
Threads that are under concurrency control. For example, an I/O completion port or thread pool limits the number of associated threads that can run. If the maximum number of threads is already running, no additional associated thread can run until a running thread finishes. If a thread uses Sleep with an interval of zero to wait for one of the additional associated threads to accomplish some work, the process might deadlock.


Also the problem we had was with the actual scheduling that windows does. One thread was favored above the other ones but each of them was yielding. Our input thread for instance which was supposed to run much faster than all the other threads could be locked out completely and got only allowed to run sometimes which the user could feel. And no we didn't implement any locking mechanisms that could have caused it, changing from yielding to actually sleeping 1 ms limited us to a 1000 FPS but solved everything.

Any bug you are talking about, exist in Windows land out of our reach.
Title: Flipped RenderTexture
Post by: Silvah on February 03, 2012, 11:50:50 am
Oh yeah. It's all awesome, except that:
Quote from: "Silvah"
And, uhm, the behavior of Sleep(0) is actually well-defined, so if you want something else, then you shouldn't blame Sleep(0) for that.
Title: Flipped RenderTexture
Post by: Groogy on February 03, 2012, 03:10:25 pm
Quote from: "Silvah"
Oh yeah. It's all awesome, except that:
Quote from: "Silvah"
And, uhm, the behavior of Sleep(0) is actually well-defined, so if you want something else, then you shouldn't blame Sleep(0) for that.


You mean this definition?
Quote
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread continues execution.


This is a new definition and doesn't apply to XP which is still largely used around the world so we have to use the "worst" case definition... Which is that it will only give up to to at least equal or higher priority threads. And nightmare scenarios could force your application into a stagnation problem.

Statistics from 2011 December:
Quote
Win7    Vista    Win2003    WinXP    Linux    Mac    Mobile
46.1%    5.0%    0.7%    32.6%    4.9%    8.5%    1.2%


That's the definition of Sleep 0 on Windows yes. POSIX don't have any defined behavior for sleep 0. Closest you can get is shed_yield. And still on windows, even if they do have a defined behavior for Sleep 0, they also have a lot of associated problems with this usage on Windows. That they themselves have documented.

And don't hi-jack threads.