OpenGL and threads on linux Topic is solved

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

OpenGL and threads on linux

Post by RobertSimpson »

I'm porting a GL app from windows to linux and running into some problems. The app uses two threads. The main thread handles all the UI (window creation, events etc.) and the 2nd thread has the main app and all GL calls. The UI thread forwards commands to the GL thread via a thread-safe fifo (so I effectively have message passing). This works fine on windows but on linux (Ubuntu 11.10) it fails when the wxGLContext is created.

I added a call to XInitThreads() in wxApp::OnInit() before the wxFrame is created. It returns '1' indicating success but the app still hangs.

Running the wxGLContext constructor code (I can't yet seem to step into the code) shows that the glCCreateNewContext is failing:

Code: Select all

GLXFBConfig *fbc = canvas->GetGLXFBConfig(); // returns fbc = 0x833360 which looks ok to me
_XDisplay* display = wxGetX11Display();

GLXContext m_glContext = glXCreateNewContext( display, fbc[0], GLX_RGBA_TYPE, None, GL_TRUE ); // hangs in linux
To check I wasn't attempting something that was impossible, I created a simple app using glX and pthreads (no wxWidgets). The GL thread is:

Code: Select all

void* ThreadEntry (void* ptr)
{
  Thread_Params* params = (Thread_Params*)(ptr);
  
  Display* display      = params->display;
  Window x_window       = params->x_window;
  GLXFBConfig fb_config = params->fb_config;
  
  GLXContext context = glXCreateNewContext (display,
                                            fb_config,
                                            GLX_RGBA_TYPE,
                                            NULL,
                                            True);

  // Create a GLX window to associate the frame buffer configuration with the created X window
  GLXWindow glx_window = glXCreateWindow (display, fb_config, x_window, NULL);

  glXMakeContextCurrent (display, glx_window, glx_window, context);

  /* OpenGL rendering ... */
  glClearColor( 1.0, 1.0, 0.0, 1.0 );
  glClear( GL_COLOR_BUFFER_BIT );

  glFlush();
  
  glXSwapBuffers (display, glx_window);
}
This runs perfectly on linux.

In the original wx app, moving the GL initialization into the main thread also works ok. I have a few GL apps running in wx on Ubuntu no problem.

The Ubuntu graphics is GL4.1 on an Nvidia GT430 card. wx is 2.9.2 (both windows and linux)
DavidHart
Site Admin
Site Admin
Posts: 4254
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Re: OpenGL and threads on linux

Post by DavidHart »

Hi Robert,

wxGTK seems much more sensitive than wxMSW to worker threads directly touching the gui thread. Apparently this is true even when using mutexes and such. There are also non-obvious things that appear to 'touch' the gui thread. (I'm reporting what others have found; I'm glad to say I've not had to do this sort of thing myself :) .)

I suggest you make absolutely sure that any worker -> gui thread communication happens using wxPostEvent, or the similar new things in wx2.9.

Regards,

David
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

Thanks for the info David. Under GTK, it seems to be very difficult to know when the GUI is doing something.

I've now modified the app so that the wxGLContext isn't created in the GL thread until the 1st PAINT message has been received. It still crashes but the error is more explicit:

[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
<appname>: ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.

I do have the XInitThreads call. It's right here:

Code: Select all

bool MyApp::OnInit()
{
	int result = XInitThreads ();
Interestingly the app window is displayed (grey background) but there's no menu. So maybe GTK hasn't completely finished creating the window. Adding a wxSleep(4) before the wxGLContext is created results in the menu appearing but then it still crashes with the same error.

I assume what is happening here is that is the wxGLContex and GUI operations are being sent to the X server at the same time and so the X server receives an invalid command sequence. The question is how to stop that happening.
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

A few other things I've tried:

I moved the GL context creation into the main thread but kept the SetCurrent (which calls glXMakeCurrent) in the 2nd thread. Unfortunately, that just causes SetCurrent to hang.

I installed the X11 version of wx. That also fails but it's much easier to see what is going on. When the glXMakeCurrent call hangs, the main thread is in the event loop in _XReadEvents while the 2nd thread is in _XReply, presumably trying to talk the the X server at the same time. I'm not at all surprised this isn't working but I'm still not sure what to do about it.

I did try moving the MakeCurrent into the main thread but then I can't get anything to render. I'll investigate that further. Update: this is disallowed by the GL spec. Contexts are bound to threads so can't be used in another thread.
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

It appears to be supported in Qt. Is there any chance it could be included in a future wx release?

http://doc.trolltech.com/qq/qq06-glimps ... plications
beck
In need of some credit
In need of some credit
Posts: 1
Joined: Wed Apr 27, 2005 8:17 am

Re: OpenGL and threads on linux

Post by beck »

Dear Robert,

I had similiar problems long ago. The problems IMHO seems to be creating a new GLContext while the App isnt fully initialized. You may try to prevent the GL-part to Init or process any events while its not finished initializing itself. For example at app start you set "done_init = false;" at the first line of your code in OnInit(), and only towards the end of the OnInit() set it to true. Right after this line send some init-event to your GL-thread (I do a wxSizeEvent). In your GL part first statement in all Event- or Init-routines should be an "if(!wxGetApp()->done_init)return;" statement.

Regards,
Bernhard
ptriller
In need of some credit
In need of some credit
Posts: 1
Joined: Wed Feb 01, 2012 10:49 am

Re: OpenGL and threads on linux

Post by ptriller »

Hi

calling XInitThread in OnInit is too late, you have to call it in the Constructor of your wxApp, or you will get some uninitialized mutexes,

also you have to use a wxMutexGuiLocker wround the "SwapBuffer" call or you will get extremely slow framerates because it will hang until the next gui event.
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

beck wrote:Dear Robert,

I had similiar problems long ago. The problems IMHO seems to be creating a new GLContext while the App isnt fully initialized. You may try to prevent the GL-part to Init or process any events while its not finished initializing itself. For example at app start you set "done_init = false;" at the first line of your code in OnInit(), and only towards the end of the OnInit() set it to true. Right after this line send some init-event to your GL-thread (I do a wxSizeEvent). In your GL part first statement in all Event- or Init-routines should be an "if(!wxGetApp()->done_init)return;" statement.

Regards,
Bernhard
Hi Bernhard. I believe I am delaying the context creation until after app initialization. I have an 'is_initialized' flag and do the initialization on the 1st paint. It's possible the 1st paint is being sent before initialization is complete. I'll check that.

I have since spoken to developers working on other linux platforms and they tell me they use a command fifo to send GL commands back to the UI thread so that all GL is done in the main thread. Given that GL works asynchronously (i.e. doesn't block on API calls), I'm wondering if I should have done this in the first place. Longer term I'm hoping we'll get proper multi-threading support in GL.
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

ptriller wrote:Hi

calling XInitThread in OnInit is too late, you have to call it in the Constructor of your wxApp, or you will get some uninitialized mutexes,

also you have to use a wxMutexGuiLocker wround the "SwapBuffer" call or you will get extremely slow framerates because it will hang until the next gui event.
Interesting. I'll definitely try that and report back (will be in a couple of weeks though).

Thanks,

Rob.
RobertSimpson
Experienced Solver
Experienced Solver
Posts: 88
Joined: Sat Oct 18, 2008 8:32 pm

Re: OpenGL and threads on linux

Post by RobertSimpson »

ptriller wrote:Hi

calling XInitThread in OnInit is too late, you have to call it in the Constructor of your wxApp, or you will get some uninitialized mutexes,

also you have to use a wxMutexGuiLocker wround the "SwapBuffer" call or you will get extremely slow framerates because it will hang until the next gui event.
Putting XInitThread in the constructor solved it. Yes, I can see the problem with SwapBuffer! I've since tried the app on Mac OSX and it worked without any problems so I assume this issue is specific to GTK.

Many thanks!

Rob.
Post Reply