Seeing loss of frame sync on 8K display on one quadrant on Linux but not Windows

I’ve got an application that draws 21 textured rectangles in a 7x3 array on a sphere around the user. When I look far left and down on an 8K display at 60Hz under Linux, one quadrant of the display gets a frame ahead of the other three. If I look left, the lower-right quadrant. If I look right, the lower-left quadrant. Driver 550 on Linux (also an earlier one, probably 535). Does not happen on Windows driver using the same code base. Does not happen when displaying 4K 240 Hz. Happens whether or not another display is plugged in. HDMI 2.1 single cable. It feels a lot like the system is internally rendering 4 tiles and then sending them to the display and not ensuring that all four are from the same frame. OpenGL, GLFW, (some CUDA mixed in for texture filtering but this happens even when CUDA is not operating because I’ve paused the video). Ubuntu 23.10 and 22.04 both behave this way.

It happens on both fullscreen and decorated windows. It happens with and without double buffering (the rendering waits until 2.5ms before vertical retrace to render).

On further observation, it sometimes moves above the bottom half of the screen, so it appears to be screen halves rather than quarters, where one half tears and the other does not.

glFinish() is being called after glfwSwapBuffers() to ensure that we wait for all rendering to complete for one frame before moving on to the next (and we’re also waiting until near retrace). There is only one rendering thread.

The side with more pixels landing on it is the one whose lower portion gets ahead of both its upper portion and the other half of the screen. The more imbalance, the larger the fraction of the half that gets ahead. Reducing the FOV of the virtual camera reveals that this imbalance may be per-mesh rather than global (it happens on a mesh that is surrounded by other meshes such that some mesh is showing on the whole screen).

The following call is used to set the viewProjection matrix, which is one thing that differs between the older and newer regions of the screen: glUniformMatrix4fv(m_viewProjectionUniformId, 1, GL_FALSE, viewProjection); that call is made once and then each mesh is drawn with its own precomputed (and unchanging) coordinates in that same space. The vertex shader multiplies the incoming aPos by this matrix to produce gl_Position. This is not the only thing that changes – when the texture ID changes due to video updating it also has the new video in the region that is ahead – the whole rendering gets one frame ahead in that region.

I’ve added a single-file reproduction example that can be built using CMake. The repository includes a video showing the behavior in action. GitHub - ReliaSolve/Reproduce_8K_Tearing

The versions tried were 23.10 and 24.04, not 22.04