OpenGL | macOS Big Sur

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
Ishtar
Experienced Solver
Experienced Solver
Posts: 78
Joined: Mon May 20, 2013 6:33 pm

OpenGL | macOS Big Sur

Post by Ishtar »

Details of my Setup
  • wxWidgets Version: 3.1.5 (compiled with the default macOS SDK)
  • wxWidgets Version: 3.1.4 (compiled with the default macOS SDK)
  • wxWidgets latest git hub sources (compiled with the default macOS SDK)
  • macOS Big Sur
  • Compiler: clang 12.0.5
I have also tried wxWidgets compiled with the High Sierra SDK (10.13) on Big Sur.

Details

My application makes extensive use of OpenGL in a different thread to the UI. Basically, I create a wxGLCanvas window in the main UI and then pass a pointer of that window into another class that is then run in a separate thread started by std::thread. Within that thread, I then create an instance of wxGLContext that is initialised with the wxGLCanvas and then I call SetCurrent() by using the wxGLCanvas pointer.

This works perfectly on Windows, Linux and macOS High Sierra. However, when compiled on Big Sur my application produces the following error:

Code: Select all

-[NSOpenGLContext setView:] must be called from the main thread.
I have tried creating an instance of wxGLContext and then call SetCurrent() in the main thread but this just results in a crash as soon as the first OpenGL call is made.

Interestingly, if I compile on High Sierra and then run the application on Big Sur, it works correctly.

Does anybody know how to solve this problem?

Many thanks
Amanda
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: OpenGL | macOS Big Sur

Post by ONEEYEMAN »

Hi,
Did you try to build OpenGL samples?
And why do need to operate OpenGL in a thread?

Thank you.
Ishtar
Experienced Solver
Experienced Solver
Posts: 78
Joined: Mon May 20, 2013 6:33 pm

Re: OpenGL | macOS Big Sur

Post by Ishtar »

The OpenGL samples work fine. The problems only arise when running in a thread.

My application is a scientific image capture application which renders 2D image buffers to a preview screen and also renders a histogram using OpenGL with frame rates that can exceed 500 frames per second.

It's multi-threaded for very good reasons. wxWidgets simply implements the UI controls (things like wxSliders, wxTextCtrl, wxComboBox etc) and all other functionality is threaded in order to keep the UI fully responsive and keep frame rates as high as possible especially when saving huge image buffers.

As I mentioned, my approach has worked perfectly until Big Sur and even then, if I compile on High Sierra (or using a macos cross-compiler on Linux) and run the resulting binary on Big Sur, it works as expected. The problems only occur when compiled on Big Sur. This implementation also works on Linux and Windows.

Further research (since posting) has shown that this problem is not unique to wxWidgets. It appears that Apple have made some changes to the runtime which demand that NSOpenGLContext setView is run in the main thread. It seems that SetCurrent() makes a call to NSOpenGLContext setView (which now must be called in the main thread) and that SetCurrent() must be run in the same thread as the GL functions.

Is it possible to call SetCurrent() from the main thread and sitll make OpenGL calls and SwapBuffers() from a worker thread?

I posted here in the hope that somebody might have a workaround to this problem, otherwise I will have to look at reimplementing the OpenGL functionality in Metal or even Vulkan together with MoltenVK, which I would really like to avoid.

Amanda
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: OpenGL | macOS Big Sur

Post by ONEEYEMAN »

Hi,
I think that this the limitations of the underlying OS.
Can you try to do those calls in the main thread and keep the algorithm otherwise intact?

Thank you.
Ishtar
Experienced Solver
Experienced Solver
Posts: 78
Joined: Mon May 20, 2013 6:33 pm

Re: OpenGL | macOS Big Sur

Post by Ishtar »

Thanks ONEEYEMAN,

Sadly, I think the same. I'm afraid that to put the OpenGL calls in the main thread would be a major refactor. I might have to reimplement the GL calls in Vulkan with the MoltenVK abstraction layer.

Thank you
Amanda
Manolo
Can't get richer than this
Can't get richer than this
Posts: 827
Joined: Mon Apr 30, 2012 11:07 pm

Re: OpenGL | macOS Big Sur

Post by Manolo »

