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

Author Topic: Hang after sf::RenderTarget::clear  (Read 3765 times)

0 Members and 2 Guests are viewing this topic.

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Hang after sf::RenderTarget::clear
« on: August 16, 2014, 09:50:04 am »
Hey,
I am having some issues with (seemingly) random hangs at startup while clearing a RenderTexture
My setup looks like this:
Main Thread does Logic/Physics at a fixed "frame"rate
Graphics thread renders as fast it can

I use box2d for physics and make use of the debug drawing, to do so I have a mutex-protected rendertexture which I render stuff to once per logic cycle and the graphics thread simply draws it.

Like I said, I have some issues that sometimes (feels like every damn time after every compile&run) the process will simply hang.
I'm working on windows under MinGW. I tried debugging the thing with gdb, but that didnt give me any useful stack traces whatsoever, so I created a memory dump of the process and loaded that up in visual studio: http://puu.sh/aUEcb/f10b5617c6.png
test.exe!40a6aa is where it calls "m_texture.clear(sf::Color(0, 0, 0, 0));"
Code: http://puu.sh/aUEec/8951a49c94.png
Assembly: http://puu.sh/aUEpZ/94ad99483e.png

sfml-graphics-d-2.dll!68ee0c65 is a call to sf::Context::setActive in bool "sf::priv::RenderTextureImplFBO::activate(sf::priv::RenderTextureImplFBO *const this, bool active)" (why does it call activate again? I already set it to active)
Assembly: http://puu.sh/aUEkH/10767d1ac6.png

After that it seems to get lost in the ati dll
I've got a  AMD Radeon HD 7800 (dont know exactly which version, can be looked up if needed though) and video drivers seem to be up to date
Does anyone have any idea what might be causing this?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10990
    • View Profile
    • development blog
    • Email
AW: Hang after sf::RenderTarget::clear
« Reply #1 on: August 16, 2014, 11:28:21 am »
Not sure if I understood your concept right, but if you block your rendering thread every logic iteration, what good is your "mulithreaded" system? All this can be easily achieved in one thread and would cause you less trouble, because it's rather hard to make sure no race conditions ever exist etc.

As for the problem you first need to make sure your multi threading stuff isn't blocking, then check if you get similar issues in a non multi threaded environment and at last check if it makes a difference when disable the multi thread graphics optimization in your driver settings.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Hang after sf::RenderTarget::clear
« Reply #2 on: August 16, 2014, 12:07:17 pm »
It's only blocking while it's drawing the debug graphics to the render texture, which i'll disable in production versions anyways.

Simple pseudocode
Physics:
while(running){
    simulatePhysics();
    updateEntities();
    mutex.lock();
    prepareDebugTexture();
    mutex.unlock();
}
Graphics
while(running){
    window.clear();
    m_window.draw(scene); // scene is a drawable, passes down call to children
    mutex.lock();
    m_window.draw(debugTexture); // simplified, using a sprite+getTexture
    mutex.unlock();
}
See Edit2 for a simple test case
(click to show/hide)
Edit:
Quote
and at last check if it makes a difference when disable the multi thread graphics optimization in your driver settings.
No idea how I'd do that


Edit2:
Minimal testcase code:
#include <SFML/Graphics.hpp>
#include <thread>
#include <iostream>
sf::RenderWindow window(sf::VideoMode(1024, 576), "SFML works!");

void graphics() {
    window.setActive(true);
    while(1){
        window.clear(sf::Color::Green);
        window.display();
    }
}

int main(int argc, char** argv) {
    window.setActive(false);
    sf::RenderTexture rentex;
    rentex.create(500, 500);
    std::thread d(graphics);
    while (1) {
        std::cout << "preclear" << std::endl;
        rentex.clear(sf::Color(0,0,0,0));
        std::cout << "postclear" << std::endl;
    }
    return 0;
}
 
