SFML community forums

Help => Window => Topic started by: mercurio7891 on December 29, 2010, 10:34:10 am

Title: Can GetEvent or sf::Input be called from another thread?
Post by: mercurio7891 on December 29, 2010, 10:34:10 am
Hi I was wondering if sf::Window::GetEvent or sf::Input be used from another thread from that of which the window is created?

for example
thread 1: Create the Window and do all rendering (aka Graphics Thread)
thread 2: Physics Thread
thread 3: Main Loop where I call window::GetEvent or use the sf::Input here?

is this possible??

regards
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Laurent on December 29, 2010, 10:38:18 am
Nop, this is disallowed by the OS.

However, the following scenario works:
- thread 1: Create the Window and main Loop where you call window::GetEvent or use the sf::Input
- thread 2: Physics Thread
- thread 3: Graphics thread
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 29, 2010, 02:44:23 pm
Quote from: "Laurent"
Nop, this is disallowed by the OS.

However, the following scenario works:
- thread 1: Create the Window and main Loop where you call window::GetEvent or use the sf::Input
- thread 2: Physics Thread
- thread 3: Graphics thread


That's how I designed my game engine for example :)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Grimshaw on December 30, 2010, 01:15:16 am
Question:

Wouldn't we get a more stable application if the main thread was the graphics thread? (Fetch events and render everything)

Have a renderer drawing all game structures in the main loop and those structures would be updated in some other thread : )
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 30, 2010, 01:27:26 am
Depends on how you design it. The problem with having anything heavy together with the events is that the gamer can experience a delay in the input. For example in my game engine my rendering works at a maximum of 60Hz while my main thread works at a 1000Hz, so even if I would do something heavy in the rendering or logics threads, the input will always be the same and no delay will be felt by the gamer.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Laurent on December 30, 2010, 08:06:02 am
Quote
The problem with having anything heavy together with the events is that the gamer can experience a delay in the input. For example in my game engine my rendering works at a maximum of 60Hz while my main thread works at a 1000Hz, so even if I would do something heavy in the rendering or logics threads, the input will always be the same and no delay will be felt by the gamer.

Is it really noticeable? I mean, even if you process events as fast as possible, their effect will still be seen only on the next graphics refresh, so isn't it the same as processing them directly before that refresh (ie. in the graphics loop)? I'm just curious, as I've never experienced such a design.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 30, 2010, 02:57:17 pm
Quote from: "Laurent"
Quote
The problem with having anything heavy together with the events is that the gamer can experience a delay in the input. For example in my game engine my rendering works at a maximum of 60Hz while my main thread works at a 1000Hz, so even if I would do something heavy in the rendering or logics threads, the input will always be the same and no delay will be felt by the gamer.

Is it really noticeable? I mean, even if you process events as fast as possible, their effect will still be seen only on the next graphics refresh, so isn't it the same as processing them directly before that refresh (ie. in the graphics loop)? I'm just curious, as I've never experienced such a design.


I am not a 100% sure. I'm basing it on that in my class there's a lot of hardcore gamers(Duuh... we want to make games) including me. And you do notice a difference in responsiveness between a game running at 120 FPS or 60 FPS even if you don't see any graphical difference.

I kind of try to exploit this in my engine since I have the main thread at 1000Hz, the logic threads at 1000Hz and finally the graphics at 120Hz. The engine is made completely asynchronous so the 3 threads will never have to wait for each other. And most of the time it will be that the event signals get processed directly in the main thread, converted to appropriate signals sent to the logics thread where any associated function/update will be performed. If this results in an entity get's moved for example then the renderer has to be notified and will be by a "Signal.Renderer.Entity.Moved" signal containing what entity and it's position. I believe this should give me an optimal way to have the best responsiveness even though graphics haven't caught up.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Laurent on December 30, 2010, 03:08:54 pm
Ok I see. If the logic thread runs as fast as the event thread, it makes sense.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Contadotempo on December 31, 2010, 12:00:24 am
Quote from: "Laurent"
Nop, this is disallowed by the OS.