This "gl-context vs main thread" is not new. OGL was not designed to work multithreaded externally. Internally it does a lot of multithreading, but you can not control it, unless you leave OGL and use Vulcan (or alike).
There is a mayor rule: Only a thread can be set as current to a gl-context. So far so good. What's the issue? OGL is designed for drawing, so it's pefectly logic that you associate a gl-context to a window. again, so far so good. The issue arises when not only OGL is using the screen, but the OS does. And likely the OS wants all drawing done by it to be done in the main thread. For example, user controls (sliders, textctrls, buttons, etc) created from a secondary thread will probably may the OS to complain.
This seems the case with Big Sur, only the main thread can draw (read: use the graphics card) despite it's OS or OGL drawing. And remember Apple has deprecated OGL, so don't expect any care in Mac's OGL implementation. I don't know if they keep this only-main-thread in Metal too.

Let's see if we can do all OGL stuff in the main thread, at least mostly.

If everything happens in a millisecond, there's not problem at all. If it takes too much time, we can suffer UI blocking due to some needed glFlush or glFinish command. And surely we may allow the user to cancel current rendering. And thus we start thinking of mulithreading.
There are four jobs: 1) Prepare data for the GPU. This can be done in a common working thread. 2) Transfer data to the GPU. 3) The GPU renders, no user control on this. 4) Display or transfer buffers from GPU to RAM.
Jobs 2 and 4 are where we can play some tricks.
We have some strategy points:

A) Don't submmit too many comands to the driver at once. Perhaps we can measure how long a group of commands takes to complete, so we can tell a "good number" of commands; and we use in a loop the sequence 'some commands' ==>> 'yield for UI' with some groups of commands. This will allow to cancel the sequence at any time.

B) Transfer data is optimized by using "buffer streaming". See https://www.khronos.org/opengl/wiki/Buf ... _Streaming and Chapter 28 of http://openglinsights.com/

C) If we need to know when a GPU-job is done, and we don't want to wait (blocking CPU thread) we can use a "fence" See https://www.khronos.org/opengl/wiki/Synchronization and https://www.khronos.org/opengl/wiki/Sync_Object
The trick is to use a timer in the main thread, let's say it fires every 0.17 seconds (moreless 60 fps). When the timer fires we use glClientWaitSync with a 'timeout' around 0.05 seconds and read its return. If it returns 'GL_TIMEOUT_EXPIRED' we know the GPU is still working and thus we'll check again in the next timer event; but in the while we are not blocking the CPU, just those 0.05 seconds.

You see, a fence can be used in many places, including buffer data transfers.
Ishtar
Experienced Solver
Experienced Solver
Posts: 78
Joined: Mon May 20, 2013 6:33 pm

Re: OpenGL | macOS Big Sur

Post by Ishtar »

For the benefit of anybody else having this problem. I have found a workaround which involves not using the Apple clang compiler.
  • Checkout and build the vanilla LLVM / clang sources
  • Use MacOS MacOSX10.14.sdk (for wxWidgets and build projects with -isysroot /path/to/sdk/MacOSX10.14.sdk
  • Build all dependencies (libtiff, libjpeg, libpng etc) with the new clang compiler
  • Build wxWidgets with the new clang compiler
  • Build your project with the new clang compiler
The above procedure allows SetCurrent() to be run in a worker thread together with all other OpenGL code (just like previous versions of macOS).

Amanda
Last edited by Ishtar on Fri Jun 04, 2021 1:40 am, edited 1 time in total.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: OpenGL | macOS Big Sur

Post by ONEEYEMAN »

Hi,
This definitely feels like a workaround.
And it deserve to be reported to Apple. But I doubt they will do anything.

Thank you.
Ishtar
Experienced Solver
Experienced Solver
Posts: 78
Joined: Mon May 20, 2013 6:33 pm

Re: OpenGL | macOS Big Sur

Post by Ishtar »

Thanks for your help in this thread ONEEYEMAN.

It's a bit hacky but at least it works. Well, until Apple make another change that breaks things again. Apple want everyone to recode to use Metal which is something that I'm not prepared to do. I'll keep my application working as long as possible and then reimplement in Vulkan when the time comes.
Post Reply