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
This commit is contained in:
parent
39763d4add
commit
9df6cda3e3
@ -73,7 +73,8 @@ typedef struct
|
|||||||
Display *xdisplay;
|
Display *xdisplay;
|
||||||
|
|
||||||
XSyncFence xfence;
|
XSyncFence xfence;
|
||||||
GLsync glsync;
|
GLsync gl_x11_sync;
|
||||||
|
GLsync gpu_fence;
|
||||||
|
|
||||||
XSyncCounter xcounter;
|
XSyncCounter xcounter;
|
||||||
XSyncAlarm xalarm;
|
XSyncAlarm xalarm;
|
||||||
@ -118,6 +119,8 @@ static void (*meta_gl_wait_sync) (GLsync sync,
|
|||||||
static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
|
static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
|
||||||
GLintptr external_sync,
|
GLintptr external_sync,
|
||||||
GLbitfield flags);
|
GLbitfield flags);
|
||||||
|
static GLsync (*meta_gl_fence_sync) (GLenum condition,
|
||||||
|
GLbitfield flags);
|
||||||
|
|
||||||
static MetaSyncRing *
|
static MetaSyncRing *
|
||||||
meta_sync_ring_get (void)
|
meta_sync_ring_get (void)
|
||||||
@ -224,6 +227,8 @@ load_required_symbols (void)
|
|||||||
goto out;
|
goto out;
|
||||||
if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
|
if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
|
||||||
goto out;
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
|
||||||
|
goto out;
|
||||||
|
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
out:
|
out:
|
||||||
@ -238,7 +243,8 @@ meta_sync_insert (MetaSync *self)
|
|||||||
XSyncTriggerFence (self->xdisplay, self->xfence);
|
XSyncTriggerFence (self->xdisplay, self->xfence);
|
||||||
XFlush (self->xdisplay);
|
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;
|
self->state = META_SYNC_STATE_WAITING;
|
||||||
}
|
}
|
||||||
@ -255,9 +261,13 @@ meta_sync_check_update_finished (MetaSync *self,
|
|||||||
status = GL_ALREADY_SIGNALED;
|
status = GL_ALREADY_SIGNALED;
|
||||||
break;
|
break;
|
||||||
case META_SYNC_STATE_WAITING:
|
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)
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -312,7 +322,8 @@ meta_sync_new (Display *xdisplay)
|
|||||||
self->xdisplay = xdisplay;
|
self->xdisplay = xdisplay;
|
||||||
|
|
||||||
self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
|
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);
|
self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
|
||||||
|
|
||||||
@ -365,6 +376,8 @@ meta_sync_free (MetaSync *self)
|
|||||||
switch (self->state)
|
switch (self->state)
|
||||||
{
|
{
|
||||||
case META_SYNC_STATE_WAITING:
|
case META_SYNC_STATE_WAITING:
|
||||||
|
meta_gl_delete_sync (self->gpu_fence);
|
||||||
|
break;
|
||||||
case META_SYNC_STATE_DONE:
|
case META_SYNC_STATE_DONE:
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
@ -383,7 +396,7 @@ meta_sync_free (MetaSync *self)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta_gl_delete_sync (self->glsync);
|
meta_gl_delete_sync (self->gl_x11_sync);
|
||||||
XSyncDestroyFence (self->xdisplay, self->xfence);
|
XSyncDestroyFence (self->xdisplay, self->xfence);
|
||||||
XSyncDestroyCounter (self->xdisplay, self->xcounter);
|
XSyncDestroyCounter (self->xdisplay, self->xcounter);
|
||||||
XSyncDestroyAlarm (self->xdisplay, self->xalarm);
|
XSyncDestroyAlarm (self->xdisplay, self->xalarm);
|
||||||
|
Loading…
Reference in New Issue
Block a user