-=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- (c) WidthPadding Industries 1987 0|511|0 -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=-
SoCoder -> Article Home -> Graphics 3D


 
Cower
Created : 18 February 2013
Edited : 18 February 2013
System : Mac
Language : Monkey

Using GLFW with libdispatch on OS X

How to properly use GLFW with libdispatch on OS X

One of the benefits of using GLFW is that it largely strips out a lot of the work you'd need to do on OS X to create a GL window and so on (this isn't a large amount of work, granted, but it's boilerplate crap nobody likes doing). Unfortunately, libdispatch doesn't play nice with it or really any other UI library without knowing a little about how OS X does windowing and how libdispatch expects you to do things.

When creating an application that uses libdispatch, your first instinct might be to queue up a task that would otherwise contain the entry point/initialization routine of your program and call dispatch_main() to give the process over to libdispatch. This works extremely well for command-line utilities where you don't need to know anything but you do need to work with the main queue (if you're not using the main queue, you don't need to call dispatch_main(), but this is unlikely in game dev). This doesn't work well in other scenarios because dispatch_main terminates thread zero, the thread OS X expects all UI code to run on. So, it plays hell with OS X and, as a result, also screws with GLFW.

The trick is to keep the main queue on thread zero. The downside is this requires a little platform-specific code. Specifically, you'll want to use Cocoa's NSRunLoop to kick off the application's main run loop, which will in turn receive events and process the main dispatch queue. This is as simple as calling [NSRunLoop mainRunLoop] run]. You may also be able to use CFRunLoopRun(), but I recommend using Cocoa instead of Core Foundation where possible (it makes life easier).

So, with the NSRunLoop working, your next instinct might be to again throw your initialization task on the main queue and begin your frame loop in that task, but that would then block the main queue, which you'll need in order to poll for events and so on. Instead, you want to create a new thread for your frame loop, then using libdispatch, create tasks on the main thread to poll for events as needed. Make note of what has to be done on the main thread and push that off to tasks run on the main thread.

Once the frame loop thread has started, you can leave your init code and let the main queue handle whatever it needs to via the NSRunLoop. This includes windowing, events, and so on that your frame loop can blissfully ignore until it's needed. In other words, it prevents the UI from blocking game logic except where needed and it prevents game logic from blocking the UI. Most everything ends up being relatively lag-free.

Your frame loop can then handle input, rendering, and whatever else. Note that you do not have to do rendering on the frameloop thread. You might want to create a serial queue specifically for working with OpenGL, thereby allowing your rendering and game logic to run concurrently without blocking one another. You'll also need to create a thread-safe way to send events to the frame loop thread, but that's easy enough and makes it a lot safer to work with GLFW events (without worrying about callback restrictions). I've already done all that, so it's not hard, especially given what libdispatch lets you do to simplify synchronization.

Because I'm crap at explaining all this, however, I've also included the source code for a very bare-bones main source file using libdispatch and GLFW 3.0 on OS X. This code sample requires a C++11 compiler. I use Clang and libc++, but really the most prevalent compilers now should support enough of C++11 for this. The sample also assumes you are defining TARGET_OS_MAC and passing -ObjC++ (so you can make use of ObjC features) in your compiler flags.

Code sample on gist.github.com

And for those wondering how to handle using libdispatch on other operating systems, you might want to check out xdispatch, which ports it to other OSes. Granted, the other OSes won't have the same performance as OS X and the BSDs since they lack kqueue, which allows all of this to be done very, very quickly. Still, it's a handy tool and something to keep in mind.

 

Comments


Tuesday, 05 March 2013, 06:16
caligula
I'm trying to piece together the different submissions you've made here recently: stuff about Lua, 3D maths, GLFW, a bitmap font generator -- is there perhaps a game in the making?

Anyways, it's cool that there's at least someone who's still posting articles and snippets on SoCoder. I've never had to deal with GLFW and libdispatch, but the day I do I'll keep in mind that there's an article about it here.
Tuesday, 05 March 2013, 16:38
Cower
I'm working on a game but it's rather slow in the making since I've rebooted the thing about eighty times now. In the meantime, I've just been releasing chunks of it that might be useful in other projects (e.g., SnowCommon and sbfgen).