processMessages() on different thread than update()

Started by SmashMaster, October 07, 2013, 18:51:20

Previous topic - Next topic

SmashMaster

It's a pretty standard model in the industry to have a game's logic and input run at 60hz, and render on a separate thread at whatever frame rate it needs to. Ideally, the game runs at 60hz no matter what, even if it's being rendered at 5 fps. This alleviates the dual problems of variable time step and input latency.

This is also a good idea because OpenGL calls block until the graphics card finishes doing whatever it's told. After any needed data is supplied, the CPU isn't doing anything but waiting.

So here's what I'm trying to do:

Thread A: Main; rendering back end
while (running)
{
    render(); //Have renderer perform jobs supplied by front end.

    Display.update(false);
    Display.sync(60);
}


Thread B: Game logic, rendering front end
while (running)
{
    Display.processMessages();
    
    while (Mouse.next()) mouseInput();
    while (Keyboard.next()) keyboardInput();

    step(); //Do game logic.
    sync(60); //Synchronize using something other than Display.sync();
}


processMessages() does nothing, events are never buffered. It doesn't even block, it just does nothing. Display.update() works fine, the buffer is swapped and rendering happens. It seems that Display ignores any calls from a thread other than the one that called create(). Looking at the source for Display, I see no reason there should be synchronization between swapBuffers() and processMessages(), but everything is on one global lock for some reason.

So, how do I make this work?

spasi

Quote from: SmashMaster on October 07, 2013, 18:51:20It seems that Display ignores any calls from a thread other than the one that called create().

This is not an LWJGL limitation. Different OSes have different limitations related to this, but e.g. on Windows the behavior is exactly what you're seeing. The thread that created a window is the only thread that can receive events for it.

So, if you can't move Display.create and Display.processMessages in different threads, you'll have to move the OpenGL context. You can achieve that by creating the window on the main thread and then calling Display.makeCurrent() on the rendering thread.

I understand this may be a bit confusing and unclear in LWJGL currently. LWJGL 3.0 is going to make such issues explicit and you'll have much more control where possible.

SmashMaster

Quote from: spasi on October 07, 2013, 19:45:45
You can achieve that by creating the window on the main thread and then calling Display.makeCurrent() on the rendering thread.

Works perfectly, thank you. I just ran some tests, and this multithreading scheme is everything I hoped for. I'm getting input at 60Hz while rendering at 1 FPS and lower.