Hangs after preclear when either window.clear or window.display is being used in the thread
gcc version 4.8.1 (rev5, Built by MinGW-W64 project) (32bit)
I've tried the "GCC 4.7 TDM (SJLJ) - 32 bits" binaries as well as self built ones with fresh sourcecode from github
« Last Edit: August 16, 2014, 12:43:03 pm by iMer »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Hang after sf::RenderTarget::clear
« Reply #3 on: August 16, 2014, 12:36:22 pm »
You might not see it, but when you access SFML graphics from multiple threads simultaneously, SFML has no choice other than to create an OpenGL context per thread which is required to do anything with the GPU.

Many beginners make the mistake of believing that they gain from splitting their graphics operations up among multiple threads, most of the time based on rumours or advanced publications that were not targeted towards them in the first place. OpenGL can benefit from being run in multiple simultaneous threads, but only when used in very very advanced ways. SFML, needless to say, doesn't even make use of modern OpenGL yet, so all the possible benefits are already out of the question. Fact of the matter is that you don't gain any performance when drawing in multiple threads with the current version of SFML. Any apparent gains are solely attributed to the CPU doing CPU-based work in the secondary thread and nothing related to graphics at all.

Now, as for your problem, since the internal synchronization strategy of the driver was never meant to be transparent, we can only assume things. In this case, I assume it is having a hard time synchronizing certain operations at the start of your application because contrary to what beginners might think, when you create a GPU-based resource like the sf::RenderTexture, it is up to the driver and ultimately the GPU when it really creates it. All that is guaranteed is that your graphics operations are executed in the order you specified, but not at what time. It would be easy to find out where exactly it is really blocking if I had a copy of the executable and could perform an OpenGL API trace, but I don't think I would find anything other than that multi-threading is the root cause of the issue.

Like eXpl0it3r already said, what are you trying to gain with multiple threads? The same could be done in a single thread, or at least if you wanted to use multiple threads for your physics, restrict any graphics operations to a single one. Performing your own synchronization is always superior to relying on the driver to do it for you, and you won't have to pay the cost of it doing something wrong.

This was all I could make out given the very sparse code you provided. It might be possible that you made a trivial mistake somewhere else, but there is no way for anyone to tell if you don't provide a more complete picture of what your code looks like.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Hang after sf::RenderTarget::clear
« Reply #4 on: August 16, 2014, 12:56:26 pm »
Apparently I was editing my code while you replied, see Edit2 for a minimal test case
Quote
Many beginners make the mistake of believing that they gain from splitting their graphics operations up among multiple threads

I only do the graphics from that thread since it's the only threadsafe way to render debug stuff from box2d without locking the graphics/logic thread completely, it should work though.
It's more the logic/graphics seperation I'm looking for - call it premature optimization, but I think such a drastic design element is easier to implement at the start instead of patching it in later.
I might not ever use it really, it'll be a good excercise regardless.

I also included the binary in case you cant be bothered to compile the code yourself
I cant upload an attachment (84kb):
Quote
An Error Has Occurred!
The upload folder is full. Please try a smaller file and/or contact an administrator.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Hang after sf::RenderTarget::clear
« Reply #5 on: August 16, 2014, 01:13:46 pm »
There is no delay for me when running that code. It just runs as if nothing blocked at all. Must be something that is specific to your driver.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Hang after sf::RenderTarget::clear
« Reply #6 on: August 16, 2014, 01:25:53 pm »
There is no delay for me when running that code. It just runs as if nothing blocked at all. Must be something that is specific to your driver.
Well, there isnt any delay
It just stops doing anything/blocks and never continues

Any ideas how I can debug that?

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Hang after sf::RenderTarget::clear
« Reply #7 on: August 16, 2014, 01:35:11 pm »
It just stops doing anything/blocks and never continues

Any ideas how I can debug that?
In that case, if it really just blocks forever, you can break in the debugger and show us the full stack trace.

You need to be more specific when specifying your graphics hardware and driver version. "Seems to be up to date" isn't good enough. Many laptop users say that as well when they are using 5 year old drivers.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Hang after sf::RenderTarget::clear
« Reply #8 on: August 16, 2014, 02:27:18 pm »
It just stops doing anything/blocks and never continues

Any ideas how I can debug that?
In that case, if it really just blocks forever, you can break in the debugger and show us the full stack trace.

