summarylogtreecommitdiffstats
path: root/216.patch
blob: ee92895446d8ee0912341c43f3808af115e3ba54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
From 6d8d73beeef3a618c553e89b0b3e532ec3654a30 Mon Sep 17 00:00:00 2001
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
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