From ab03f010df7b78854433093030f08a81c059aa26 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 was that CoglBool can only count to one pending notification, so we just change that to an integer and count properly. --- 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 012c712bd..2cf6e95fc 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; - CoglBool pending_sync_notify; - CoglBool pending_complete_notify; - CoglBool 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; - CoglBool pending_sync_notify = glx_onscreen->pending_sync_notify; - CoglBool 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