diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h index 42458daa2..6839b0872 100644 --- a/src/compositor/meta-shaped-texture-private.h +++ b/src/compositor/meta-shaped-texture-private.h @@ -40,7 +40,6 @@ void meta_shaped_texture_set_snippet (MetaShapedTexture *stex, void meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, int fallback_width, int fallback_height); -gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self); cairo_region_t * meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex); void meta_shaped_texture_set_transform (MetaShapedTexture *stex, MetaMonitorTransform transform); @@ -51,11 +50,6 @@ void meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex, int dst_width, int dst_height); void meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex); -void meta_shaped_texture_cull_out (MetaShapedTexture *stex, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region, - uint8_t opacity); -void meta_shaped_texture_reset_culling (MetaShapedTexture *stex); void meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, int buffer_scale); int meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex); diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 308d9361a..f85b55e23 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -88,10 +88,6 @@ struct _MetaShapedTexture /* The region containing only fully opaque pixels */ cairo_region_t *opaque_region; - /* MetaCullable regions, see that documentation for more details */ - cairo_region_t *clip_region; - cairo_region_t *unobscured_region; - gboolean size_invalid; MetaMonitorTransform transform; gboolean has_viewport_src_rect; @@ -219,34 +215,6 @@ ensure_size_valid (MetaShapedTexture *stex) update_size (stex); } -static void -set_unobscured_region (MetaShapedTexture *stex, - cairo_region_t *unobscured_region) -{ - g_clear_pointer (&stex->unobscured_region, cairo_region_destroy); - if (unobscured_region) - { - int width, height; - - ensure_size_valid (stex); - width = stex->dst_width; - height = stex->dst_height; - - cairo_rectangle_int_t bounds = { 0, 0, width, height }; - stex->unobscured_region = cairo_region_copy (unobscured_region); - cairo_region_intersect_rectangle (stex->unobscured_region, &bounds); - } -} - -static void -set_clip_region (MetaShapedTexture *stex, - cairo_region_t *clip_region) -{ - g_clear_pointer (&stex->clip_region, cairo_region_destroy); - if (clip_region) - stex->clip_region = cairo_region_copy (clip_region); -} - static void meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex) { @@ -271,12 +239,8 @@ meta_shaped_texture_dispose (GObject *object) stex->paint_tower = NULL; g_clear_pointer (&stex->texture, cogl_object_unref); - g_clear_pointer (&stex->opaque_region, cairo_region_destroy); meta_shaped_texture_set_mask_texture (stex, NULL); - set_unobscured_region (stex, NULL); - set_clip_region (stex, NULL); - meta_shaped_texture_reset_pipelines (stex); g_clear_pointer (&stex->snippet, cogl_object_unref); @@ -546,12 +510,6 @@ texture_is_idle_and_not_mipmapped (gpointer user_data) return G_SOURCE_REMOVE; } -static cairo_region_t * -effective_unobscured_region (MetaShapedTexture *stex) -{ - return stex->unobscured_region; -} - static void do_paint_content (MetaShapedTexture *stex, ClutterPaintNode *root_node, @@ -599,19 +557,12 @@ do_paint_content (MetaShapedTexture *stex, if (use_opaque_region) { - if (stex->clip_region) - blended_tex_region = cairo_region_copy (stex->clip_region); - else - blended_tex_region = cairo_region_create_rectangle (&content_rect); - + blended_tex_region = cairo_region_create_rectangle (&content_rect); cairo_region_subtract (blended_tex_region, stex->opaque_region); } else { - if (stex->clip_region) - blended_tex_region = cairo_region_reference (stex->clip_region); - else - blended_tex_region = NULL; + blended_tex_region = NULL; } /* Limit to how many separate rectangles we'll draw; beyond this just @@ -633,21 +584,10 @@ do_paint_content (MetaShapedTexture *stex, /* First, paint the unblended parts, which are part of the opaque region. */ if (use_opaque_region) { - cairo_region_t *region; int n_rects; int i; - if (stex->clip_region) - { - region = cairo_region_copy (stex->clip_region); - cairo_region_intersect (region, stex->opaque_region); - } - else - { - region = cairo_region_reference (stex->opaque_region); - } - - if (!cairo_region_is_empty (region)) + if (!cairo_region_is_empty (stex->opaque_region)) { CoglPipeline *opaque_pipeline; @@ -655,18 +595,16 @@ do_paint_content (MetaShapedTexture *stex, cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); - n_rects = cairo_region_num_rectangles (region); + n_rects = cairo_region_num_rectangles (stex->opaque_region); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); + cairo_region_get_rectangle (stex->opaque_region, i, &rect); paint_clipped_rectangle_node (stex, root_node, opaque_pipeline, &rect, alloc); } } - - cairo_region_destroy (region); } /* Now, go ahead and paint the blended parts. */ @@ -786,9 +724,6 @@ meta_shaped_texture_paint_content (ClutterContent *content, CoglTexture *paint_tex = NULL; uint8_t opacity; - if (stex->clip_region && cairo_region_is_empty (stex->clip_region)) - return; - /* The GL EXT_texture_from_pixmap extension does allow for it to be * used together with SGIS_generate_mipmap, however this is very * rarely supported. Also, even when it is supported there @@ -873,17 +808,6 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, clutter_content_invalidate (CLUTTER_CONTENT (stex)); } -gboolean -meta_shaped_texture_is_obscured (MetaShapedTexture *stex) -{ - cairo_region_t *unobscured_region = effective_unobscured_region (stex); - - if (unobscured_region) - return cairo_region_is_empty (unobscured_region); - else - return FALSE; -} - /** * meta_shaped_texture_update_area: * @stex: #MetaShapedTexture @@ -891,6 +815,7 @@ meta_shaped_texture_is_obscured (MetaShapedTexture *stex) * @y: the y coordinate of the damaged area * @width: the width of the damaged area * @height: the height of the damaged area + * @clip: (out): the resulting clip region * * Repairs the damaged area indicated by @x, @y, @width and @height * and potentially queues a redraw. @@ -898,33 +823,37 @@ meta_shaped_texture_is_obscured (MetaShapedTexture *stex) * Return value: Whether a redraw have been queued or not */ gboolean -meta_shaped_texture_update_area (MetaShapedTexture *stex, - int x, - int y, - int width, - int height) +meta_shaped_texture_update_area (MetaShapedTexture *stex, + int x, + int y, + int width, + int height, + cairo_rectangle_int_t *clip) { - cairo_region_t *unobscured_region; - cairo_rectangle_int_t clip; MetaMonitorTransform inverted_transform; if (stex->texture == NULL) return FALSE; - clip = (cairo_rectangle_int_t) { + *clip = (cairo_rectangle_int_t) { .x = x, .y = y, .width = width, .height = height }; + meta_rectangle_scale_double (clip, + 1.0 / stex->buffer_scale, + META_ROUNDING_STRATEGY_SHRINK, + clip); + inverted_transform = meta_monitor_transform_invert (stex->transform); ensure_size_valid (stex); - meta_rectangle_transform (&clip, + meta_rectangle_transform (clip, inverted_transform, stex->dst_width, stex->dst_height, - &clip); + clip); if (stex->has_viewport_src_rect || stex->has_viewport_dst_size) { @@ -969,11 +898,11 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, inverted_dst_width = ceilf (viewport.size.width); inverted_dst_height = ceilf (viewport.size.height); - meta_rectangle_crop_and_scale (&clip, + meta_rectangle_crop_and_scale (clip, &inverted_viewport, inverted_dst_width, inverted_dst_height, - &clip); + clip); } meta_texture_tower_update_area (stex->paint_tower, @@ -996,36 +925,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, stex->fast_updates++; } - unobscured_region = effective_unobscured_region (stex); - if (unobscured_region) - { - cairo_rectangle_int_t extents; - cairo_region_t *scaled_unobscured_region; - cairo_region_t *intersection; - - if (cairo_region_is_empty (unobscured_region)) - return FALSE; - - intersection = cairo_region_copy (unobscured_region); - cairo_region_intersect_rectangle (intersection, &clip); - - if (!cairo_region_is_empty (intersection)) - { - cairo_rectangle_int_t damage_rect; - cairo_region_get_extents (intersection, &damage_rect); - clutter_content_invalidate (CLUTTER_CONTENT (stex)); - cairo_region_destroy (intersection); - return TRUE; - } - - cairo_region_destroy (intersection); - return FALSE; - } - else - { - clutter_content_invalidate (CLUTTER_CONTENT (stex)); - return TRUE; - } + return TRUE; } /** @@ -1455,34 +1355,3 @@ meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex) return stex->buffer_scale; } - -void -meta_shaped_texture_cull_out (MetaShapedTexture *stex, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region, - uint8_t opacity) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - set_unobscured_region (stex, unobscured_region); - set_clip_region (stex, clip_region); - - if (opacity == 0xff) - { - if (stex->opaque_region) - { - if (unobscured_region) - cairo_region_subtract (unobscured_region, stex->opaque_region); - if (clip_region) - cairo_region_subtract (clip_region, stex->opaque_region); - } - } -} - -void -meta_shaped_texture_reset_culling (MetaShapedTexture *stex) -{ - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - set_clip_region (stex, NULL); -} diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index e50eb8018..c7256c3b8 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -30,6 +30,10 @@ typedef struct _MetaSurfaceActorPrivate cairo_region_t *input_region; + /* MetaCullable regions, see that documentation for more details */ + cairo_region_t *clip_region; + cairo_region_t *unobscured_region; + /* Freeze/thaw accounting */ cairo_region_t *pending_damage; guint frozen : 1; @@ -51,6 +55,78 @@ enum static guint signals[LAST_SIGNAL]; +static cairo_region_t * +effective_unobscured_region (MetaSurfaceActor *surface_actor) +{ + MetaSurfaceActorPrivate *priv = + meta_surface_actor_get_instance_private (surface_actor); + ClutterActor *actor; + + /* Fail if we have any mapped clones. */ + actor = CLUTTER_ACTOR (surface_actor); + do + { + if (clutter_actor_has_mapped_clones (actor)) + return NULL; + actor = clutter_actor_get_parent (actor); + } + while (actor != NULL); + + return priv->unobscured_region; +} + + +static void +set_unobscured_region (MetaSurfaceActor *surface_actor, + cairo_region_t *unobscured_region) +{ + MetaSurfaceActorPrivate *priv = + meta_surface_actor_get_instance_private (surface_actor); + + g_clear_pointer (&priv->unobscured_region, cairo_region_destroy); + if (unobscured_region) + { + cairo_rectangle_int_t bounds = { 0, }; + float width, height; + + clutter_content_get_preferred_size (CLUTTER_CONTENT (priv->texture), + &width, + &height); + bounds = (cairo_rectangle_int_t) { + .width = width, + .height = height, + }; + + priv->unobscured_region = cairo_region_copy (unobscured_region); + cairo_region_intersect_rectangle (priv->unobscured_region, &bounds); + } +} + +static void +set_clip_region (MetaSurfaceActor *surface_actor, + cairo_region_t *clip_region) +{ + MetaSurfaceActorPrivate *priv = + meta_surface_actor_get_instance_private (surface_actor); + + g_clear_pointer (&priv->clip_region, cairo_region_destroy); + if (clip_region) + priv->clip_region = cairo_region_copy (clip_region); +} + +static void +meta_surface_actor_paint (ClutterActor *actor) +{ + MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (actor); + MetaSurfaceActorPrivate *priv = + meta_surface_actor_get_instance_private (surface_actor); + + if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) + return; + + CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->paint (actor); +} + static void meta_surface_actor_pick (ClutterActor *actor, const ClutterColor *color) @@ -126,6 +202,9 @@ meta_surface_actor_dispose (GObject *object) g_clear_pointer (&priv->input_region, cairo_region_destroy); + set_unobscured_region (self, NULL); + set_clip_region (self, NULL); + G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); } @@ -136,6 +215,7 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass) ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); object_class->dispose = meta_surface_actor_dispose; + actor_class->paint = meta_surface_actor_paint; actor_class->pick = meta_surface_actor_pick; actor_class->get_paint_volume = meta_surface_actor_get_paint_volume; @@ -164,17 +244,31 @@ meta_surface_actor_cull_out (MetaCullable *cullable, meta_surface_actor_get_instance_private (surface_actor); uint8_t opacity = clutter_actor_get_opacity (CLUTTER_ACTOR (cullable)); - meta_shaped_texture_cull_out (priv->texture, unobscured_region, clip_region, opacity); + set_unobscured_region (surface_actor, unobscured_region); + set_clip_region (surface_actor, clip_region); + + if (opacity == 0xff) + { + cairo_region_t *opaque_region; + + opaque_region = meta_shaped_texture_get_opaque_region (priv->texture); + + if (opaque_region) + { + if (unobscured_region) + cairo_region_subtract (unobscured_region, opaque_region); + if (clip_region) + cairo_region_subtract (clip_region, opaque_region); + } + } } static void meta_surface_actor_reset_culling (MetaCullable *cullable) { MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (cullable); - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (surface_actor); - meta_shaped_texture_reset_culling (priv->texture); + set_clip_region (surface_actor, NULL); } static void @@ -232,18 +326,58 @@ meta_surface_actor_update_area (MetaSurfaceActor *self, { MetaSurfaceActorPrivate *priv = meta_surface_actor_get_instance_private (self); + gboolean repaint_scheduled = FALSE; + cairo_rectangle_int_t clip; - if (meta_shaped_texture_update_area (priv->texture, x, y, width, height)) + if (meta_shaped_texture_update_area (priv->texture, x, y, width, height, &clip)) + { + cairo_region_t *unobscured_region; + + unobscured_region = effective_unobscured_region (self); + + if (unobscured_region) + { + cairo_region_t *intersection; + + if (cairo_region_is_empty (unobscured_region)) + return; + + intersection = cairo_region_copy (unobscured_region); + cairo_region_intersect_rectangle (intersection, &clip); + + if (!cairo_region_is_empty (intersection)) + { + cairo_rectangle_int_t damage_rect; + + cairo_region_get_extents (intersection, &damage_rect); + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &damage_rect); + repaint_scheduled = TRUE; + } + + cairo_region_destroy (intersection); + } + else + { + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &clip); + repaint_scheduled = TRUE; + } + } + + if (repaint_scheduled) g_signal_emit (self, signals[REPAINT_SCHEDULED], 0); } gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self) { - MetaSurfaceActorPrivate *priv = - meta_surface_actor_get_instance_private (self); + cairo_region_t *unobscured_region; - return meta_shaped_texture_is_obscured (priv->texture); + unobscured_region = effective_unobscured_region (self); + + if (unobscured_region) + return cairo_region_is_empty (unobscured_region); + else + return FALSE; } void diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index c36b8547f..9a4b5e7c6 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -45,11 +45,12 @@ void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, gboolean create_mipmaps); META_EXPORT -gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, - int x, - int y, - int width, - int height); +gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, + int x, + int y, + int width, + int height, + cairo_rectangle_int_t *clip); META_EXPORT CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);