However, the following scenario works:
- thread 1: Create the Window and main Loop where you call window::GetEvent or use the sf::Input
- thread 2: Physics Thread
- thread 3: Graphics thread

I'm really bad with threads and I'm having a bit of trouble trying to think of algorithm with this working (I'm a beginner).

Are there any examples of something simple? I searched the wiki out of curiosity but I couldn't find anything (or I'm just bad at searching).

Thanks :)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 31, 2010, 12:21:43 am
There isn't really anything simple. This is pretty heavy stuff. So only thing I can say is to experiment if you don't want to look at some more advanced and complete examples.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Contadotempo on December 31, 2010, 01:11:35 am
I'd be willing to look at any example then  :)
I'm having trouble picturing threads.

I tried doing the following:
I have a simple class with some sprites...
(I trimmed the constructors, initializations, etc  to keep it short. Let's suppose all sf::Sprites have an image already set)
Code: [Select]

//App is a sf::RenderWindow object

class main_roll
{
public:
       sf::Sprite char1;
       void DrawStuff()
       {
                App.Clear();
                App.Draw(char1);
                App.Display();
       }
       void MainInputs()
       {
               //Get Inputs and Move char1
       }
       void MainRoll()
       {
              MainInputs();
              DrawStuff();
       }

};


And I wanted to make "DrawStuff" a thread.
I tried:

Code: [Select]

class main_roll
{
public:
       sf::Sprite char1;
       void DrawStuff()
       {
                App->Clear();
                App->Draw(char1);
                App->Display();
       }
       void MainInputs(void *Data)
       {
               //Get Inputs and Move char1
       }
       void MainRoll()
       {
              sf::Thread th(&DrawStuff);
              th.Launch();
              MainInputs();
       }

};


But it seems it's not the correct way to do it.
So as you can see I'm pretty bad. But I'm willing to look at any example.

Thanks again :)

