MetaRendererNative: Flush all pending swap notifies on idle
authorRui Matos <tiagomatos@gmail.com>
Mon, 5 Dec 2016 18:18:24 +0000 (19:18 +0100)
committerAndreas Henriksson <andreas@fatal.se>
Sun, 8 Jan 2017 02:12:13 +0000 (02:12 +0000)
We need to do swap notifications asynchronously from flip events since
these might be processed during swap buffers if we are waiting for the
previous frame's flip to continue with the current.

This means that we might have more than one swap notification queued
to be delivered when the idle handler runs. In that case we must
deliver all notifications for which we've already seen a flip event.

Failing to do so means that if a new frame, that only swaps buffers on
such a swap notification backlogged Onscreen, is started, when later
we get its flip event, we'd notify only an old frame which would hit
this MetaStageNative's frame_cb() early exit:

  if (global_frame_counter <= presented_frame_counter)
    return;

and we'd never finish the new frame and thus clutter's master clock
would be waiting forever stuck.

https://bugzilla.gnome.org/show_bug.cgi?id=774557

Gbp-Pq: Name git_flush_all_swap_notifies_on_idle.patch

src/backends/native/meta-renderer-native.c

index 67bd635b9ba78e43b8f2701ce3ed7a9bd22f31ae..6d891535cc02afe8a90338b15fe98b9f8e94d12a 100644 (file)
@@ -73,6 +73,9 @@ typedef struct _MetaOnscreenNative
 
   gboolean pending_set_crtc;
 
+  int64_t pending_queue_swap_notify_frame_count;
+  int64_t pending_swap_notify_frame_count;
+
   MetaRendererView *view;
   int pending_flips;
 } MetaOnscreenNative;
@@ -124,16 +127,19 @@ flush_pending_swap_notify (CoglFramebuffer *framebuffer)
 
       if (onscreen_native->pending_swap_notify)
         {
-          CoglFrameInfo *info =
-            g_queue_pop_head (&onscreen->pending_frame_infos);
+          CoglFrameInfo *info;
 
-          _cogl_onscreen_notify_frame_sync (onscreen, info);
-          _cogl_onscreen_notify_complete (onscreen, info);
+          while ((info = g_queue_peek_head (&onscreen->pending_frame_infos)) &&
+                 info->global_frame_counter <= onscreen_native->pending_swap_notify_frame_count)
+            {
+              _cogl_onscreen_notify_frame_sync (onscreen, info);
+              _cogl_onscreen_notify_complete (onscreen, info);
+              cogl_object_unref (info);
+              g_queue_pop_head (&onscreen->pending_frame_infos);
+            }
 
           onscreen_native->pending_swap_notify = FALSE;
           cogl_object_unref (onscreen);
-
-          cogl_object_unref (info);
         }
     }
 }
@@ -200,6 +206,9 @@ meta_onscreen_native_queue_swap_notify (CoglOnscreen *onscreen)
   CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
   MetaRendererNative *renderer_native = egl_renderer->platform;
 
+  onscreen_native->pending_swap_notify_frame_count =
+    onscreen_native->pending_queue_swap_notify_frame_count;
+
   /* We only want to notify that the swap is complete when the
    * application calls cogl_context_dispatch so instead of
    * immediately notifying we queue an idle callback */
@@ -640,6 +649,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
       onscreen_native->pending_set_crtc = FALSE;
     }
 
+  onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter;
   meta_onscreen_native_flip_crtcs (onscreen);
 }