mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 17:40:40 -05:00
mutter-window: stream raw updates to ClutterX11TexturePixmap
This changes the way we handle Damage events so instead of getting an event when the damage region of a pixmap becomes non-empty we now get sent all damage rectangles and stream those all though to ClutterX11TexturePixmap using clutter_x11_texture_pixmap_update_area() For Clutter 1.2, ClutterGLXTexturePixmap was updated so that calls to clutter_x11_texture_pixmap_update_area are now cheap (glXBindTexImageEXT calls are now deferred until just before painting) and since ClutterGLXTexturePixmap is now capable of queueing clipped redraws that can result in only updating a sub-region of the stage during a repaint cycle (and using glXCopySubBufferMESA to present the sub-region redraw to the front buffer) this should improve performance and reduced power consumption for a range of use cases. (For example viewing a website that has animated adverts doesn't force the whole screen to be redrawn for each frame of the advert) Besides being able to take advantage of glXCopySubBuffer to only update a small region of the stage the fact that this patch makes Mutter now request RawRectangles from the X server means we no longer do a synchronous X request for a complete Damage Region for every window damaged each frame. This should also improve performance. CLUTTER_PAINT=redraws can be used to visualize what parts of the stage are redrawn and with this patch applied I can open a terminal and as I type I see that only the damaged areas of the terminal are being redrawn.
This commit is contained in:
parent
cfa30f9876
commit
0c14640352
@ -47,6 +47,8 @@ struct _MutterWindowPrivate
|
|||||||
* texture */
|
* texture */
|
||||||
GdkRegion *bounding_region;
|
GdkRegion *bounding_region;
|
||||||
|
|
||||||
|
guint freeze_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These need to be counters rather than flags, since more plugins
|
* These need to be counters rather than flags, since more plugins
|
||||||
* can implement same effect; the practicality of stacking effects
|
* can implement same effect; the practicality of stacking effects
|
||||||
@ -65,7 +67,9 @@ struct _MutterWindowPrivate
|
|||||||
guint disposed : 1;
|
guint disposed : 1;
|
||||||
guint redecorating : 1;
|
guint redecorating : 1;
|
||||||
|
|
||||||
guint needs_repair : 1;
|
guint needs_damage_all : 1;
|
||||||
|
|
||||||
|
guint needs_pixmap : 1;
|
||||||
guint needs_reshape : 1;
|
guint needs_reshape : 1;
|
||||||
guint size_changed : 1;
|
guint size_changed : 1;
|
||||||
|
|
||||||
@ -332,7 +336,8 @@ mutter_window_constructed (GObject *object)
|
|||||||
if (priv->attrs.class == InputOnly)
|
if (priv->attrs.class == InputOnly)
|
||||||
priv->damage = None;
|
priv->damage = None;
|
||||||
else
|
else
|
||||||
priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportNonEmpty);
|
priv->damage = XDamageCreate (xdisplay, xwindow,
|
||||||
|
XDamageReportRawRectangles);
|
||||||
|
|
||||||
format = XRenderFindVisualFormat (xdisplay, priv->attrs.visual);
|
format = XRenderFindVisualFormat (xdisplay, priv->attrs.visual);
|
||||||
|
|
||||||
@ -765,6 +770,60 @@ mutter_window_showing_on_its_workspace (MutterWindow *self)
|
|||||||
return meta_window_showing_on_its_workspace (self->priv->window);
|
return meta_window_showing_on_its_workspace (self->priv->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mutter_window_freeze (MutterWindow *self)
|
||||||
|
{
|
||||||
|
self->priv->freeze_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mutter_window_damage_all (MutterWindow *self)
|
||||||
|
{
|
||||||
|
MutterWindowPrivate *priv = self->priv;
|
||||||
|
ClutterX11TexturePixmap *texture_x11 = CLUTTER_X11_TEXTURE_PIXMAP (priv->actor);
|
||||||
|
guint pixmap_width = 0;
|
||||||
|
guint pixmap_height = 0;
|
||||||
|
|
||||||
|
if (!priv->needs_damage_all)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_object_get (texture_x11,
|
||||||
|
"pixmap-width", &pixmap_width,
|
||||||
|
"pixmap-height", &pixmap_height,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
clutter_x11_texture_pixmap_update_area (texture_x11,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
pixmap_width,
|
||||||
|
pixmap_height);
|
||||||
|
|
||||||
|
priv->needs_damage_all = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mutter_window_thaw (MutterWindow *self)
|
||||||
|
{
|
||||||
|
self->priv->freeze_count--;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (self->priv->freeze_count < 0))
|
||||||
|
{
|
||||||
|
g_warning ("Error in freeze/thaw accounting.");
|
||||||
|
self->priv->freeze_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->priv->freeze_count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Since we ignore damage events while a window is frozen for certain effects
|
||||||
|
* we may need to issue an update_area() covering the whole pixmap if we
|
||||||
|
* don't know what real damage has happened. */
|
||||||
|
|
||||||
|
if (self->priv->needs_damage_all)
|
||||||
|
mutter_window_damage_all (self);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
mutter_window_effect_in_progress (MutterWindow *self)
|
mutter_window_effect_in_progress (MutterWindow *self)
|
||||||
{
|
{
|
||||||
@ -776,11 +835,11 @@ mutter_window_effect_in_progress (MutterWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mutter_window_mark_for_repair (MutterWindow *self)
|
mutter_window_queue_create_pixmap (MutterWindow *self)
|
||||||
{
|
{
|
||||||
MutterWindowPrivate *priv = self->priv;
|
MutterWindowPrivate *priv = self->priv;
|
||||||
|
|
||||||
priv->needs_repair = TRUE;
|
priv->needs_pixmap = TRUE;
|
||||||
|
|
||||||
if (!priv->mapped)
|
if (!priv->mapped)
|
||||||
return;
|
return;
|
||||||
@ -796,6 +855,21 @@ mutter_window_mark_for_repair (MutterWindow *self)
|
|||||||
clutter_actor_queue_redraw (priv->actor);
|
clutter_actor_queue_redraw (priv->actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_freeze_thaw_effect (gulong event)
|
||||||
|
{
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case MUTTER_PLUGIN_DESTROY:
|
||||||
|
case MUTTER_PLUGIN_MAXIMIZE:
|
||||||
|
case MUTTER_PLUGIN_UNMAXIMIZE:
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
start_simple_effect (MutterWindow *self,
|
start_simple_effect (MutterWindow *self,
|
||||||
gulong event)
|
gulong event)
|
||||||
@ -803,6 +877,7 @@ start_simple_effect (MutterWindow *self,
|
|||||||
MutterWindowPrivate *priv = self->priv;
|
MutterWindowPrivate *priv = self->priv;
|
||||||
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
|
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
|
||||||
gint *counter = NULL;
|
gint *counter = NULL;
|
||||||
|
gboolean use_freeze_thaw = FALSE;
|
||||||
|
|
||||||
if (!info->plugin_mgr)
|
if (!info->plugin_mgr)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -827,6 +902,11 @@ start_simple_effect (MutterWindow *self,
|
|||||||
|
|
||||||
g_assert (counter);
|
g_assert (counter);
|
||||||
|
|
||||||
|
use_freeze_thaw = is_freeze_thaw_effect (event);
|
||||||
|
|
||||||
|
if (use_freeze_thaw)
|
||||||
|
mutter_window_freeze (self);
|
||||||
|
|
||||||
(*counter)++;
|
(*counter)++;
|
||||||
|
|
||||||
if (!mutter_plugin_manager_event_simple (info->plugin_mgr,
|
if (!mutter_plugin_manager_event_simple (info->plugin_mgr,
|
||||||
@ -834,6 +914,8 @@ start_simple_effect (MutterWindow *self,
|
|||||||
event))
|
event))
|
||||||
{
|
{
|
||||||
(*counter)--;
|
(*counter)--;
|
||||||
|
if (use_freeze_thaw)
|
||||||
|
mutter_window_thaw (self);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -857,7 +939,7 @@ mutter_window_after_effects (MutterWindow *self)
|
|||||||
if (!meta_window_is_mapped (priv->window))
|
if (!meta_window_is_mapped (priv->window))
|
||||||
mutter_window_detach (self);
|
mutter_window_detach (self);
|
||||||
|
|
||||||
if (priv->needs_repair)
|
if (priv->needs_pixmap)
|
||||||
clutter_actor_queue_redraw (priv->actor);
|
clutter_actor_queue_redraw (priv->actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,6 +1008,9 @@ mutter_window_effect_completed (MutterWindow *self,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_freeze_thaw_effect (event))
|
||||||
|
mutter_window_thaw (self);
|
||||||
|
|
||||||
if (!mutter_window_effect_in_progress (self))
|
if (!mutter_window_effect_in_progress (self))
|
||||||
mutter_window_after_effects (self);
|
mutter_window_after_effects (self);
|
||||||
}
|
}
|
||||||
@ -951,7 +1036,7 @@ mutter_window_detach (MutterWindow *self)
|
|||||||
clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
|
clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
|
||||||
None);
|
None);
|
||||||
|
|
||||||
mutter_window_mark_for_repair (self);
|
mutter_window_queue_create_pixmap (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1014,7 +1099,7 @@ mutter_window_sync_actor_position (MutterWindow *self)
|
|||||||
priv->attrs.height != window_rect.height)
|
priv->attrs.height != window_rect.height)
|
||||||
{
|
{
|
||||||
priv->size_changed = TRUE;
|
priv->size_changed = TRUE;
|
||||||
mutter_window_mark_for_repair (self);
|
mutter_window_queue_create_pixmap (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX deprecated: please use meta_window_get_outer_rect instead */
|
/* XXX deprecated: please use meta_window_get_outer_rect instead */
|
||||||
@ -1206,7 +1291,7 @@ mutter_window_new (MetaWindow *window)
|
|||||||
|
|
||||||
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
|
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
|
||||||
if (priv->mapped)
|
if (priv->mapped)
|
||||||
mutter_window_mark_for_repair (self);
|
mutter_window_queue_create_pixmap (self);
|
||||||
|
|
||||||
mutter_window_sync_actor_position (self);
|
mutter_window_sync_actor_position (self);
|
||||||
|
|
||||||
@ -1234,7 +1319,7 @@ mutter_window_mapped (MutterWindow *self)
|
|||||||
|
|
||||||
priv->mapped = TRUE;
|
priv->mapped = TRUE;
|
||||||
|
|
||||||
mutter_window_mark_for_repair (self);
|
mutter_window_queue_create_pixmap (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1250,7 +1335,7 @@ mutter_window_unmapped (MutterWindow *self)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
mutter_window_detach (self);
|
mutter_window_detach (self);
|
||||||
priv->needs_repair = FALSE;
|
priv->needs_pixmap = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1462,7 +1547,7 @@ mutter_window_reset_visible_regions (MutterWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_needs_repair (MutterWindow *self)
|
check_needs_pixmap (MutterWindow *self)
|
||||||
{
|
{
|
||||||
MutterWindowPrivate *priv = self->priv;
|
MutterWindowPrivate *priv = self->priv;
|
||||||
MetaScreen *screen = priv->screen;
|
MetaScreen *screen = priv->screen;
|
||||||
@ -1473,7 +1558,7 @@ check_needs_repair (MutterWindow *self)
|
|||||||
Window xwindow = priv->xwindow;
|
Window xwindow = priv->xwindow;
|
||||||
gboolean full = FALSE;
|
gboolean full = FALSE;
|
||||||
|
|
||||||
if (!priv->needs_repair)
|
if (!priv->needs_pixmap)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!priv->mapped)
|
if (!priv->mapped)
|
||||||
@ -1545,74 +1630,50 @@ check_needs_repair (MutterWindow *self)
|
|||||||
full = TRUE;
|
full = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO -- on some gfx hardware updating the whole texture instead of
|
|
||||||
* the individual rectangles is actually quicker, so we might want to
|
|
||||||
* make this a configurable option (on desktop HW with multiple pipelines
|
|
||||||
* it is usually quicker to just update the damaged parts).
|
|
||||||
*
|
|
||||||
* If we are using TFP we update the whole texture (this simply trigers
|
|
||||||
* the texture rebind).
|
|
||||||
*/
|
|
||||||
if (full
|
|
||||||
#ifdef HAVE_GLX_TEXTURE_PIXMAP
|
|
||||||
|| (CLUTTER_GLX_IS_TEXTURE_PIXMAP (priv->actor) &&
|
|
||||||
clutter_glx_texture_pixmap_using_extension
|
|
||||||
(CLUTTER_GLX_TEXTURE_PIXMAP (priv->actor)))
|
|
||||||
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
XDamageSubtract (xdisplay, priv->damage, None, None);
|
|
||||||
|
|
||||||
clutter_x11_texture_pixmap_update_area
|
|
||||||
(CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
clutter_actor_get_width (priv->actor),
|
|
||||||
clutter_actor_get_height (priv->actor));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XRectangle *r_damage;
|
|
||||||
XRectangle r_bounds;
|
|
||||||
XserverRegion parts;
|
|
||||||
int i, r_count;
|
|
||||||
|
|
||||||
parts = XFixesCreateRegion (xdisplay, 0, 0);
|
|
||||||
XDamageSubtract (xdisplay, priv->damage, None, parts);
|
|
||||||
|
|
||||||
r_damage = XFixesFetchRegionAndBounds (xdisplay,
|
|
||||||
parts,
|
|
||||||
&r_count,
|
|
||||||
&r_bounds);
|
|
||||||
|
|
||||||
if (r_damage)
|
|
||||||
{
|
|
||||||
for (i = 0; i < r_count; ++i)
|
|
||||||
{
|
|
||||||
clutter_x11_texture_pixmap_update_area
|
|
||||||
(CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
|
|
||||||
r_damage[i].x,
|
|
||||||
r_damage[i].y,
|
|
||||||
r_damage[i].width,
|
|
||||||
r_damage[i].height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree (r_damage);
|
|
||||||
XFixesDestroyRegion (xdisplay, parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_error_trap_pop (display, FALSE);
|
meta_error_trap_pop (display, FALSE);
|
||||||
|
|
||||||
priv->needs_repair = FALSE;
|
priv->needs_pixmap = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_frozen (MutterWindow *self)
|
||||||
|
{
|
||||||
|
return self->priv->freeze_count ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mutter_window_process_damage (MutterWindow *self,
|
mutter_window_process_damage (MutterWindow *self,
|
||||||
XDamageNotifyEvent *event)
|
XDamageNotifyEvent *event)
|
||||||
{
|
{
|
||||||
mutter_window_mark_for_repair (self);
|
MutterWindowPrivate *priv = self->priv;
|
||||||
|
ClutterX11TexturePixmap *texture_x11 = CLUTTER_X11_TEXTURE_PIXMAP (priv->actor);
|
||||||
|
|
||||||
|
if (is_frozen (self))
|
||||||
|
{
|
||||||
|
/* The window is frozen due to an effect in progress: we ignore damage
|
||||||
|
* here on the off chance that this will stop the corresponding
|
||||||
|
* texture_from_pixmap from being update.
|
||||||
|
*
|
||||||
|
* needs_damage_all tracks that some unknown damage happened while the
|
||||||
|
* window was frozen so that when the window becomes unfrozen we can
|
||||||
|
* issue a full window update to cover any lost damage.
|
||||||
|
*
|
||||||
|
* It should be noted that this is an unreliable mechanism since it's
|
||||||
|
* quite likely that drivers will aim to provide a zero-copy
|
||||||
|
* implementation of the texture_from_pixmap extension and in those cases
|
||||||
|
* any drawing done to the window is always immediately reflected in the
|
||||||
|
* texture regardless of damage event handling.
|
||||||
|
*/
|
||||||
|
priv->needs_damage_all = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clutter_x11_texture_pixmap_update_area (texture_x11,
|
||||||
|
event->area.x,
|
||||||
|
event->area.y,
|
||||||
|
event->area.width,
|
||||||
|
event->area.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1683,17 +1744,15 @@ mutter_window_update_shape (MutterWindow *self,
|
|||||||
void
|
void
|
||||||
mutter_window_pre_paint (MutterWindow *self)
|
mutter_window_pre_paint (MutterWindow *self)
|
||||||
{
|
{
|
||||||
MutterWindowPrivate *priv = self->priv;
|
if (is_frozen (self))
|
||||||
|
{
|
||||||
/* The window is frozen due to a pending animation: we'll wait until
|
/* The window is frozen due to a pending animation: we'll wait until
|
||||||
* the animation finishes to reshape and repair the window */
|
* the animation finishes to reshape and repair the window */
|
||||||
if (priv->destroy_in_progress ||
|
return;
|
||||||
priv->maximize_in_progress ||
|
}
|
||||||
priv->unmaximize_in_progress)
|
|
||||||
return;
|
|
||||||
|
|
||||||
check_needs_reshape (self);
|
check_needs_reshape (self);
|
||||||
check_needs_repair (self);
|
check_needs_pixmap (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user