You need to be more specific when specifying your graphics hardware and driver version. "Seems to be up to date" isn't good enough. Many laptop users say that as well when they are using 5 year old drivers.
That's where I'm having issues.. gdb doesnt exactly cooperate for whatever reason
There definitely shouldn't be 5 threads
(click to show/hide)
A different debugger shows 4 threads with a similar stack trace
So, then I tried using Visual Studio (Man that GUI is confusing if you never use it)
Same stack trace as in the op: http://puu.sh/aUPmj/19faffb936.png not sure what to make of that (line 22 is actually the 2nd std::cout <<... guess thats just a inconsistency)

I grabbed glintercept and let that log (both the vs and mingw version stop at DXCloseDeviceNV)
(click to show/hide)

iMer

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Hang after sf::RenderTarget::clear
« Reply #9 on: August 16, 2014, 02:51:01 pm »
Bleh, turns out it was my drivers fault after all.
Updated from 13.something to the newest version (14) and everything works fine

Thanks for your help anyways

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Hang after sf::RenderTarget::clear
« Reply #10 on: August 16, 2014, 03:03:01 pm »
It is easy to recognize how old AMD drivers are. The more recent versioning scheme comes in the form of <year>.<month> when the driver was released, so 13.something means that driver was from sometime last year. The latest Catalyst driver is 14.4, which means it is at least 3 versions newer than what you had, and given your relatively new hardware (1 year since release is still new for me), it probably fixed a few issues that were still present in the early driver releases.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10990
    • View Profile
    • development blog
    • Email
Re: Hang after sf::RenderTarget::clear
« Reply #11 on: August 17, 2014, 12:01:56 am »
It's only blocking while it's drawing the debug graphics to the render texture, which i'll disable in production versions anyways.

Simple pseudocode
Physics:
while(running){
    simulatePhysics();
    updateEntities();
    mutex.lock();
    prepareDebugTexture();
    mutex.unlock();
}
Graphics
while(running){
    window.clear();
    m_window.draw(scene); // scene is a drawable, passes down call to children
    mutex.lock();
    m_window.draw(debugTexture); // simplified, using a sprite+getTexture
    mutex.unlock();
}

I only do the graphics from that thread since it's the only threadsafe way to render debug stuff from box2d without locking the graphics/logic thread completely, it should work though.
It's more the logic/graphics seperation I'm looking for - call it premature optimization, but I think such a drastic design element is easier to implement at the start instead of patching it in later.
Just out of curiosity, how much did you ever learn/read about multi-threaded development? Why do you think "it's the only threadsafe way to render debug stuff from box2d"?

If you do logic in one thread and render stuff in another, how do you synchronize the two threads? Are you aware that if the logic thread is in the middle of updating the entities and the graphic thread draws all entities, that part of them will be at the new position and part of them will be at the old position? Have you ever thought about what happens, if the logic thread is in the process of writing the new position of the entity while at the exact same time the graphic thread is trying to read that position? What value will the graphics thread read? Who will be faster at read or writing?

These are all general multi-threading problems which can most of the time only be solved by placing mutexes/locks, which again in turn will make your multi-threaded system totally useless or actually produce an unnecessary overhead, meaning worse performance. The reason is that you'd end up with having to lock one or the other threads to update the logic or graphics and thus your seemingly "parallel" execution becomes a sequential one, which would be better placed in one thread and not having to deal with threading overhead and synchronization issues.

So while you think it's any kind of optimization or being smart about splitting up things, you're essentially writing broken code and don't get any gain from it. Just search the forum or the internet a bit and you'll find, many many users (me included), who had the same smart idea, until they actually started to learn a bit more about parallel programming. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Hang after sf::RenderTarget::clear
« Reply #12 on: August 17, 2014, 12:22:55 am »
Some tools that may help you debug threading issues:

  • Valgrind (especially the Helgrind tool).
  • ThreadSanitizer (easily available as build-in functionallity of newer versions of the clang and gcc compilers by simply building with "-fsanitize=thread".
  • CHESS also looks interresting, but I've never tried that one myself.