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

Author Topic: Issue with Threads and Recreating sf::RenderWindow  (Read 3021 times)

0 Members and 1 Guest are viewing this topic.

kitteh-warrior

  • Guest
Issue with Threads and Recreating sf::RenderWindow
« on: August 08, 2015, 03:27:58 pm »
Hello, I have encountered a problem while using a std::thread to do drawing, while the main thread to handle events.

Using this code:
(click to show/hide)
causes the blue rectangle to appear on half of the screen.
But: when I release a key to recreate the render window, the rectangle is no longer appearing, though the drawing thread doesn't exit from the loop, nor does it halt from the mutex.

Basic information:
Version: SFML 2.3.x (this commit: https://github.com/SFML/SFML/commit/f6020c5f8e8baa0884029fc9629d5bdcf56d50fc)
OS: Windows 10 Pro
Graphics: AMD Radeon R4
Processor: AMD A6-6310

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #1 on: August 08, 2015, 04:51:20 pm »
If you insist on using threads (I'd advice against it generally) you should do your rendering on the main thread (or be prepared to dig into some unpleasant OpenGL context  stuff - I'm no expert, but search the forum; there have been many threads on the topic).
The easy solution is usually to just avoid threads - most projects don't actually need them anyway and they bring a lot of complexity beyond just rendering issues.

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #2 on: August 08, 2015, 06:34:35 pm »
You need a way to make the drawThread call window.setActive(true), iirc.

GraphicsWhale

  • Full Member
  • ***
  • Posts: 131
    • View Profile
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #3 on: August 08, 2015, 06:39:01 pm »
You called window.setActive(false) from your main thread but never called window.setActive(true) in your secondary thread. Maybe this has something to do with it.

GraphicsWhale

  • Full Member
  • ***
  • Posts: 131
    • View Profile
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #4 on: August 08, 2015, 06:52:23 pm »
I typically implement my multi-threaded polling like this:

void logic_thread(sf::Window& window, std::queue<sf::Event>& buffer, std::mutex& buffer_mutex)
{
    window.setActive(true);

    std::queue<sf::Mutex> events;
    while (window.isOpen())
    {
        while (buffer.size() > 0)
        {
            buffer_mutex.lock();
            events.push(buffer.front());
            buffer.pop();
            buffer_mutex.unlock();
        }

        while (events.size() > 0)
        {
            sf::Event event = events.front();
            events.pop();

            //Handle event
        }
    }
}

void main()
{
    sf::Window window;
    std::queue<sf::Event> buffer;
    std::mutex buffer_mutex;

    window.setActive(false);
    std::thread logic_thread(std::ref(window), std::ref(buffer), std::ref(buffer_mutex));

    std::queue<sf::Mutex> tmp;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
            tmp.push(event);

        while (tmp.size() > 0)
        {
            buffer_mutex.lock();
            buffer.push(tmp.front());
            tmp.pop();
            buffer_mutex.unlock();
        }
    }

   logic_thread.join();
}
 

The reason why is because when you have implementations like yours, it's difficult to defer things that require processing on the other thread. On top of that, I've found that certain things can cause sf::Window::pollEvent to "hang", which mixed with a mutex would cause the same thing to happen on the other thread. And if you're using a time-step, accumulating updates is a very bad thing.

There's a few functions I call that I don't use a mutex for, but I don't have any synchronization problems. There's simply no other way around easily deferring events from one thread to another.
« Last Edit: August 08, 2015, 07:40:10 pm by GraphicsWhale »

kitteh-warrior

  • Guest
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #5 on: August 08, 2015, 07:06:59 pm »
I have noticed that calling any draw()/update()/display() calls of a sf::RenderWindow or sf::RenderTexture will implicitly call a setActive(true); (at least in previous versions of SFML), which is why it would say that it failed with to context while attempting to draw something if I didn't use setActive(false);.

I will try out your suggestion, GraphicsWhale.

That main reason that I want to have event processing in a separate thread from drawing, is because drawing is typically limited by a frame rate, but event input shouldn't be (at least how I look at it).

GraphicsWhale

  • Full Member
  • ***
  • Posts: 131
    • View Profile
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #6 on: August 08, 2015, 07:34:31 pm »
If your input handling is programmed right, you shouldn't need to rely on how many times it's polled (of course it should be polled often enough to not feel sluggish, but if your frame-rate drops and it's polled not-so-often, the frame-rate would be more noticeable than the slower input response).

Even then there's the problem with events that cannot be handled by the main thread. Unless you plan on synchronizing any part of your game that is effected by input with both of your threads (which will lock both of your threads at whichever one goes the slowest), you're going to have to defer the input anyways to the game logic thread.

Just use the main thread for polling events, don't try to make modifying your game's state in both threads work.
« Last Edit: August 08, 2015, 07:42:04 pm by GraphicsWhale »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Issue with Threads and Recreating sf::RenderWindow
« Reply #7 on: August 08, 2015, 11:25:56 pm »
That main reason that I want to have event processing in a separate thread from drawing, is because drawing is typically limited by a frame rate, but event input shouldn't be (at least how I look at it).
Threads are not necessary for this. You can loop the input and/or logic multiple times (if required) per frame and only render a frame when it's necessary.
This article (which always gets thrown around when this topic comes up but it helped me to understand it) could help. See the section entitled Free The Physics as that seems to be the aim you have.
I even wrote a couple of classes to make it easy (see this example and this project).
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*