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

Author Topic: Drawing from within a thread  (Read 23845 times)

0 Members and 1 Guest are viewing this topic.

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« on: January 01, 2009, 07:41:15 pm »
As explained in my other posting here, I have written a small class that inherits from the thread class.
The purpose of this thread is to draw some moving stars (up to now, these are only small, white rectangles). This starfield class has a member variable that points to the appropriate RenderWindow.

The class's Run() method calls another method that iterates over all the stars, creates a Rectangle for each, and draws this Rectangle to the RenderWindow that is specified by the appropriate pointer.

The Display()-method of the RenderWindow is called outside this thread, in the program's main loop.

Now, for some reason, whatever I try to draw within this separate thread doesn't get displayed on the window, whereas stuff I draw in the main loop is correctly displayed.

In contrast, when I call the Draw-method of my Starfiled class from within the main loop, everything is displayed correctly.

Is this some sort of race condition, as it might happen that the thread tries to draw some stuff on the RenderWindow, while the main loop calls Display()?
If so, I guess I'd have to use some mutex for synchronization, but in that case, there wouldn't be any benefit from using a separate thread for drawing those stars (my original intention was to keep movement of the player's sprite more responsive, by not having to wait until all stars are drawn before input is processed).

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« Reply #1 on: January 01, 2009, 08:08:18 pm »
Now I modified my program a bit so that no drawing is performed within the main loop, but only from within the thread (the main loop only does the event handling).

This didn't improve the situation, now I only see lots of garbage within the window, as if it wasn't correctly initialized. Really weird.

EDIT: I just found this thread here:
http://www.sfml-dev.org/forum/viewtopic.php?t=349

I guess that's more or less the same problem I encounter here, isn't it?
Should I see any error messages in that case?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Drawing from within a thread
« Reply #2 on: January 01, 2009, 08:56:01 pm »
The problem is that OpenGL (and thus SFML) doesn't allow a context (RenderWindow) to be active in multiple threads at the same time.

So you can actually draw from many threads, but you have to :
- Activate the window (window.SetActive(true))
- Do your drawing
- Deactivate the window (window.SetActive(false))

And make sure that no thread will try to do the same stuff at the same time.

You should get error messages accordingly, saying something like "the operation is not allowed in the current state".
Laurent Gomila - SFML developer

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« Reply #3 on: January 01, 2009, 09:04:35 pm »
Quote from: "Laurent"
The problem is that OpenGL (and thus SFML) doesn't allow a context (RenderWindow) to be active in multiple threads at the same time.

So you can actually draw from many threads, but you have to :
- Activate the window (window.SetActive(true))
- Do your drawing
- Deactivate the window (window.SetActive(false))

And make sure that no thread will try to do the same stuff at the same time.

You should get error messages accordingly, saying something like "the operation is not allowed in the current state".


Thanks for the answer. To ensure that no two threads set the same window active/inactive concurrently, I'd have to use some mutex or lock, I guess. In that case, using a thread won't probably be very advantageous compared to the single-threaded solution.

By the way: How does/can OpenGL know that a context is active within multiple threads?
Supposed we have a thread A that tries to draw something, and another thread B that tries to draw something else.
If the two calls would strictly alternate (i.e., never occur concurrently), wouldn't it look to OpenGL as if both calls were made from within the same thread, one after the other?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Drawing from within a thread
« Reply #4 on: January 01, 2009, 09:10:40 pm »
Quote
How does/can OpenGL know that a context is active within multiple threads?

It doesn't have to know this, you just can't activate a context if it's already active in another thread ;)
Laurent Gomila - SFML developer

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« Reply #5 on: January 01, 2009, 09:22:43 pm »
Quote from: "Laurent"
Quote
How does/can OpenGL know that a context is active within multiple threads?

It doesn't have to know this, you just can't activate a context if it's already active in another thread ;)


And why is it/must it be activated from within the second thread?
I still have some problems in understanding the  difference between:
Code: [Select]

Thread A:
Create/Init Window
DrawSomeObject
DrawAnotherObject

and
Code: [Select]

Thread A:                             Thread B:
Create/Init Window
DrawSomeObject
                                      DrawAnotherObject


Both examples should result in the same sequence of OpenGL function calls, shouldn't they? (assuming that DrawSomeObject and DrawAnotherObject don't run in parallel).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Drawing from within a thread
« Reply #6 on: January 01, 2009, 11:27:07 pm »
The problem is not the sequence of calls, it's just that multiple threads are involved. Don't ask me why, I don't know the internal secrets of OpenGL.
Laurent Gomila - SFML developer

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« Reply #7 on: January 02, 2009, 02:22:30 am »
Really strange.

I just tried to add some mutual exclusion to my program, and indeed, it only works correctly if I make one window inactive and the other active. But it's the same window in both cases!

I'd really like to understand what happens here. I found lots of threads saying OpenGL is not thread-safe, but even in that case, a strict alternation of the draw operations should be sufficient in my opinion - but obviously, this isn't the case.

Anyway, I now just draw the stars within my main loop and not within a separate thread.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Drawing from within a thread
« Reply #8 on: January 02, 2009, 09:24:07 am »
I guess it's too complicated (or even impossible) to implement a multi-threaded OpenGL driver, so they chose to add this strong constraint directly into the specification.

That makes sense, because like you say:
Quote
a strict alternation of the draw operations should be sufficient in my opinion

and in this case, multi-threading is useless.

Generally speaking, drawing in multiple threads is a bad idea and should be avoided if possible.
Laurent Gomila - SFML developer

kullerhamPster

  • Newbie
  • *
  • Posts: 40
    • View Profile
Drawing from within a thread
« Reply #9 on: January 02, 2009, 01:15:50 pm »
I found and interesting note on multithreading in Microsoft's documentation to wglmakecurrent:
http://msdn.microsoft.com/en-us/library/ms537558(VS.85).aspx

There they say that one can/should use a separate device and rendering context per thread. I don't know much about OpenGL, but I wonder if is possible to display more than one context at a time.

By the way: Both the documentation of wglMakeCurrent and glXMakeCurrent state that the rendering context of the calling thread is changed, which implies that the function knows which thread it called.
When I posted my question here yesterday, I thought this might be a problem, but I simply didn't think of the possibility that a thread library will likely offer a function to retrieve the current thread's id. As the OpenGL calls are performed in the context of the calling thread, it shouldn't be a problem to find out which thread it called.

Oh, and I hope you didn't misunderstand my previous posting: A strict alternation of function calls alone didn't work, I had to make the window active/inactive each time in the appropriate thread. I slowly start to believe that it is really something thread-specific and not only parallelism-specific ;)