summaryrefslogtreecommitdiffstats
path: root/src/loader
diff options
context:
space:
mode:
authorMichel Dänzer <[email protected]>2018-05-08 11:51:09 +0200
committerMichel Dänzer <[email protected]>2018-05-22 17:59:53 +0200
commitfe2edb25dd5628c395a65b60998f11e839d2b458 (patch)
treedf6a4c9e9bbde03c789b940f675e09069fb4b169 /src/loader
parent75e919c0454dcc759dce69c46717356980f18fd8 (diff)
dri3: Stricter SBC wraparound handling
Prevents corrupting the upper 32 bits of draw->recv_sbc when draw->send_sbc resets to 0 (which currently happens when the window is unbound from a context and bound to one again), which in turn caused loader_dri3_swap_buffers_msc to calculate target_msc with corrupted upper 32 bits. This resulted in hangs with the Xorg modesetting driver as of xserver 1.20 (older versions and other drivers ignored the upper 32 bits of the target MSC, which is why this wasn't noticed earlier). Cc: [email protected] Bugzilla: https://bugs.freedesktop.org/106351 Tested-by: Mike Lothian <[email protected]>
Diffstat (limited to 'src/loader')
-rw-r--r--src/loader/loader_dri3_helper.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index 6db8303d26d..f0ff2f07bde 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -370,9 +370,17 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
* checking for wrap.
*/
if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
- draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
- if (draw->recv_sbc > draw->send_sbc)
- draw->recv_sbc -= 0x100000000;
+ uint64_t recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
+
+ /* Only assume wraparound if that results in exactly the previous
+ * SBC + 1, otherwise ignore received SBC > sent SBC (those are
+ * probably from a previous loader_dri3_drawable instance) to avoid
+ * calculating bogus target MSC values in loader_dri3_swap_buffers_msc
+ */
+ if (recv_sbc <= draw->send_sbc)
+ draw->recv_sbc = recv_sbc;
+ else if (recv_sbc == (draw->recv_sbc + 0x100000001ULL))
+ draw->recv_sbc = recv_sbc - 0x100000000ULL;
/* When moving from flip to copy, we assume that we can allocate in
* a more optimal way if we don't need to cater for the display