When responses to window refresh take too long

I would like to check if my understanding is right.

When I run GLFW with OpenGL on Linux, I have to respond to “refresh” (or “move” /"resize) callbacks to repaint the window. If I don’t do this in a timely manner, I get flicker or corrupt looking contents. If I am running a single threaded app and my response takes too long, maybe the drawing is too slow and exceeds the screen refresh rate, then flicker is unavoidable. This seems basic, but I could be overlooking something. But if this is true, this would mean, that for slow redraws I must be using some multi-threaded setup. Is this true ?

Hi & welcome to the GLFW forums!

Please take a look at the example code in the documentation, along with the GLFW examples the GLFW CMake Starter. This shows the basics of a GLFW application.

From these you’ll notice that you don’t need to respond to “refresh” or “resize” callbacks - the application should run a render loop calling either glfwPollEvents if you want to animate/redraw without waiting for input or glfwWaitEvents if you want to wait for input before re-drawing.

You shouldn’t get flickering if your render time is longer than the refresh time, because OpenGL draws to a backbuffer whilst the front buffer is being displayed, then swaps these when glfwSwapBuffers is called.

Very well, lets use the “boing.c” demo as an example. When I put in a delay before the glfwSwapBuffers(window); and resize the window, I get a lot of flicker.

       /* Swap buffers */
          struct timespec  delay = { 0, 1 / 60.0 * 1000L * 1000 * 1000 };
          nanosleep( &delay, NULL);

To me that’s not unexpected as I wrote in the initial question.

The resize is done by the window manager on linux (a separate process) My understanding is that it’s up to the app to provide the window contents in a timely manner (what timely is exactly I don’t know). The framebuffer size is different due to the resize, so a new framebuffer must be filled with contents. As I see black in the flicker, I assume the old framebuffer has been invalidated and cleared already.

During resizing the exact behaviour of the backbuffer is presented depends on the OS/Window Manager/Driver and this isn’t something developers have explicit control over, so if you are unable to render during resizing there could indeed be some issues. Note that on Win32 there is currently an open issue with being able to process messages during a resize, as Windows blocks the message queue during this operation:

If your rendering is too slow, multithreading won’t help alleviate any of these issues.

So we agree, that flicker is unavoidable during resize in a single threaded scenario, if the drawing code takes too long. We disagree on whether that’s fixable with threads, but that’s OK!

What would be interesting to know, if it’s possible to determine the amount of time available for the redraw. For example one might assume, that glfwSwapInterval(1); guarantees one frame worth of time.

But if the resize message from the OS could arrive towards the end of the frame, it would reduce the available render time. I would like to learn about real life experiences and solutions. Other OpenGL programmer must have run into this ?!

When I originally stated You shouldn’t get flickering if your render time is longer than the refresh time I should have clarified this was if your window size was constant.

Flickering is not quite ‘unavoidable’ since the OS/Window Manager/Driver may not exhibit this (it could for example rescale the content). Additionally I would not describe what I’ve seen as flickering, but this is somewhat subjective.

glfwSwapInterval(1) does not guarantee that the rendering will take one frame - it requests that the buffer swap does not occur immediately on render completion but when the next display refresh occurs. So with 60Hz refresh if your rendering takes longer than 1/60s (~16ms) then you get the buffer swapping at the next refresh time of 2/60s or 30Hz. However, when running in a window some OS/Window Manager/Driver combinations do not honor refresh rate requests.

If your rendering is slower than your refresh rate then you will have frames during resizing where the window size is not equal to the last rendered framebuffer size, which will potentially produce visual issues. To resolve these you need your rendering to be faster than the refresh rate to start with, at which point multithreading the rendering and event loop may help reduce the residual issues which remain due to input timing.

In my case I simply ignore this issue - if the user is resizing or moving the window they are not interacting with the content so I don’t worry about it. For fullscreen OpenGL apps this obviously also isn’t an issue.

I spent a little bit of time looking into tears during window resizing when using GLFW on Linux with the Intel Mesa driver. I started exploring the extended frame synchronization protocols that have been designed to solve this. I have written a small sample along with documentation that may make it easier to implement GLX XSync extended frame synchronization when using the GLX-based Window system in GLFW. It has so far had testing with NVIDIA on Xorg and Intel on XWayland:

This email to the Mesa Developers mailing list goes into the background behind the sample:

I would consider making patches for GLFW but would like to know if the approach is reasonable first. The reason to make something freestanding and isolated was so that it was easier to debug as it seem easy to get flickers with the Intel Mesa driver if the timing is not just right. I think once the approach is workable it should not be too hard to integrate with GLFW. I am not sure if there is a bug in the issue tracker where one could add these notes or it is appropriate to discuss here.

Thanks for this sample work & information!

In future I would recommend starting a new thread (with a link to this one) or a new Github issue for feedback of this type.

I know @mmozeiko has been working on an improved Win32 resize event handling PR, and the design of that may have some bearing on your proposal.

From reading your sample and notes I am personally unable to tell exactly how the PR would work within GLFW's current design without a good deal more time to read it through. The main issue I see is that your event loop directly handles frame rendering via the submit_frame function, whereas GLFW has no such render callback - client code handles when and how to render and rendering can be on a secondary thread. I am also concerned about potential performance and latency related issues for applications which care less about resizing causing flickering than they do about performance when the window size is fixed (for example games).

One consideration is how much of the sample requires exposure in GLFW code, and how much can be exposed for client code to decide how to use the information. For example, an API which allows the application to synchronize during window resizing along with example code would in my view a better approach than ‘builtin’ GLFW synchronization, although making this workable in a cross platform way needs consideration.

Thanks for getting back to me. I will take a look at the resize handling PR.

I think the event loop and submit_frame in the example should be able to be abstracted to use glfwWaitEventsTimeout and regular draw calls. As long as we can poll with a timeout I think it should work. We have control over the event loop. The glxsync sample is quite deliberately hardcoded because the intention was to isolate the concern so there were no function pointer indirections to reason about while testing as it took quite a bit of iteration to figure out exactly which events were needed and how they should be handled.

The compositor resize sync events need some consideration as to how they would be exposed (or not exposed). It could be via calls to refresh where the frame sync locking magic is done behind the scenes. It actually amounts to locking around swap buffers and some serial numbers from the window manager events. It could suffice to allow a user to hook swap buffers with a before and after callback but ideally, one could hide frame sync from the user altogether and expose it simply as a Hint to enable it (off by default) and the frame sync locking added around refresh callbacks and swap_buffers if it is enabled.

See this patch where I made a small change after reasoning about the frame sync locking as I added some docs describing the events and locking at each stage, subject to verification of course:

Note that most applications will likely be using glfwPollEvents which does not wait. Applications could combine this with glfwWaitEventsTimeout when the window is resizing, but currently GLFW only has an API for window resize events which indicate a size has changed, not that it has started/stopped changing so managing this is complex.

Frame sync locking via a hint sounds a valid solution, especially if it only applies during resizing. This could be done within glfwSwapBuffers so the only API to expose would be the hint, and as a hint it’s reasonable that some OS’s either wouldn’t need or be able to honour it.