From 6d8d73beeef3a618c553e89b0b3e532ec3654a30 Mon Sep 17 00:00:00 2001 From: Daniel van Vugt Date: Mon, 23 Jul 2018 16:28:56 +0800 Subject: [PATCH] cogl-winsys-glx: Fix frame notification race/leak If a second `set_{sync,complete}_pending` was queued before the idle handler had flushed the first then one of them would be forgotten. It would stay queued forever and never emitted as a notification. This could happen repeatedly causing a slow leak. But worse still, `clutter-stage-cogl` would then have `pending_swaps` permanently stuck above zero preventing the presentation timing logic from being used. The problem is that a boolean can only count to one, but in some cases (triple buffering, whether intentional or accidental #334) we need it to count to two. So just change booleans to integers and count properly. https://gitlab.gnome.org/GNOME/mutter/merge_requests/216 --- cogl/cogl/winsys/cogl-winsys-glx.c | 58 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c index 2623d02c6..235cfe81f 100644 --- a/cogl/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/cogl/winsys/cogl-winsys-glx.c @@ -99,9 +99,9 @@ typedef struct _CoglOnscreenGLX CoglOnscreenXlib _parent; GLXDrawable glxwin; uint32_t last_swap_vsync_counter; - gboolean pending_sync_notify; - gboolean pending_complete_notify; - gboolean pending_resize_notify; + uint32_t pending_sync_notify; + uint32_t pending_complete_notify; + uint32_t pending_resize_notify; GThread *swap_wait_thread; GQueue *swap_wait_queue; @@ -347,35 +347,35 @@ flush_pending_notifications_cb (void *data, { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreenGLX *glx_onscreen = onscreen->winsys; - gboolean pending_sync_notify = glx_onscreen->pending_sync_notify; - gboolean pending_complete_notify = glx_onscreen->pending_complete_notify; - /* If swap_region is called then notifying the sync event could - * potentially immediately queue a subsequent pending notify so - * we need to clear the flag before invoking the callback */ - glx_onscreen->pending_sync_notify = FALSE; - glx_onscreen->pending_complete_notify = FALSE; - - if (pending_sync_notify) + while (glx_onscreen->pending_sync_notify > 0 || + glx_onscreen->pending_complete_notify > 0 || + glx_onscreen->pending_resize_notify > 0) { - CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos); - - _cogl_onscreen_notify_frame_sync (onscreen, info); - } + if (glx_onscreen->pending_sync_notify > 0) + { + CoglFrameInfo *info = + g_queue_peek_head (&onscreen->pending_frame_infos); - if (pending_complete_notify) - { - CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos); + _cogl_onscreen_notify_frame_sync (onscreen, info); + glx_onscreen->pending_sync_notify--; + } - _cogl_onscreen_notify_complete (onscreen, info); + if (glx_onscreen->pending_complete_notify > 0) + { + CoglFrameInfo *info = + g_queue_pop_head (&onscreen->pending_frame_infos); - cogl_object_unref (info); - } + _cogl_onscreen_notify_complete (onscreen, info); + cogl_object_unref (info); + glx_onscreen->pending_complete_notify--; + } - if (glx_onscreen->pending_resize_notify) - { - _cogl_onscreen_notify_resize (onscreen); - glx_onscreen->pending_resize_notify = FALSE; + if (glx_onscreen->pending_resize_notify > 0) + { + _cogl_onscreen_notify_resize (onscreen); + glx_onscreen->pending_resize_notify--; + } } } } @@ -417,7 +417,7 @@ set_sync_pending (CoglOnscreen *onscreen) NULL); } - glx_onscreen->pending_sync_notify = TRUE; + glx_onscreen->pending_sync_notify++; } static void @@ -440,7 +440,7 @@ set_complete_pending (CoglOnscreen *onscreen) NULL); } - glx_onscreen->pending_complete_notify = TRUE; + glx_onscreen->pending_complete_notify++; } static void @@ -533,7 +533,7 @@ notify_resize (CoglContext *context, NULL); } - glx_onscreen->pending_resize_notify = TRUE; + glx_onscreen->pending_resize_notify++; if (!xlib_onscreen->is_foreign_xwin) { -- 2.18.1