From e55e61758c704f79fa6634bfdcd7563330d68060 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Fri, 24 Sep 2021 15:47:50 +0800 Subject: [PATCH] loader/dri3: fix swap out of order when changing swap interval MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This fixes SPECVIEWPERF13 creo test case hang: 1. Client: send present pixmap request (serial=1) when swap_interval==1 and increase send_sbc=1 2. Server: pend the request before vblank arrives 3. Client: set swap_interval=0 (so set XCB_PRESENT_OPTION_ASYNC), send another present pixmap request (serial=2), increase send_sbc=2 4. Server: handle the async request immediately and send complete event (serial=2) 5. Client: handle the event and set recv_sbc=event->serial=2 6. Server: vblank arrives so handle pending request and send complete event (serial=1) 7. Client: handle the event and set recv_sbc=event->serial=1 8. Client: someone call loader_dri3_swapbuffer_barrier() and waiting on recv_sbc==send_sbc, but no one will set recv_sbc=2 again So basically it's caused by swap happens out of order. This commit fixes the problem by waiting on the pending sync swaps all done when switching to async mode, so move 6&7 before 3. Attach the xtrace when problem happens: 005:<:003e: 72: Present-Request(148,1): Pixmap window=0x03000002 pixmap=0x0300000b serial=1 valid=0x00000000 update=0x00000000 x_off=0 y_off=0 target_crtc=0x00000000 wait_fence=0x00000000 idle_fence=0x0300000c options=0 target_msc=4294967296 divisor=0 remainder=0 notifies=; ... 005:<:0041: 72: Present-Request(148,1): Pixmap window=0x03000002 pixmap=0x03000011 serial=2 valid=0x00000000 update=0x00000000 x_off=0 y_off=0 target_crtc=0x00000000 wait_fence=0x00000000 idle_fence=0x03000012 options=Async target_msc=0 divisor=0 remainder=0 notifies=; 005:>:0041: Event Generic(35) Present(148) IdleNotify(2) event=0x03000006 window=0x03000002 serial=2 pixmap=0x03000011 idle_fence=0x03000012 005:>:0041: Event Generic(35) Present(148) CompleteNotify(1) kind=Pixmap(0x00) mode=Copy(0x00) event=0x03000006 window=0x03000002 serial=2 ust=7505462213117739011 msc=3565046193979392 005:>:0041: Event Generic(35) Present(148) IdleNotify(2) event=0x03000006 window=0x03000002 serial=1 pixmap=0x0300000b idle_fence=0x0300000c 005:>:0041: Event Generic(35) Present(148) CompleteNotify(1) kind=Pixmap(0x00) mode=Copy(0x00) event=0x03000006 window=0x03000002 serial=1 ust=7505533793042694147 msc=3565050488946688 Cc: mesa-stable Reviewed-by: Michel Dänzer Signed-off-by: Qiang Yu Part-of: --- src/loader/loader_dri3_helper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index e808bcf..fc043bd 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -317,6 +317,20 @@ dri3_update_max_num_back(struct loader_dri3_drawable *draw) void loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) { + /* Wait all previous swap done before changing swap interval. + * + * This is for preventing swap out of order in the following cases: + * 1. Change from sync swap mode (>0) to async mode (=0), so async swap occurs + * before previous pending sync swap. + * 2. Change from value A to B and A > B, so the target_msc for the previous + * pending swap may be bigger than newer swap. + * + * PS. changing from value A to B and A < B won't cause swap out of order but + * may still gets wrong target_msc value at the beginning. + */ + if (draw->swap_interval != interval) + loader_dri3_swapbuffer_barrier(draw); + draw->swap_interval = interval; } -- 2.7.4