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_y,
|
||||||
int window_width,
|
int window_width,
|
||||||
int window_height,
|
int window_height,
|
||||||
guint8 opacity);
|
guint8 opacity,
|
||||||
|
cairo_region_t *clip);
|
||||||
void meta_shadow_get_bounds (MetaShadow *shadow,
|
void meta_shadow_get_bounds (MetaShadow *shadow,
|
||||||
int window_x,
|
int window_x,
|
||||||
int window_y,
|
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_y: y position of the region to paint a shadow for
|
||||||
* @window_width: actual width 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
|
* @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
|
* Paints the shadow at the given position, for the specified actual
|
||||||
* size of the region. (Since a #MetaShadow can be shared between
|
* 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.)
|
* size needs to be passed in here.)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
meta_shadow_paint (MetaShadow *shadow,
|
meta_shadow_paint (MetaShadow *shadow,
|
||||||
int window_x,
|
int window_x,
|
||||||
int window_y,
|
int window_y,
|
||||||
int window_width,
|
int window_width,
|
||||||
int window_height,
|
int window_height,
|
||||||
guint8 opacity)
|
guint8 opacity,
|
||||||
|
cairo_region_t *clip)
|
||||||
{
|
{
|
||||||
float texture_width = cogl_texture_get_width (shadow->texture);
|
float texture_width = cogl_texture_get_width (shadow->texture);
|
||||||
float texture_height = cogl_texture_get_height (shadow->texture);
|
float texture_height = cogl_texture_get_height (shadow->texture);
|
||||||
int i, j;
|
int i, j;
|
||||||
float src_x[4];
|
float src_x[4];
|
||||||
float src_y[4];
|
float src_y[4];
|
||||||
float dest_x[4];
|
int dest_x[4];
|
||||||
float dest_y[4];
|
int dest_y[4];
|
||||||
int n_x, n_y;
|
int n_x, n_y;
|
||||||
|
|
||||||
cogl_material_set_color4ub (shadow->material,
|
cogl_material_set_color4ub (shadow->material,
|
||||||
@ -267,11 +271,30 @@ meta_shadow_paint (MetaShadow *shadow,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < n_y; j++)
|
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],
|
cairo_rectangle_int_t dest_rect;
|
||||||
dest_x[i + 1], dest_y[j + 1],
|
dest_rect.y = dest_y[j];
|
||||||
src_x[i], src_y[j],
|
dest_rect.height = dest_y[j + 1] - dest_y[j];
|
||||||
src_x[i + 1], src_y[j + 1]);
|
|
||||||
|
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
|
/* A rectangular region with the unshaped extends of the window
|
||||||
* texture */
|
* texture */
|
||||||
cairo_region_t *bounding_region;
|
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 */
|
/* Extracted size-invariant shape used for shadows */
|
||||||
MetaWindowShape *shadow_shape;
|
MetaWindowShape *shadow_shape;
|
||||||
@ -93,7 +95,6 @@ struct _MetaWindowActorPrivate
|
|||||||
guint needs_reshape : 1;
|
guint needs_reshape : 1;
|
||||||
guint recompute_focused_shadow : 1;
|
guint recompute_focused_shadow : 1;
|
||||||
guint recompute_unfocused_shadow : 1;
|
guint recompute_unfocused_shadow : 1;
|
||||||
guint paint_shadow : 1;
|
|
||||||
guint size_changed : 1;
|
guint size_changed : 1;
|
||||||
|
|
||||||
guint needs_destroy : 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_shape_region (MetaWindowActor *self);
|
||||||
static void meta_window_actor_clear_bounding_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,
|
static gboolean is_shaped (MetaDisplay *display,
|
||||||
Window xwindow);
|
Window xwindow);
|
||||||
@ -283,7 +285,6 @@ meta_window_actor_init (MetaWindowActor *self)
|
|||||||
MetaWindowActorPrivate);
|
MetaWindowActorPrivate);
|
||||||
priv->opacity = 0xff;
|
priv->opacity = 0xff;
|
||||||
priv->shadow_class = NULL;
|
priv->shadow_class = NULL;
|
||||||
priv->paint_shadow = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -439,6 +440,7 @@ meta_window_actor_dispose (GObject *object)
|
|||||||
|
|
||||||
meta_window_actor_clear_shape_region (self);
|
meta_window_actor_clear_shape_region (self);
|
||||||
meta_window_actor_clear_bounding_region (self);
|
meta_window_actor_clear_bounding_region (self);
|
||||||
|
meta_window_actor_clear_shadow_clip (self);
|
||||||
|
|
||||||
if (priv->shadow_class != NULL)
|
if (priv->shadow_class != NULL)
|
||||||
{
|
{
|
||||||
@ -665,27 +667,24 @@ meta_window_actor_paint (ClutterActor *actor)
|
|||||||
{
|
{
|
||||||
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
||||||
MetaWindowActorPrivate *priv = self->priv;
|
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);
|
MetaShadowParams params;
|
||||||
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
|
cairo_rectangle_int_t shape_bounds;
|
||||||
|
|
||||||
if (shadow != NULL)
|
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
||||||
{
|
meta_window_actor_get_shadow_params (self, appears_focused, ¶ms);
|
||||||
MetaShadowParams params;
|
|
||||||
cairo_rectangle_int_t shape_bounds;
|
|
||||||
|
|
||||||
meta_window_actor_get_shape_bounds (self, &shape_bounds);
|
meta_shadow_paint (shadow,
|
||||||
meta_window_actor_get_shadow_params (self, appears_focused, ¶ms);
|
params.x_offset + shape_bounds.x,
|
||||||
|
params.y_offset + shape_bounds.y,
|
||||||
meta_shadow_paint (shadow,
|
shape_bounds.width,
|
||||||
params.x_offset + shape_bounds.x,
|
shape_bounds.height,
|
||||||
params.y_offset + shape_bounds.y,
|
(clutter_actor_get_paint_opacity (actor) * params.opacity) / 255,
|
||||||
shape_bounds.width,
|
priv->shadow_clip);
|
||||||
shape_bounds.height,
|
|
||||||
(clutter_actor_get_paint_opacity (actor) * params.opacity) / 255);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
|
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
|
static void
|
||||||
meta_window_actor_update_bounding_region (MetaWindowActor *self,
|
meta_window_actor_update_bounding_region (MetaWindowActor *self,
|
||||||
int width,
|
int width,
|
||||||
@ -1710,18 +1721,8 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
|
|||||||
|
|
||||||
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
|
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
|
||||||
{
|
{
|
||||||
cairo_rectangle_int_t shadow_bounds;
|
meta_window_actor_clear_shadow_clip (self);
|
||||||
cairo_region_overlap_t overlap;
|
priv->shadow_clip = cairo_region_copy (beneath_region);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1739,7 +1740,7 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
|
|||||||
|
|
||||||
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
|
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
|
||||||
NULL);
|
NULL);
|
||||||
priv->paint_shadow = TRUE;
|
meta_window_actor_clear_shadow_clip (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user