(Hope this isn't considered topic-hijacking)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Wafthrudnir on December 31, 2010, 01:24:01 am
I am a lil drunk atm, but i try to add some stuff ;D

Is it possible to make a thread via a Class Method in SFML?!?...try this:

You need a wrapper function for each Class Method to use in a thread.

E.G.

For CLASS.Method1() you must run this function in a thread:

Code: [Select]
void meth1func(CLASS* c)
{
    c->Method1();
}


So the Thread should be working...if that's your problem...

If not, i could take a look at some source i wrote a while ago and give an exact example....

regards,

Wafthrudnir

P.S: I always used WinApi Threads...not the SFML ones...[/code]
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Contadotempo on December 31, 2010, 03:27:36 am
I'm having a bit of trouble understanding that example.
What does CLASS mean? Is it creating an object of "main_roll" on my example?

Sorry for the trouble  :(
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 31, 2010, 05:29:58 am
The simplest way to do this is that at the end of each threads frequency stop(when the thread is finished working and are about to sleep) it waits for the other threads to catchup, and then synchronize. So let's say we have the Main thread which should monitor and handle the other threads, we also put the event-pulling into this thread. Then we have the logics thread and the rendering thread.

At the start of each cycle the main thread will pass along copies of the processed events to the input and render queue that it needs to. Each thread does it's work. Render, calculate collisions, process events. And when done it goes to sleep and waits until the main thread tells everyone "BACK TO WORK YOU LAZY ***" and a new cycle begins. But before main tells the threads to go back to work, main should copy all data in the logics thread over to the rendering thread. It's very important that every thread woks in it's own environment, we never want the threads to work with shared data at the same time.

This is the simplest way I can come up with to implement a way for threads to be assigned specific subsystem-roles. I.E: One rendering thread, One logics thread and so on. Now this way got a lot of cons. Like the rendering will always be 1 frame behind the logics, the fact that we have to duplicate data(we would have to anyway if we want to make it efficient), that the data is copied at every frame is not a good choice. And so on. The pro is(according to my teachers, I haven't tried this model) that it will actually run faster on a 2+ Core platform if done properly. Also it's probably the easiest way in getting into this kind of thinking.

I can go more deeper into detail if this wasn't enough. I can also give you another model which I talked a little about in some previous posts. I am currently using it in my game engine which makes it completely asynchronous. Every part, every thread is independent from one another. But if I'm gonna go trough that I'll have to write a whole essay and probably draw diagrams to explain it. Though a part of that system is available in the wiki ^^

It's one thing to have it in your head another to try and explain it to someone else.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Wafthrudnir on December 31, 2010, 05:33:13 am
Hi,

sorry maybe it's the alcohol ;D I try it this way:

With the WinApi it's like this

You have a class called MyClass...

Code: [Select]

class MyClass
{
   public:
       void drawGraphics();
};


This class has the method drawGraphics()...

You can not run this method in a thread. A thread needs to be a real function.
If you want to use this method as a thread method, there is this workaround:
You build a (global) function that takes a pointer of an object of your class(MyClass)
Like:

Code: [Select]

void wrapperDrawGraphics(MyClass* c )
{
      c->drawGraphics()
}


When creating a thread in WinApi style it would look like this:

Code: [Select]

MyClass myClassObject;
DWORD dwThreadId;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wrapperDrawGraphics, myClassObject, 0, &dwThreadId);


I do not know if SFML is handling it different, but maybe creating this kind of helper function, that takes a pointer to your class Object and running this function in a thread would help?!!

in SFML it would look like this i think:

Code: [Select]

class MyClass
{
   public:
       void drawGraphics();
};

void wrapperDrawGraphics(void* c)
{
     MyClass* myClassObj = static_cast<MyClass*>(c); //cast back to MyClass
     myClassObj->drawGraphics();
}

//somewhere in main maybe...
MyClass myClassObject;
//First the function to be run in a thread, then the param passed to this function...
sf::Thread Thread(&wrapperDrawGraphics, &myClassObject);
Thread.Launch();


This would make the wrapperDrawGraphics function run in a thread. And cuz this function calls the drawGraphics-Method of the referenced MyClass object, the Method is running in a thread.

Hope this helps somehow.

Regards,

Wafthrudnir
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on December 31, 2010, 06:09:47 am
That workaround is not needed in SFML.. You can simply inherit from sf::Thread and in SFML2 it can take an object and associated member function to run. So it more or less does it for you :)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: mercurio7891 on December 31, 2010, 12:21:05 pm
for me my system is design base on a thread pool. So a subsystem is technically not bounded to any thread but spreaded in the pool. However as the sf::Input and GetEvent can't be separated from the main thread, I just forced them together :)

The main advantage of using a thread pool is so that we are not locked to 1 subsystem per thread, and we can scale the number of threads as and when the computer has more cores available.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Wafthrudnir on December 31, 2010, 05:08:33 pm
@Groogy:

Thanks, I didn't know that  :)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Contadotempo on December 31, 2010, 06:48:39 pm
Aaah, I think I'm starting to understand how threads work.
I did some experiments but still the results weren't very good hehe.
I tried doing this (following my example):

Code: [Select]
//App is a sf::RenderWindow object

class main_roll : public sf::Thread
{
public:
       sf::Sprite char1;
       //Override threaded function inherited from sf::Thread:
       virtual void Run()
       {
                while(App.IsOpened())
                {
                       App.Clear();
                       App.Draw(char1);
                       App.Display();
                }
       }
       void MainInputs()
       {
                  while(App.IsOpened())
                      //Get Inputs and Move char1
       }
       void MainRoll()
       {
              Launch();
              MainInputs();
       }

};


But the results were bizarre. Distorted Graphics, white screens flashing...
I'm guessing it's because the main thread and the thread that runs the drawable objects are not synchronized. How could I do this? Mutex's?

Thanks for all the help so far and happy new year community  :D
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on January 01, 2011, 07:43:23 pm
All I can do is referring you to my previous wall of text. I described there how to synchronize, if you use nutex,  critical section or atomic operations is up to your implementation.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Wafthrudnir on January 01, 2011, 09:47:00 pm
Yes, use Mutexes.

I think this could help...
Code: [Select]

//App is a sf::RenderWindow object

class main_roll : public sf::Thread
{
public:
       sf::Sprite char1;
       //Override threaded function inherited from sf::Thread:
       virtual void Run()
       {
                while(App.IsOpened())
                {
                       //MUTEX LOCK <--------------------------
                       App.Clear();
                       App.Draw(char1);
                       App.Display();
                       //MUTEX UNLOCK <--------------------------
                }
       }
       void MainInputs()
       {
                  while(App.IsOpened())
                  {
                      //MUTEX LOCK <--------------------------
                      //Get Inputs and Move char1
                      //MUTEX UNLOCK <--------------------------
                  }
       }
       void MainRoll()
       {
              Launch();
              MainInputs();
       }

};


Maybe this could give you some FPS Issue?!
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Laurent on January 01, 2011, 11:17:54 pm
Nice example of what not to do with threads ;)

