dri: avoid sending too many present reuqests when app start or pause
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

Found when running glxgears with vblank enabled and modesetting DDX.
glxgears will send many present requests at the beginning, but most
of them get complete event with skip mode. This problem causes
glxgears report ~75fps on a 60Hz monitor at the first record.
This change reduces it to 60fps.

Vulkan side X11 WSI does not have this problem as it will wait first
present request's complete event before send second present request.

How the problem happens:
1. client send present request 1 with target msc = 1
2. server side current msc is 100, so it find request 1 is
   outdated and queue it for vblank with target msc = 101
3. client send present request 2 with target msc = 2
4. server side current msc is still 100, so it find request 2
   is outdated and queue it with target msc = 101, and find
   request 1 will be overridden, so mark it as skipped and
   send idle notify for it.
5. client get the idle notify for request 1, and reuse the
   request 1 buffer for new back buffer to send present
   request 3.
6. this keeps going until client send present request N, and
   server finally process the vblank queue before 101 msc
   arrive and send complete event for all these requests back
   to client.

Reviewed-by: Michel Dänzer <michel@daenzer.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38178>
This commit is contained in:
Qiang Yu 2025-10-31 10:45:59 +08:00
parent 198537039a
commit a6bf07e7c2
3 changed files with 27 additions and 6 deletions

View file

@ -1091,10 +1091,35 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
* semantic"
*/
++draw->send_sbc;
if (target_msc == 0 && divisor == 0 && remainder == 0)
if (target_msc == 0 && divisor == 0 && remainder == 0) {
/* Wait for previous send present request gets its complete event
* to update the window msc before send next present request.
*
* This is to prevent we send too many present requests before we
* get an up to date msc value from server when application
* start or pause for a while. Otherwise most of the sent
* request will be wasted as server just use the latest one and
* skip all the previous ones before a vblank. This also match the
* swap behavior for interval != 0.
*
* For example, client side window msc is 0 at the beginning,
* when swap interval=1, we will send present request with target
* msc = 1, 2, 3, ..., N, before server send back the complete
* event for target msc = 1.
*
* But server side window msc is way bigger than N, so it will
* think all these present requests are outdated and just show the
* Nth request at the next vblank. [1 .. N-1] requests are skipped.
*/
if (draw->swap_interval != 0) {
while (draw->recv_sbc + 1 != draw->send_sbc) {
if (!dri3_wait_for_event_locked(draw, NULL))
break;
}
}
target_msc = draw->msc + abs(draw->swap_interval) *
(draw->send_sbc - draw->recv_sbc);
else if (divisor == 0 && remainder > 0) {
} else if (divisor == 0 && remainder > 0) {
/* From the GLX_OML_sync_control spec:
* "If <divisor> = 0, the swap will occur when MSC becomes
* greater than or equal to <target_msc>."

View file

@ -57,8 +57,6 @@ spec@arb_texture_rg@fbo-blending-formats@GL_RG8,Fail
spec@arb_texture_rg@fbo-blending-formats@GL_RG,Fail
spec@arb_transform_feedback_instanced@draw-auto instanced,Fail
spec@egl 1.4@eglterminate then unbind context,Fail
spec@egl_chromium_sync_control@conformance@eglGetSyncValuesCHROMIUM_msc_and_sbc_test,Fail
spec@egl_chromium_sync_control@conformance,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_rgba,Fail
spec@egl_khr_surfaceless_context@viewport,Fail

View file

@ -211,8 +211,6 @@ spec@arb_texture_rg@fbo-blending-formats@GL_RG,Fail
spec@arb_transform_feedback_instanced@draw-auto instanced,Fail
spec@egl 1.4@egl-ext_egl_image_storage,Fail
spec@egl 1.4@eglterminate then unbind context,Fail
spec@egl_chromium_sync_control@conformance@eglGetSyncValuesCHROMIUM_msc_and_sbc_test,Fail
spec@egl_chromium_sync_control@conformance,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_rgba,Fail
spec@egl_khr_surfaceless_context@viewport,Fail