compositor: Sync X drawing only once per frame

We only need to call XSync() once per frame to synchronize X with GL
drawing.

https://bugzilla.gnome.org/show_bug.cgi?id=728464
This commit is contained in:
Rui Matos 2014-05-12 15:11:53 +02:00
parent 048f035d30
commit 1e6b042778
3 changed files with 35 additions and 29 deletions

View File

@ -38,6 +38,8 @@ struct _MetaCompositor
gint switch_workspace_in_progress; gint switch_workspace_in_progress;
MetaPluginManager *plugin_mgr; MetaPluginManager *plugin_mgr;
gboolean frame_has_updated_xsurfaces;
}; };
/* Wait 2ms after vblank before starting to draw next frame */ /* Wait 2ms after vblank before starting to draw next frame */

View File

@ -146,6 +146,8 @@ process_damage (MetaCompositor *compositor,
{ {
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
meta_window_actor_process_x11_damage (window_actor, event); meta_window_actor_process_x11_damage (window_actor, event);
compositor->frame_has_updated_xsurfaces = TRUE;
} }
static Window static Window
@ -1125,11 +1127,12 @@ frame_callback (CoglOnscreen *onscreen,
} }
} }
static void static gboolean
pre_paint_windows (MetaCompositor *compositor) meta_repaint_func (gpointer data)
{ {
GList *l; GList *l;
MetaWindowActor *top_window; MetaWindowActor *top_window;
MetaCompositor *compositor = data;
if (compositor->onscreen == NULL) if (compositor->onscreen == NULL)
{ {
@ -1141,7 +1144,7 @@ pre_paint_windows (MetaCompositor *compositor)
} }
if (compositor->windows == NULL) if (compositor->windows == NULL)
return; return TRUE;
top_window = g_list_last (compositor->windows)->data; top_window = g_list_last (compositor->windows)->data;
@ -1153,13 +1156,34 @@ pre_paint_windows (MetaCompositor *compositor)
for (l = compositor->windows; l; l = l->next) for (l = compositor->windows; l; l = l->next)
meta_window_actor_pre_paint (l->data); meta_window_actor_pre_paint (l->data);
}
static gboolean if (compositor->frame_has_updated_xsurfaces)
meta_repaint_func (gpointer data) {
{ /* We need to make sure that any X drawing that happens before
MetaCompositor *compositor = data; * the XDamageSubtract() for each window above is visible to
pre_paint_windows (compositor); * subsequent GL rendering; the only standardized way to do this
* is EXT_x11_sync_object, which isn't yet widely available. For
* now, we count on details of Xorg and the open source drivers,
* and hope for the best otherwise.
*
* Xorg and open source driver specifics:
*
* The X server makes sure to flush drawing to the kernel before
* sending out damage events, but since we use
* DamageReportBoundingBox there may be drawing between the last
* damage event and the XDamageSubtract() that needs to be
* flushed as well.
*
* Xorg always makes sure that drawing is flushed to the kernel
* before writing events or responses to the client, so any
* round trip request at this point is sufficient to flush the
* GLX buffers.
*/
XSync (compositor->display->xdisplay, False);
compositor->frame_has_updated_xsurfaces = FALSE;
}
return TRUE; return TRUE;
} }

View File

@ -238,26 +238,6 @@ meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor)
XDamageSubtract (xdisplay, priv->damage, None, None); XDamageSubtract (xdisplay, priv->damage, None, None);
meta_error_trap_pop (display); meta_error_trap_pop (display);
/* We need to make sure that any X drawing that happens before the
* XDamageSubtract() above is visible to subsequent GL rendering;
* the only standardized way to do this is EXT_x11_sync_object,
* which isn't yet widely available. For now, we count on details
* of Xorg and the open source drivers, and hope for the best
* otherwise.
*
* Xorg and open source driver specifics:
*
* The X server makes sure to flush drawing to the kernel before
* sending out damage events, but since we use DamageReportBoundingBox
* there may be drawing between the last damage event and the
* XDamageSubtract() that needs to be flushed as well.
*
* Xorg always makes sure that drawing is flushed to the kernel
* before writing events or responses to the client, so any round trip
* request at this point is sufficient to flush the GLX buffers.
*/
XSync (xdisplay, False);
priv->received_damage = FALSE; priv->received_damage = FALSE;
} }