[mutter] compositor: Fix GL_EXT_x11_sync_object race condition



commit 9df6cda3e33e468d8e2ed61abdc5f21094e43ab3
Author: Aaron Plattner <aplattner nvidia com>
Date:   Mon Aug 3 21:15:15 2015 -0700

    compositor: Fix GL_EXT_x11_sync_object race condition
    
    The compositor maintains a ring of shared fences with the X server in order to
    properly synchronize rendering between the X server and the compositor's GPU
    channel.  When all of the fences have been used, the compositor needs to reset
    one so that it can be reused.  It does this by first waiting on the CPU for the
    fence to become triggered, and then sending a request to the X server to reset
    the fence.
    
    If the compositor's GPU channel is busy processing other work (e.g. the desktop
    switcher animation), then the X server may process the reset request before the
    GPU has consumed the fence.  This causes the GPU channel to hang.
    
    Fix the problem by having the compositor's GPU channel trigger its own fence
    after waiting for the X server's fence.  Wait for that fence on the CPU before
    sending the reset request to the X server.  This ensures that the GPU has
    consumed the X11 fence before the server resets it.
    
    Signed-off-by: Aaron Plattner <aplattner nvidia com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=728464

 src/compositor/meta-sync-ring.c |   25 +++++++++++++++++++------
 1 files changed, 19 insertions(+), 6 deletions(-)
---
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
index 4ee61f8..44b1c41 100644
--- a/src/compositor/meta-sync-ring.c
+++ b/src/compositor/meta-sync-ring.c
@@ -73,7 +73,8 @@ typedef struct
   Display *xdisplay;
 
   XSyncFence xfence;
-  GLsync glsync;
+  GLsync gl_x11_sync;
+  GLsync gpu_fence;
 
   XSyncCounter xcounter;
   XSyncAlarm xalarm;
@@ -118,6 +119,8 @@ static void             (*meta_gl_wait_sync) (GLsync sync,
 static GLsync           (*meta_gl_import_sync) (GLenum external_sync_type,
                                                 GLintptr external_sync,
                                                 GLbitfield flags);
+static GLsync           (*meta_gl_fence_sync) (GLenum condition,
+                                               GLbitfield flags);
 
 static MetaSyncRing *
 meta_sync_ring_get (void)
@@ -224,6 +227,8 @@ load_required_symbols (void)
     goto out;
   if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
     goto out;
+  if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
+    goto out;
 
   success = TRUE;
  out:
@@ -238,7 +243,8 @@ meta_sync_insert (MetaSync *self)
   XSyncTriggerFence (self->xdisplay, self->xfence);
   XFlush (self->xdisplay);
 
-  meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
+  meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
+  self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 
   self->state = META_SYNC_STATE_WAITING;
 }
@@ -255,9 +261,13 @@ meta_sync_check_update_finished (MetaSync *self,
       status = GL_ALREADY_SIGNALED;
       break;
     case META_SYNC_STATE_WAITING:
-      status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
+      status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
       if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
-        self->state = META_SYNC_STATE_DONE;
+        {
+          self->state = META_SYNC_STATE_DONE;
+          meta_gl_delete_sync (self->gpu_fence);
+          self->gpu_fence = 0;
+        }
       break;
     default:
       break;
@@ -312,7 +322,8 @@ meta_sync_new (Display *xdisplay)
   self->xdisplay = xdisplay;
 
   self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
-  self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
+  self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
+  self->gpu_fence = 0;
 
   self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
 
@@ -365,6 +376,8 @@ meta_sync_free (MetaSync *self)
   switch (self->state)
     {
     case META_SYNC_STATE_WAITING:
+      meta_gl_delete_sync (self->gpu_fence);
+      break;
     case META_SYNC_STATE_DONE:
       /* nothing to do */
       break;
@@ -383,7 +396,7 @@ meta_sync_free (MetaSync *self)
       break;
     }
 
-  meta_gl_delete_sync (self->glsync);
+  meta_gl_delete_sync (self->gl_x11_sync);
   XSyncDestroyFence (self->xdisplay, self->xfence);
   XSyncDestroyCounter (self->xdisplay, self->xcounter);
   XSyncDestroyAlarm (self->xdisplay, self->xalarm);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]