Implement more accurate clipping of obscured shadows
Instead of making optimizing obscured shadows an all-or-none operation, pass the clip region to meta_shadow_paint() and only paint the 9-slices that are at least partially visible. https://bugzilla.gnome.org/show_bug.cgi?id=592382
This commit is contained in:
parent
15f9590427
commit
ca5f2ac3ec
@ -46,7 +46,8 @@ void meta_shadow_paint (MetaShadow *shadow,
|
||||
int window_y,
|
||||
int window_width,
|
||||
int window_height,
|
||||
guint8 opacity);
|
||||
guint8 opacity,
|
||||
cairo_region_t *clip);
|
||||
void meta_shadow_get_bounds (MetaShadow *shadow,
|
||||
int window_x,
|
||||
int window_y,
|
||||
|
@ -188,6 +188,9 @@ meta_shadow_unref (MetaShadow *shadow)
|
||||
* @window_y: y position of the region to paint a shadow for
|
||||
* @window_width: actual width of the region to paint a shadow for
|
||||
* @window_height: actual height of the region to paint a shadow for
|
||||
* @clip: (allow-none): if non-%NULL specifies the visible portion
|
||||
* of the shadow. Drawing won't be strictly clipped to this region
|
||||
* but it will be used to optimize what is drawn.
|
||||
*
|
||||
* Paints the shadow at the given position, for the specified actual
|
||||
* size of the region. (Since a #MetaShadow can be shared between
|
||||
@ -195,20 +198,21 @@ meta_shadow_unref (MetaShadow *shadow)
|
||||
* size needs to be passed in here.)
|
||||
*/
|
||||
void
|
||||
meta_shadow_paint (MetaShadow *shadow,
|
||||
int window_x,
|
||||
int window_y,
|
||||
int window_width,
|
||||
int window_height,
|
||||
guint8 opacity)
|
||||
meta_shadow_paint (MetaShadow *shadow,
|
||||
int window_x,
|
||||
int window_y,
|
||||
int window_width,
|
||||
int window_height,
|
||||
guint8 opacity,
|
||||
cairo_region_t *clip)
|
||||
{
|
||||
float texture_width = cogl_texture_get_width (shadow->texture);
|
||||
float texture_height = cogl_texture_get_height (shadow->texture);
|
||||
int i, j;
|
||||
float src_x[4];
|
||||
float src_y[4];
|
||||
float dest_x[4];
|
||||
float dest_y[4];
|
||||
int dest_x[4];
|
||||
int dest_y[4];
|
||||
int n_x, n_y;
|
||||
|
||||
cogl_material_set_color4ub (shadow->material,
|
||||
@ -267,11 +271,30 @@ meta_shadow_paint (MetaShadow *shadow,
|
||||
}
|
||||
|
||||
for (j = 0; j < n_y; j++)
|
||||
for (i = 0; i < n_x; i++)
|
||||
cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
|
||||
dest_x[i + 1], dest_y[j + 1],
|
||||
src_x[i], src_y[j],
|
||||
src_x[i + 1], src_y[j + 1]);
|
||||
{
|
||||
cairo_rectangle_int_t dest_rect;
|
||||
dest_rect.y = dest_y[j];
|
||||
dest_rect.height = dest_y[j + 1] - dest_y[j];
|
||||
|
||||
for (i = 0; i < n_x; i++)
|
||||
{
|
||||
cairo_region_overlap_t overlap;
|
||||
|
||||
dest_rect.x = dest_x[i];
|
||||
dest_rect.width = dest_x[i + 1] - dest_x[i];
|
||||
|
||||
if (clip)
|
||||
overlap = cairo_region_contains_rectangle (clip, &dest_rect);
|
||||
else
|
||||
overlap = CAIRO_REGION_OVERLAP_PART;
|
||||
|
||||
if (overlap != CAIRO_REGION_OVERLAP_OUT)
|
||||
cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
|
||||
dest_x[i + 1], dest_y[j + 1],
|
||||
src_x[i], src_y[j],
|
||||
src_x[i + 1], src_y[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,6 +60,8 @@ struct _MetaWindowActorPrivate
|
||||
/* A rectangular region with the unshaped extends of the window
|
||||
* texture */
|
||||
cairo_region_t *bounding_region;
|
||||
/* The region we should clip to when painting the shadow */
|
||||
cairo_region_t *shadow_clip;
|
||||
|
||||
/* Extracted size-invariant shape used for shadows */
|
||||
MetaWindowShape *shadow_shape;
|
||||
@ -93,7 +95,6 @@ struct _MetaWindowActorPrivate
|
||||
guint needs_reshape : 1;
|
||||
guint recompute_focused_shadow : 1;
|
||||
guint recompute_unfocused_shadow : 1;
|
||||
guint paint_shadow : 1;
|
||||
guint size_changed : 1;
|
||||
|
||||
guint needs_destroy : 1;
|
||||
@ -140,6 +141,7 @@ static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
||||
|
||||
static void meta_window_actor_clear_shape_region (MetaWindowActor *self);
|
||||
static void meta_window_actor_clear_bounding_region (MetaWindowActor *self);
|
||||
static void meta_window_actor_clear_shadow_clip (MetaWindowActor *self);
|
||||
|
||||
static gboolean is_shaped (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
@ -283,7 +285,6 @@ meta_window_actor_init (MetaWindowActor *self)
|
||||
MetaWindowActorPrivate);
|
||||
priv->opacity = 0xff;
|
||||
priv->shadow_class = NULL;
|
||||
priv->paint_shadow = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -439,6 +440,7 @@ meta_window_actor_dispose (GObject *object)
|
||||
|
||||
meta_window_actor_clear_shape_region (self);
|
||||
meta_window_actor_clear_bounding_region (self);
|
||||
meta_window_actor_clear_shadow_clip (self);
|
||||
|
||||
if (priv->shadow_class != NULL)
|
||||
{
|
||||
@ -665,27 +667,24 @@ meta_window_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
gboolean appears_focused = meta_window_appears_focused (priv->window);
|
||||
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
||||
|
||||
if (priv->paint_shadow)
|
||||
if (shadow != NULL)
|
||||
{
|
||||
gboolean appears_focused = meta_window_appears_focused (priv->window);
|
||||
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
||||
MetaShadowParams params;
|
||||
cairo_rectangle_int_t shape_bounds;
|
||||
|
||||
if (shadow != NULL)
|
||||
{
|
||||
MetaShadowParams params;
|
||||
cairo_rectangle_int_t shape_bounds;
|
||||
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
||||
meta_window_actor_get_shadow_params (self, appears_focused, ¶ms);
|
||||
|
||||
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
||||
meta_window_actor_get_shadow_params (self, appears_focused, ¶ms);
|
||||
|
||||
meta_shadow_paint (shadow,
|
||||
params.x_offset + shape_bounds.x,
|
||||
params.y_offset + shape_bounds.y,
|
||||
shape_bounds.width,
|
||||
shape_bounds.height,
|
||||
(clutter_actor_get_paint_opacity (actor) * params.opacity) / 255);
|
||||
}
|
||||
meta_shadow_paint (shadow,
|
||||
params.x_offset + shape_bounds.x,
|
||||
params.y_offset + shape_bounds.y,
|
||||
shape_bounds.width,
|
||||
shape_bounds.height,
|
||||
(clutter_actor_get_paint_opacity (actor) * params.opacity) / 255,
|
||||
priv->shadow_clip);
|
||||
}
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
|
||||
@ -1550,6 +1549,18 @@ meta_window_actor_clear_bounding_region (MetaWindowActor *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_clear_shadow_clip (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->shadow_clip)
|
||||
{
|
||||
cairo_region_destroy (priv->shadow_clip);
|
||||
priv->shadow_clip = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_update_bounding_region (MetaWindowActor *self,
|
||||
int width,
|
||||
@ -1710,18 +1721,8 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
|
||||
|
||||
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
|
||||
{
|
||||
cairo_rectangle_int_t shadow_bounds;
|
||||
cairo_region_overlap_t overlap;
|
||||
|
||||
/* We could compute an full clip region as we do for the window
|
||||
* texture, but the shadow is relatively cheap to draw, and
|
||||
* a little more complex to clip, so we just catch the case where
|
||||
* the shadow is completely obscured and doesn't need to be drawn
|
||||
* at all.
|
||||
*/
|
||||
meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
|
||||
overlap = cairo_region_contains_rectangle (beneath_region, &shadow_bounds);
|
||||
priv->paint_shadow = overlap != CAIRO_REGION_OVERLAP_OUT;
|
||||
meta_window_actor_clear_shadow_clip (self);
|
||||
priv->shadow_clip = cairo_region_copy (beneath_region);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1739,7 +1740,7 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
|
||||
|
||||
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
|
||||
NULL);
|
||||
priv->paint_shadow = TRUE;
|
||||
meta_window_actor_clear_shadow_clip (self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user