Threads must be used to make things run in parallel. If you end up synchronizing everything, you loose all the benefits -- and you have a code that is even worse than the single-threaded version.

Use threads when you know what you do, not just because "it's cool" ;)
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Wafthrudnir on January 02, 2011, 01:22:51 am
I was wondering why to use threads anyway in a game (except for a loading/statusbar, that's displayed on top of an animated map etc.) :?

The mutexes in the code example above may work, but yes, threading in this one does not really make sense.

@Contadotempo

Imaging this:

Everything gets drawn to screen, to do this, the app needs to know the x-coordinates of each object.
But if you want to access them, you need to block them, so no other thread can change it's values while reading them (could cause serious bullsh**).
And while your app is drawing, no input can be processed, if it changes the objects coordinates.
SO...
after your App has drawn everything, it frees the mutex...you push the left-key...but...oh no...the app already has locked the mutex again, you have not been fast enough...so no update on movement...

If there is no lock, things get messed up...Variables get read and written to by different threads at the same time...the screen refreshes while reading a value that has just been change at the same time...instead of getting a X-Position of 6 you get a 32523 or something else, because the writing was not finished.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on January 02, 2011, 02:01:27 pm
Waft is correct but there are ways to go around this need of locking the data and I've already described one way using synchronization and data duplication(one for each thread).

Also there is a way to make it completely asynchronous without any need for locking data(In my implementation I actually use mutexes around 1 queue but when I get time I'll remove it) which gives you 100% exploitation of parallel programming. How this is possible is based on data duplication. How you duplicate the data depends on the model. For my model the data is duplicated on the run and I can't go into detail as I'm writing from my phone. For you guys, just to get started, have the data duplicated at the end of the frame.

If you still don't see the need of data duplication. It's very simple, we never want threads that work on the same memory. What we basically wants are processes which still interfaces with each others easily. If you don't know what a process is then simple explained, a thread with private memory. This is easily made by duplication of the data. An easiest way to do that is by stopping all the threads except for the main, copy the data from main to the various threads.

Writing on the phone is hard and takes a long time to do XD
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Contadotempo on February 04, 2011, 12:54:52 pm
I'm sorry for replying a month later, but exam season in university left me with no time and I only got a chance to come here now. I really can't go out without saying thanks after I find the solution so here I am. :)

I ended up following Groogy's implementation  and using sf::Thread and its working nice and smooth now. Thanks guys for all the help.
Title: Can GetEvent or sf::Input be called from another thread?
Post by: Groogy on February 04, 2011, 01:49:51 pm
I'm glad you got it to work :)

Get things running parallel is pretty hard for newbies to do right. Also since you can see that CPU's are not getting better, they are just getting an increased core size, being able to utilize that is pretty important for the future.