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

Author Topic: Window.waitEvent() and multithreaded input handling.  (Read 4604 times)

0 Members and 1 Guest are viewing this topic.

papush!

  • Newbie
  • *
  • Posts: 3
    • View Profile
Window.waitEvent() and multithreaded input handling.
« on: February 03, 2018, 09:53:54 pm »
Hi,
the official documentation for Window.waitEvent() says its main use is when called from a dedicated input handling thread, but after some experimentation and reading around it seems the only way to handle input in a separate thread is to:
  • create the window in the input handling thread (doesn’t seem to be a problem on GNU/Linux, but apparently most systems don’t like handling input on a different thread);
  • make sure not to draw on the window and gather input events at the same time.

So I guess I’m left with three questions:
  • What’s the point of waitEvent(), considering you can’t draw on the window while waiting for an event?
  • Is there a point to a separate rendering thread? Most people seem to agree there isn’t, considering you’d still have to synchronise it to the rendering, but maybe you could poll at a fixed interval in the input handling thread and draw the rest of the time to make sure input is framerate-independent (unless the framerate is lower than the polling rate, a possible solution would be to draw to a backbuffer and only lock the window for the (short) time it takes to copy the backbuffer to it)
  • Is the waitEvent() documentation just plain wrong then?

I’m just making a simple top-down 2D game, so I’m probably overthinking a lot of stuff, but it got me curious and I’d appreciate if someone could shine some light on the matter.
« Last Edit: February 03, 2018, 10:19:23 pm by papush! »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Window.waitEvent() and multithreaded input handling.
« Reply #1 on: February 04, 2018, 11:14:52 am »
All your questions seem to be related to this conclusion:

Quote
you can’t draw on the window while waiting for an event

What makes you think it is impossible? It should not. Please describe your problem precisely, instead of jumping to conclusions directly ;)
Laurent Gomila - SFML developer

papush!

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Window.waitEvent() and multithreaded input handling.
« Reply #2 on: February 04, 2018, 12:10:59 pm »
Well attempting to do so either results in a bunch of “Failed to activate the window's context” followed by a “XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server: 0”, or an immediate “XInitThreads has not been called”. Considering that other people were having the same problem (and calling XInitThread isn’t cross-platform), I thought it was just impossible.

Here is a basic example that produces either of those errors (I’m guessing depending on wether draw() or waitEvent() gets called first):
#include <thread>
#include <memory>
#include <SFML/Graphics.hpp>

sf::Sprite sprite;
bool quit = false;

void draw(sf::RenderWindow *window) {
    while (!quit) {
        window->draw(sprite);
        window->display();
    }
}

int main() {
    sf::Texture texture;
    texture.loadFromFile("poivron.png");
    sprite = sf::Sprite(texture);
    sf::RenderWindow window(sf::VideoMode(640, 360), "test");
    window.setFramerateLimit(300);

    std::thread rendering(draw, &window);

    sf::Event event;
    while (true) {
        if (window.waitEvent(event)) {
            if (event.type == sf::Event::Closed)
                break;
        }
        else
            break;
    }
    quit = true;
    rendering.join();
}
 

Am I doing something wrong? I guess I should have made a post in the help forum first, sorry about that.

Edit, to clarify my point:
Synchronising the threads to prevent concurrent access like this:
#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>
#include <memory>
#include <SFML/Graphics.hpp>

std::mutex m;
sf::Sprite sprite;
bool quit = false;

void draw(sf::RenderWindow *window) {
    unsigned i = 0;
    while(!quit) {
        sprite.setPosition((i % 10) * 30, (i / 10) * 30);
        i++;
        if (i > 100) {
            i = 0;
        }
        m.lock();
        std::cout << "Rendering." << std::endl;
        window->clear();
        window->draw(sprite);
        window->display();
        m.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main() {
    sf::Texture texture;
    texture.loadFromFile("poivron.png");
    sprite = sf::Sprite(texture);
    sf::RenderWindow window(sf::VideoMode(640, 360), "test");
    window.setFramerateLimit(300);

    std::thread rendering(draw, &window);
    window.setActive(false);

    sf::Event event;
    while (true) {
        m.lock();
        std::cout << "Waiting for an event…" << std::endl;
        bool ok = window.waitEvent(event);
        std::cout << "Event received." << std::endl;
        m.unlock();
        if (ok) {
            if (event.type == sf::Event::Closed)
                break;
        }
        else
            break;
    }
    quit = true;
    rendering.join();
}
 
effectively gets rid of the errors and crashes, but then the rendering is halted while waiting for an event (see attachment).
« Last Edit: February 04, 2018, 07:48:41 pm by Laurent »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Window.waitEvent() and multithreaded input handling.
« Reply #3 on: February 04, 2018, 01:31:07 pm »
You need to activate a context in the thread you want to use OpenGL (through SFML).

window.setActive(true)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Window.waitEvent() and multithreaded input handling.
« Reply #4 on: February 04, 2018, 07:52:31 pm »
You're facing two well-known limitations of the lower levels (OS and OpenGL), which are expected and described in the documentation (not sure for XInitThreads, but the information can easily be found on the forum):

1. On Linux, with XLib, you need to call XInitThreads() when you're managing your window from multiple threads; it's not multi-platform but it is needed anyway, so just use some preprocessor conditions to make that call only on Linux.

2. As eXpl0it3r said, if drawing happens in a different thread, you need to deactivate the window from the thread where it is active, and activate it in the thread that makes the draw calls.
Laurent Gomila - SFML developer

papush!

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Window.waitEvent() and multithreaded input handling.
« Reply #5 on: February 04, 2018, 09:03:51 pm »
That cleared it up, thanks, you guys are doing great work  :)