From e33d6b2908f4519bd836ae01ac25318af8a60ea6 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 15 Feb 2019 10:40:05 -0200 Subject: [PATCH 1/9] clutter/paint-node: Expose clutter_paint_node_get_framebuffer() Mutter needs to know which framebuffer the paint nodes will be drawn into, and using cogl_get_draw_framebuffer() directly is not an option since ClutterRootNode only pushes the draw fb at draw time. Expose clutter_paint_node_get_framebuffer(). https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- clutter/clutter/clutter-paint-node-private.h | 2 -- clutter/clutter/clutter-paint-node.c | 9 +++++++++ clutter/clutter/clutter-paint-node.h | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clutter/clutter/clutter-paint-node-private.h b/clutter/clutter/clutter-paint-node-private.h index d61b899514f..b0ac8c56f87 100644 --- a/clutter/clutter/clutter-paint-node-private.h +++ b/clutter/clutter/clutter-paint-node-private.h @@ -138,8 +138,6 @@ G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_last_child (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node); -G_GNUC_INTERNAL -CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node); #define CLUTTER_TYPE_LAYER_NODE (_clutter_layer_node_get_type ()) #define CLUTTER_LAYER_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYER_NODE, ClutterLayerNode)) diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c index e731ca60a26..928c32cced2 100644 --- a/clutter/clutter/clutter-paint-node.c +++ b/clutter/clutter/clutter-paint-node.c @@ -1194,6 +1194,15 @@ clutter_paint_node_get_root (ClutterPaintNode *node) return iter; } +/** + * clutter_paint_node_get_framebuffer: + * @node: a #ClutterPaintNode + * + * Retrieves the #CoglFramebuffer that @node will draw + * into. + * + * Returns: (transfer none): a #CoglFramebuffer + */ CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node) { diff --git a/clutter/clutter/clutter-paint-node.h b/clutter/clutter/clutter-paint-node.h index c42abbc3d8a..cd22e431e26 100644 --- a/clutter/clutter/clutter-paint-node.h +++ b/clutter/clutter/clutter-paint-node.h @@ -56,6 +56,9 @@ CLUTTER_EXPORT void clutter_paint_node_set_name (ClutterPaintNode *node, const char *name); +CLUTTER_EXPORT +CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node); + CLUTTER_EXPORT void clutter_paint_node_add_child (ClutterPaintNode *node, ClutterPaintNode *child); -- GitLab From 75cffd0ec4aeaf8b4577b6690a26260ea5cba4e9 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 26 Dec 2018 13:41:26 -0200 Subject: [PATCH 2/9] shaped-texture: Implement ClutterContent MetaWindowActor is the compositor-side representative of a MetaWindow. Specifically it represents the geometry of the window under Clutter scene graph. MetaWindowActors are backed by MetaSurfaceActors, that represent the windowing system's surfaces themselves. Naturally, these surfaces have textures with the pixel content of the clients associated with them. These textures are represented by MetaShapedTexture. MetaShapedTextures are currently implemented as ClutterActor subclasses that override the paint function to paint the textures it holds. Conceptually, however, Clutter has an abstraction layer for contents of actors: ClutterContent. Which MetaShapedTexture fits nicely, in fact. Make MetaShapedTexture a ClutterContent implementation. This forces a few changes in the stack: * MetaShapedTexture now handles buffer scale. * We now paint into ClutterPaintNode instead of the direct framebuffer. * Various pieces of Wayland code now use MetaSurfaceActor instead of MetaShapedTexture. * MetaSurfaceActorWayland doesn't override size negotiation vfuncs anymore https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-shaped-texture-private.h | 10 +- src/compositor/meta-shaped-texture.c | 502 +++++++++---------- src/compositor/meta-surface-actor-wayland.c | 50 -- src/compositor/meta-surface-actor.c | 20 +- src/compositor/meta-window-actor.c | 33 +- src/meta/meta-window-actor.h | 3 +- src/wayland/meta-wayland-actor-surface.c | 5 +- src/wayland/meta-wayland-data-device.c | 2 +- src/wayland/meta-wayland-surface.c | 4 +- src/wayland/meta-wayland-tablet-tool.c | 2 +- 10 files changed, 276 insertions(+), 355 deletions(-) diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h index a86a2bff0ab..42458daa296 100644 --- a/src/compositor/meta-shaped-texture-private.h +++ b/src/compositor/meta-shaped-texture-private.h @@ -30,7 +30,7 @@ #include "backends/meta-monitor-manager-private.h" #include "meta/meta-shaped-texture.h" -ClutterActor *meta_shaped_texture_new (void); +MetaShapedTexture *meta_shaped_texture_new (void); void meta_shaped_texture_set_texture (MetaShapedTexture *stex, CoglTexture *texture); void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex, @@ -51,5 +51,13 @@ 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); #endif diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 90a02210dfe..667d43d5669 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -58,21 +58,7 @@ static void meta_shaped_texture_dispose (GObject *object); -static void meta_shaped_texture_paint (ClutterActor *actor); - -static void meta_shaped_texture_get_preferred_width (ClutterActor *self, - gfloat for_height, - gfloat *min_width_p, - gfloat *natural_width_p); - -static void meta_shaped_texture_get_preferred_height (ClutterActor *self, - gfloat for_width, - gfloat *min_height_p, - gfloat *natural_height_p); - -static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume); - -static void cullable_iface_init (MetaCullableInterface *iface); +static void clutter_content_iface_init (ClutterContentInterface *iface); enum { @@ -85,7 +71,7 @@ static guint signals[LAST_SIGNAL]; struct _MetaShapedTexture { - ClutterActor parent; + GObject parent; MetaTextureTower *paint_tower; @@ -123,25 +109,22 @@ struct _MetaShapedTexture guint remipmap_timeout_id; gint64 earliest_remipmap; + int buffer_scale; + guint create_mipmaps : 1; }; -G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); +G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, + clutter_content_iface_init)); static void meta_shaped_texture_class_init (MetaShapedTextureClass *klass) { GObjectClass *gobject_class = (GObjectClass *) klass; - ClutterActorClass *actor_class = (ClutterActorClass *) klass; gobject_class->dispose = meta_shaped_texture_dispose; - actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width; - actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height; - actor_class->paint = meta_shaped_texture_paint; - actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume; - signals[SIZE_CHANGED] = g_signal_new ("size-changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, @@ -161,40 +144,30 @@ meta_shaped_texture_init (MetaShapedTexture *stex) { stex->paint_tower = meta_texture_tower_new (); + stex->buffer_scale = 1; stex->texture = NULL; stex->mask_texture = NULL; stex->create_mipmaps = TRUE; stex->is_y_inverted = TRUE; stex->transform = META_MONITOR_TRANSFORM_NORMAL; - - g_signal_connect (stex, - "notify::scale-x", - G_CALLBACK (invalidate_size), - stex); } static void update_size (MetaShapedTexture *stex) { - ClutterActor *actor = CLUTTER_ACTOR (stex); + int buffer_scale = stex->buffer_scale; int dst_width; int dst_height; if (stex->has_viewport_dst_size) { - double tex_scale; - - clutter_actor_get_scale (actor, &tex_scale, NULL); - dst_width = ceil (stex->viewport_dst_width / tex_scale); - dst_height = ceil (stex->viewport_dst_height / tex_scale); + dst_width = stex->viewport_dst_width; + dst_height = stex->viewport_dst_height; } else if (stex->has_viewport_src_rect) { - double tex_scale; - - clutter_actor_get_scale (actor, &tex_scale, NULL); - dst_width = ceil (stex->viewport_src_rect.size.width / tex_scale); - dst_height = ceil (stex->viewport_src_rect.size.height / tex_scale); + dst_width = stex->viewport_src_rect.size.width; + dst_height = stex->viewport_src_rect.size.height; } else { @@ -202,26 +175,26 @@ update_size (MetaShapedTexture *stex) { if (stex->texture) { - dst_width = stex->tex_height; - dst_height = stex->tex_width; + dst_width = stex->tex_height / buffer_scale; + dst_height = stex->tex_width / buffer_scale; } else { - dst_width = stex->fallback_height; - dst_height = stex->fallback_width; + dst_width = stex->fallback_height / buffer_scale; + dst_height = stex->fallback_width / buffer_scale; } } else { if (stex->texture) { - dst_width = stex->tex_width; - dst_height = stex->tex_height; + dst_width = stex->tex_width / buffer_scale; + dst_height = stex->tex_height / buffer_scale; } else { - dst_width = stex->fallback_width; - dst_height = stex->fallback_height; + dst_width = stex->fallback_width / buffer_scale; + dst_height = stex->fallback_height / buffer_scale; } } } @@ -234,7 +207,7 @@ update_size (MetaShapedTexture *stex) stex->dst_width = dst_width; stex->dst_height = dst_height; meta_shaped_texture_set_mask_texture (stex, NULL); - clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); + clutter_content_invalidate_size (CLUTTER_CONTENT (stex)); g_signal_emit (stex, signals[SIZE_CHANGED], 0); } } @@ -377,27 +350,25 @@ get_base_pipeline (MetaShapedTexture *stex, if (stex->has_viewport_src_rect) { - ClutterActor *actor = CLUTTER_ACTOR (stex); - double tex_scale; - - clutter_actor_get_scale (actor, &tex_scale, NULL); + float scaled_tex_width = stex->tex_width / (float) stex->buffer_scale; + float scaled_tex_height = stex->tex_height / (float) stex->buffer_scale; if (meta_monitor_transform_is_rotated (stex->transform)) { cogl_matrix_scale (&matrix, stex->viewport_src_rect.size.width / - (stex->tex_height * tex_scale), + scaled_tex_height, stex->viewport_src_rect.size.height / - (stex->tex_width * tex_scale), + scaled_tex_width, 1); } else { cogl_matrix_scale (&matrix, stex->viewport_src_rect.size.width / - (stex->tex_width * tex_scale), + scaled_tex_width, stex->viewport_src_rect.size.height / - (stex->tex_height * tex_scale), + scaled_tex_height, 1); } @@ -469,21 +440,17 @@ get_unblended_pipeline (MetaShapedTexture *stex, } static void -paint_clipped_rectangle (MetaShapedTexture *stex, - CoglFramebuffer *fb, - CoglPipeline *pipeline, - cairo_rectangle_int_t *rect, - ClutterActorBox *alloc) +paint_clipped_rectangle_node (MetaShapedTexture *stex, + ClutterPaintNode *root_node, + CoglPipeline *pipeline, + cairo_rectangle_int_t *rect, + ClutterActorBox *alloc) { + g_autoptr (ClutterPaintNode) node = NULL; float coords[8]; - float x1, y1, x2, y2; float alloc_width; float alloc_height; - x1 = rect->x; - y1 = rect->y; - x2 = rect->x + rect->width; - y2 = rect->y + rect->height; alloc_width = alloc->x2 - alloc->x1; alloc_height = alloc->y2 - alloc->y1; @@ -497,9 +464,18 @@ paint_clipped_rectangle (MetaShapedTexture *stex, coords[6] = coords[2]; coords[7] = coords[3]; - cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline, - x1, y1, x2, y2, - &coords[0], 8); + node = clutter_pipeline_node_new (pipeline); + clutter_paint_node_set_name (node, "MetaShapedTexture (clipped)"); + clutter_paint_node_add_child (root_node, node); + + clutter_paint_node_add_multitexture_rectangle (node, + &(ClutterActorBox) { + .x1 = rect->x, + .x2 = rect->x + rect->width, + .y1 = rect->y, + .y2 = rect->y + rect->height, + }, + coords, 8); } static void @@ -542,6 +518,8 @@ set_cogl_texture (MetaShapedTexture *stex, if (stex->create_mipmaps) meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex); + + clutter_content_invalidate (CLUTTER_CONTENT (stex)); } static gboolean @@ -552,39 +530,47 @@ texture_is_idle_and_not_mipmapped (gpointer user_data) if ((g_get_monotonic_time () - stex->earliest_remipmap) < 0) return G_SOURCE_CONTINUE; - clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); + clutter_content_invalidate (CLUTTER_CONTENT (stex)); stex->remipmap_timeout_id = 0; return G_SOURCE_REMOVE; } +static cairo_region_t * +effective_unobscured_region (MetaShapedTexture *stex) +{ + return stex->unobscured_region; +} + static void -do_paint (MetaShapedTexture *stex, - CoglFramebuffer *fb, - CoglTexture *paint_tex, - cairo_region_t *clip_region) +do_paint_content (MetaShapedTexture *stex, + ClutterPaintNode *root_node, + CoglTexture *paint_tex, + ClutterActorBox *alloc, + uint8_t opacity) + { - double tex_scale; int dst_width, dst_height; - cairo_rectangle_int_t tex_rect; - guchar opacity; + cairo_rectangle_int_t content_rect; gboolean use_opaque_region; - cairo_region_t *clip_tex_region; - cairo_region_t *opaque_tex_region; cairo_region_t *blended_tex_region; CoglContext *ctx; - ClutterActorBox alloc; CoglPipelineFilter filter; - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); ensure_size_valid (stex); - dst_width = stex->dst_width; + dst_width = stex->dst_width; dst_height = stex->dst_height; + if (dst_width == 0 || dst_height == 0) /* no contents yet */ return; - tex_rect = (cairo_rectangle_int_t) { 0, 0, dst_width, dst_height }; + content_rect = (cairo_rectangle_int_t) { + .x = 0, + .y = 0, + .width = dst_width, + .height = dst_height, + }; /* Use nearest-pixel interpolation if the texture is unscaled. This * improves performance, especially with software rendering. @@ -592,55 +578,28 @@ do_paint (MetaShapedTexture *stex, filter = COGL_PIPELINE_FILTER_LINEAR; - if (meta_actor_painting_untransformed (fb, + if (meta_actor_painting_untransformed (clutter_paint_node_get_framebuffer (root_node), dst_width, dst_height, NULL, NULL)) filter = COGL_PIPELINE_FILTER_NEAREST; ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex)); - clutter_actor_get_allocation_box (CLUTTER_ACTOR (stex), &alloc); - - if (stex->opaque_region && opacity == 255) - { - opaque_tex_region = - meta_region_scale_double (stex->opaque_region, - 1.0 / tex_scale, - META_ROUNDING_STRATEGY_SHRINK); - use_opaque_region = TRUE; - } - else - { - opaque_tex_region = NULL; - use_opaque_region = FALSE; - } - - if (clip_region) - { - clip_tex_region = - meta_region_scale_double (clip_region, - 1.0 / tex_scale, - META_ROUNDING_STRATEGY_GROW); - } - else - { - clip_tex_region = NULL; - } + use_opaque_region = stex->opaque_region && opacity == 255; if (use_opaque_region) { - if (clip_tex_region) - blended_tex_region = cairo_region_copy (clip_tex_region); + if (stex->clip_region) + blended_tex_region = cairo_region_copy (stex->clip_region); else - blended_tex_region = cairo_region_create_rectangle (&tex_rect); + blended_tex_region = cairo_region_create_rectangle (&content_rect); - cairo_region_subtract (blended_tex_region, opaque_tex_region); + cairo_region_subtract (blended_tex_region, stex->opaque_region); } else { - if (clip_tex_region) - blended_tex_region = cairo_region_reference (clip_tex_region); + if (stex->clip_region) + blended_tex_region = cairo_region_reference (stex->clip_region); else blended_tex_region = NULL; } @@ -664,23 +623,24 @@ do_paint (MetaShapedTexture *stex, /* First, paint the unblended parts, which are part of the opaque region. */ if (use_opaque_region) { - CoglPipeline *opaque_pipeline; cairo_region_t *region; int n_rects; int i; - if (clip_tex_region) + if (stex->clip_region) { - region = cairo_region_copy (clip_tex_region); - cairo_region_intersect (region, opaque_tex_region); + region = cairo_region_copy (stex->clip_region); + cairo_region_intersect (region, stex->opaque_region); } else { - region = cairo_region_reference (opaque_tex_region); + region = cairo_region_reference (stex->opaque_region); } if (!cairo_region_is_empty (region)) { + CoglPipeline *opaque_pipeline; + opaque_pipeline = get_unblended_pipeline (stex, ctx); cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); @@ -690,11 +650,9 @@ do_paint (MetaShapedTexture *stex, { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); - paint_clipped_rectangle (stex, - fb, - opaque_pipeline, - &rect, - &alloc); + paint_clipped_rectangle_node (stex, root_node, + opaque_pipeline, + &rect, alloc); } } @@ -744,78 +702,56 @@ do_paint (MetaShapedTexture *stex, cairo_rectangle_int_t rect; cairo_region_get_rectangle (blended_tex_region, i, &rect); - if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect)) + if (!gdk_rectangle_intersect (&content_rect, &rect, &rect)) continue; - paint_clipped_rectangle (stex, - fb, - blended_pipeline, - &rect, - &alloc); + paint_clipped_rectangle_node (stex, root_node, + blended_pipeline, + &rect, alloc); } } else { + g_autoptr (ClutterPaintNode) node = NULL; + + node = clutter_pipeline_node_new (blended_pipeline); + clutter_paint_node_set_name (node, "MetaShapedTexture (unclipped)"); + clutter_paint_node_add_child (root_node, node); + /* 3) blended_tex_region is NULL. Do a full paint. */ - cogl_framebuffer_draw_rectangle (fb, blended_pipeline, - 0, 0, - alloc.x2 - alloc.x1, - alloc.y2 - alloc.y1); + clutter_paint_node_add_rectangle (node, alloc); } } - g_clear_pointer (&clip_tex_region, cairo_region_destroy); - g_clear_pointer (&opaque_tex_region, cairo_region_destroy); g_clear_pointer (&blended_tex_region, cairo_region_destroy); } -static void -meta_shaped_texture_paint (ClutterActor *actor) +static CoglTexture * +select_texture_for_paint (MetaShapedTexture *stex) { - MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor); - CoglTexture *paint_tex; - CoglFramebuffer *fb; + CoglTexture *texture = NULL; + int64_t now; if (!stex->texture) - return; - - if (stex->clip_region && cairo_region_is_empty (stex->clip_region)) - return; + return NULL; - if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) - clutter_actor_realize (CLUTTER_ACTOR (stex)); + now = g_get_monotonic_time (); - /* 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 - * are distinct performance implications from: - * - * - Updating mipmaps that we don't need - * - Having to reallocate pixmaps on the server into larger buffers - * - * So, we just unconditionally use our mipmap emulation code. If we - * wanted to use SGIS_generate_mipmap, we'd have to query COGL to - * see if it was supported (no API currently), and then if and only - * if that was the case, set the clutter texture quality to HIGH. - * Setting the texture quality to high without SGIS_generate_mipmap - * support for TFP textures will result in fallbacks to XGetImage. - */ - if (stex->create_mipmaps) + if (stex->create_mipmaps && stex->last_invalidation) { - int64_t now = g_get_monotonic_time (); int64_t age = now - stex->last_invalidation; if (age >= MIN_MIPMAP_AGE_USEC || stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) - { - paint_tex = meta_texture_tower_get_paint_texture (stex->paint_tower); - if (!paint_tex) - paint_tex = stex->texture; - } - else - { - paint_tex = stex->texture; + texture = meta_texture_tower_get_paint_texture (stex->paint_tower); + } + + if (!texture) + { + texture = stex->texture; + if (stex->create_mipmaps) + { /* Minus 1000 to ensure we don't fail the age test in timeout */ stex->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000; @@ -826,74 +762,71 @@ meta_shaped_texture_paint (ClutterActor *actor) stex); } } - else - { - paint_tex = COGL_TEXTURE (stex->texture); - } - if (cogl_texture_get_width (paint_tex) == 0 || - cogl_texture_get_height (paint_tex) == 0) - return; - - fb = cogl_get_draw_framebuffer (); - do_paint (META_SHAPED_TEXTURE (actor), fb, paint_tex, stex->clip_region); + return texture; } static void -meta_shaped_texture_get_preferred_width (ClutterActor *self, - gfloat for_height, - gfloat *min_width_p, - gfloat *natural_width_p) +meta_shaped_texture_paint_content (ClutterContent *content, + ClutterActor *actor, + ClutterPaintNode *root_node) { - MetaShapedTexture *stex = META_SHAPED_TEXTURE (self); + MetaShapedTexture *stex = META_SHAPED_TEXTURE (content); + ClutterActorBox alloc; + CoglTexture *paint_tex = NULL; + uint8_t opacity; - ensure_size_valid (stex); + if (stex->clip_region && cairo_region_is_empty (stex->clip_region)) + return; - if (min_width_p) - *min_width_p = stex->dst_width; - if (natural_width_p) - *natural_width_p = stex->dst_width; + /* 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 + * are distinct performance implications from: + * + * - Updating mipmaps that we don't need + * - Having to reallocate pixmaps on the server into larger buffers + * + * So, we just unconditionally use our mipmap emulation code. If we + * wanted to use SGIS_generate_mipmap, we'd have to query COGL to + * see if it was supported (no API currently), and then if and only + * if that was the case, set the clutter texture quality to HIGH. + * Setting the texture quality to high without SGIS_generate_mipmap + * support for TFP textures will result in fallbacks to XGetImage. + */ + paint_tex = select_texture_for_paint (stex); + if (!paint_tex) + return; + + opacity = clutter_actor_get_paint_opacity (actor); + clutter_actor_get_content_box (actor, &alloc); + + do_paint_content (stex, root_node, paint_tex, &alloc, opacity); } -static void -meta_shaped_texture_get_preferred_height (ClutterActor *self, - gfloat for_width, - gfloat *min_height_p, - gfloat *natural_height_p) +static gboolean +meta_shaped_texture_get_preferred_size (ClutterContent *content, + float *width, + float *height) { - MetaShapedTexture *stex = META_SHAPED_TEXTURE (self); + MetaShapedTexture *stex = META_SHAPED_TEXTURE (content); ensure_size_valid (stex); - if (min_height_p) - *min_height_p = stex->dst_height; - if (natural_height_p) - *natural_height_p = stex->dst_height; -} - -static cairo_region_t * -effective_unobscured_region (MetaShapedTexture *stex) -{ - ClutterActor *actor; + if (width) + *width = stex->dst_width; - /* Fail if we have any mapped clones. */ - actor = CLUTTER_ACTOR (stex); - do - { - if (clutter_actor_has_mapped_clones (actor)) - return NULL; - actor = clutter_actor_get_parent (actor); - } - while (actor != NULL); + if (height) + *height = stex->dst_height; - return stex->unobscured_region; + return TRUE; } -static gboolean -meta_shaped_texture_get_paint_volume (ClutterActor *actor, - ClutterPaintVolume *volume) +static void +clutter_content_iface_init (ClutterContentInterface *iface) { - return clutter_paint_volume_set_from_allocation (volume, actor); + iface->paint_content = meta_shaped_texture_paint_content; + iface->get_preferred_size = meta_shaped_texture_get_preferred_size; } void @@ -927,7 +860,7 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, cogl_object_ref (stex->mask_texture); } - clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); + clutter_content_invalidate (CLUTTER_CONTENT (stex)); } gboolean @@ -987,14 +920,11 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, { ClutterRect viewport; ClutterRect inverted_viewport; - double tex_scale; float dst_width; float dst_height; int inverted_dst_width; int inverted_dst_height; - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); - if (stex->has_viewport_src_rect) { viewport = stex->viewport_src_rect; @@ -1004,8 +934,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, viewport = (ClutterRect) { .origin.x = 0, .origin.y = 0, - .size.width = stex->tex_width * tex_scale, - .size.height = stex->tex_height * tex_scale + .size.width = stex->tex_width, + .size.height = stex->tex_height, }; } @@ -1016,13 +946,13 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } else { - dst_width = (float) stex->tex_width * tex_scale; - dst_height = (float) stex->tex_height * tex_scale; + dst_width = (float) stex->tex_width; + dst_height = (float) stex->tex_height; } inverted_viewport = (ClutterRect) { - .origin.x = -((viewport.origin.x * (dst_width / viewport.size.width)) / tex_scale), - .origin.y = -((viewport.origin.y * (dst_height / viewport.size.height)) / tex_scale), + .origin.x = -(viewport.origin.x * (dst_width / viewport.size.width)), + .origin.y = -(viewport.origin.y * (dst_height / viewport.size.height)), .size.width = dst_width, .size.height = dst_height }; @@ -1037,10 +967,10 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } meta_texture_tower_update_area (stex->paint_tower, - clip.x, - clip.y, - clip.width, - clip.height); + x, + y, + width, + height); stex->prev_invalidation = stex->last_invalidation; stex->last_invalidation = g_get_monotonic_time (); @@ -1059,6 +989,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, 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)) @@ -1071,7 +1003,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, { cairo_rectangle_int_t damage_rect; cairo_region_get_extents (intersection, &damage_rect); - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect); + clutter_content_invalidate (CLUTTER_CONTENT (stex)); cairo_region_destroy (intersection); return TRUE; } @@ -1081,7 +1013,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } else { - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip); + clutter_content_invalidate (CLUTTER_CONTENT (stex)); return TRUE; } } @@ -1274,6 +1206,7 @@ static cairo_surface_t * get_image_via_offscreen (MetaShapedTexture *stex, cairo_rectangle_int_t *clip) { + g_autoptr (ClutterPaintNode) root_node = NULL; ClutterBackend *clutter_backend = clutter_get_default_backend (); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); @@ -1283,7 +1216,7 @@ get_image_via_offscreen (MetaShapedTexture *stex, CoglFramebuffer *fb; CoglMatrix projection_matrix; cairo_rectangle_int_t fallback_clip; - CoglColor clear_color; + ClutterColor clear_color; cairo_surface_t *surface; if (!clip) @@ -1329,12 +1262,20 @@ get_image_via_offscreen (MetaShapedTexture *stex, cogl_framebuffer_set_projection_matrix (fb, &projection_matrix); - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color); + clear_color = (ClutterColor) { 0, 0, 0, 0 }; + + root_node = clutter_root_node_new (fb, &clear_color, COGL_BUFFER_BIT_COLOR); + clutter_paint_node_set_name (root_node, "MetaShapedTexture.offscreen"); - do_paint (stex, fb, stex->texture, NULL); + do_paint_content (stex, root_node, + stex->texture, + &(ClutterActorBox) { + clip->x, clip->y, + clip->width, clip->height, + }, + 255); - cogl_framebuffer_pop_matrix (fb); + clutter_paint_node_paint (root_node); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, clip->width, clip->height); @@ -1386,13 +1327,11 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (clip != NULL) { - double tex_scale; cairo_rectangle_int_t dst_rect; transformed_clip = alloca (sizeof (cairo_rectangle_int_t)); - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); - meta_rectangle_scale_double (clip, 1.0 / tex_scale, + meta_rectangle_scale_double (clip, stex->buffer_scale, META_ROUNDING_STRATEGY_GROW, transformed_clip); @@ -1479,17 +1418,46 @@ meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, invalidate_size (stex); } -static void -meta_shaped_texture_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) +MetaShapedTexture * +meta_shaped_texture_new (void) +{ + return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); +} + +void +meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, + int buffer_scale) +{ + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); + + if (buffer_scale == stex->buffer_scale) + return; + + stex->buffer_scale = buffer_scale; + + invalidate_size (stex); +} + +int +meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex) { - MetaShapedTexture *stex = META_SHAPED_TEXTURE (cullable); + g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 1.0); + + 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 (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex)) == 0xff) + if (opacity == 0xff) { if (stex->opaque_region) { @@ -1501,22 +1469,10 @@ meta_shaped_texture_cull_out (MetaCullable *cullable, } } -static void -meta_shaped_texture_reset_culling (MetaCullable *cullable) -{ - MetaShapedTexture *self = META_SHAPED_TEXTURE (cullable); - set_clip_region (self, NULL); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) +void +meta_shaped_texture_reset_culling (MetaShapedTexture *stex) { - iface->cull_out = meta_shaped_texture_cull_out; - iface->reset_culling = meta_shaped_texture_reset_culling; -} + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); -ClutterActor * -meta_shaped_texture_new (void) -{ - return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); + set_clip_region (stex, NULL); } diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index f8d6c32b766..27c600c593e 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -110,54 +110,6 @@ meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor) return surface->window; } -static void -meta_surface_actor_wayland_get_preferred_width (ClutterActor *actor, - gfloat for_height, - gfloat *min_width_p, - gfloat *natural_width_p) -{ - MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); - MetaShapedTexture *stex; - double scale; - - stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &scale, NULL); - clutter_actor_get_preferred_width (CLUTTER_ACTOR (stex), - for_height, - min_width_p, - natural_width_p); - - if (min_width_p) - *min_width_p *= scale; - - if (natural_width_p) - *natural_width_p *= scale; -} - -static void -meta_surface_actor_wayland_get_preferred_height (ClutterActor *actor, - gfloat for_width, - gfloat *min_height_p, - gfloat *natural_height_p) -{ - MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); - MetaShapedTexture *stex; - double scale; - - stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); - clutter_actor_get_scale (CLUTTER_ACTOR (stex), NULL, &scale); - clutter_actor_get_preferred_height (CLUTTER_ACTOR (stex), - for_width, - min_height_p, - natural_height_p); - - if (min_height_p) - *min_height_p *= scale; - - if (natural_height_p) - *natural_height_p *= scale; -} - static void meta_surface_actor_wayland_paint (ClutterActor *actor) { @@ -203,8 +155,6 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); - actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width; - actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height; actor_class->paint = meta_surface_actor_wayland_paint; surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index ca4ca19a99e..e50eb80186e 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -159,13 +159,22 @@ meta_surface_actor_cull_out (MetaCullable *cullable, cairo_region_t *unobscured_region, cairo_region_t *clip_region) { - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); + MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (cullable); + MetaSurfaceActorPrivate *priv = + 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); } static void meta_surface_actor_reset_culling (MetaCullable *cullable) { - meta_cullable_reset_culling_children (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); } static void @@ -189,10 +198,13 @@ meta_surface_actor_init (MetaSurfaceActor *self) MetaSurfaceActorPrivate *priv = meta_surface_actor_get_instance_private (self); - priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ()); + priv->texture = meta_shaped_texture_new (); g_signal_connect_object (priv->texture, "size-changed", G_CALLBACK (texture_size_changed), self, 0); - clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture)); + clutter_actor_set_content (CLUTTER_ACTOR (self), + CLUTTER_CONTENT (priv->texture)); + clutter_actor_set_request_mode (CLUTTER_ACTOR (self), + CLUTTER_REQUEST_CONTENT_SIZE); } cairo_surface_t * diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 375d7bc0a4b..81aaf4e2e44 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -833,14 +833,14 @@ meta_window_actor_get_meta_window (MetaWindowActor *self) * * Return value: (transfer none): the #ClutterActor for the contents */ -ClutterActor * +MetaShapedTexture * meta_window_actor_get_texture (MetaWindowActor *self) { MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); if (priv->surface) - return CLUTTER_ACTOR (meta_surface_actor_get_texture (priv->surface)); + return meta_surface_actor_get_texture (priv->surface); else return NULL; } @@ -1902,19 +1902,19 @@ meta_window_actor_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, MetaShapedTexture *stex; MetaRectangle buffer_rect; MetaRectangle frame_rect; - double scale_x, scale_y; + int buffer_scale; stex = meta_surface_actor_get_texture (priv->surface); - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &scale_x, &scale_y); + buffer_scale = meta_shaped_texture_get_buffer_scale (stex); window = priv->window; meta_window_get_buffer_rect (window, &buffer_rect); meta_window_get_frame_rect (window, &frame_rect); - bounds->x = (int) floor ((frame_rect.x - buffer_rect.x) / scale_x); - bounds->y = (int) floor ((frame_rect.y - buffer_rect.y) / scale_y); - bounds->width = (int) ceil (frame_rect.width / scale_x); - bounds->height = (int) ceil (frame_rect.height / scale_y); + bounds->x = (int) floor ((frame_rect.x - buffer_rect.x) / (float) buffer_scale); + bounds->y = (int) floor ((frame_rect.y - buffer_rect.y) / (float) buffer_scale); + bounds->width = (int) ceil (frame_rect.width / (float) buffer_scale); + bounds->height = (int) ceil (frame_rect.height / (float) buffer_scale); } static void @@ -1928,7 +1928,6 @@ meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (window_actor); - MetaShapedTexture *stex; MetaRectangle bounds; ClutterVertex v1 = { 0.f, }, v2 = { 0.f, }; @@ -1941,8 +1940,9 @@ meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast bounds.y, bounds.y + bounds.height); - stex = meta_surface_actor_get_texture (priv->surface); - clutter_actor_apply_transform_to_point (CLUTTER_ACTOR (stex), &v1, &v2); + clutter_actor_apply_transform_to_point (CLUTTER_ACTOR (priv->surface), + &v1, + &v2); *x_out = (double) v2.x; *y_out = (double) v2.y; @@ -1969,22 +1969,19 @@ meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_w out_cursor_scale) { MetaShapedTexture *stex; - double actor_scale; + double texture_scale; float cursor_texture_scale; stex = meta_surface_actor_get_texture (priv->surface); - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &actor_scale, NULL); + texture_scale = meta_shaped_texture_get_buffer_scale (stex); cursor_texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); - *out_cursor_scale = actor_scale / cursor_texture_scale; + *out_cursor_scale = texture_scale / cursor_texture_scale; } if (out_relative_cursor_position) { - MetaShapedTexture *stex; - - stex = meta_surface_actor_get_texture (priv->surface); - clutter_actor_transform_stage_point (CLUTTER_ACTOR (stex), + clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->surface), cursor_position->x, cursor_position->y, &out_relative_cursor_position->x, diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h index 9ba16491054..ad4b7bf1dc2 100644 --- a/src/meta/meta-window-actor.h +++ b/src/meta/meta-window-actor.h @@ -25,6 +25,7 @@ #include "clutter/clutter.h" #include "meta/compositor.h" +#include "meta/meta-shaped-texture.h" #define META_TYPE_WINDOW_ACTOR (meta_window_actor_get_type ()) @@ -38,7 +39,7 @@ META_EXPORT MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self); META_EXPORT -ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self); +MetaShapedTexture *meta_window_actor_get_texture (MetaWindowActor *self); META_EXPORT void meta_window_actor_sync_visibility (MetaWindowActor *self); diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index bd987e970c6..979422bae80 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -154,16 +154,13 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor meta_wayland_surface_role_get_surface (surface_role); MetaSurfaceActor *surface_actor; MetaShapedTexture *stex; - double actor_scale; GList *l; cairo_rectangle_int_t surface_rect; int geometry_scale; surface_actor = priv->actor; stex = meta_surface_actor_get_texture (surface_actor); - - actor_scale = meta_wayland_actor_surface_calculate_scale (actor_surface); - clutter_actor_set_scale (CLUTTER_ACTOR (stex), actor_scale, actor_scale); + meta_shaped_texture_set_buffer_scale (stex, surface->scale); /* Wayland surface coordinate space -> stage coordinate space */ geometry_scale = meta_wayland_actor_surface_get_geometry_scale (actor_surface); diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index ba9591ec1aa..7eeac7e3162 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -1197,7 +1197,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data surface_actor = meta_wayland_surface_get_actor (surface); - clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface_actor)), + clutter_actor_transform_stage_point (CLUTTER_ACTOR (surface_actor), seat->pointer->grab_x, seat->pointer->grab_y, &surface_pos.x, &surface_pos.y); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 3bf9bc9cea4..f9cc118b658 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1581,7 +1581,7 @@ meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface, else { ClutterActor *actor = - CLUTTER_ACTOR (meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface))); + CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)); clutter_actor_transform_stage_point (actor, abs_x, abs_y, sx, sy); *sx /= surface->scale; @@ -1597,7 +1597,7 @@ meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface, float *y) { ClutterActor *actor = - CLUTTER_ACTOR (meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface))); + CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)); ClutterVertex sv = { .x = sx * surface->scale, .y = sy * surface->scale, diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index d243608cffe..a149b1e670c 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -663,7 +663,7 @@ meta_wayland_tablet_tool_get_relative_coordinates (MetaWaylandTabletTool *tool, surface_actor = meta_wayland_surface_get_actor (surface); clutter_event_get_coords (event, &xf, &yf); - clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface_actor)), + clutter_actor_transform_stage_point (CLUTTER_ACTOR (surface_actor), xf, yf, &xf, &yf); *sx = wl_fixed_from_double (xf) / surface->scale; -- GitLab From d3f30d9ece3ad9b10bee03efa69dee825d775a46 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Tue, 9 Jul 2019 12:29:37 -0300 Subject: [PATCH 3/9] wayland/actor-surface: Set geometry scale in surface actor Now that MetaShapedTexture is a ClutterContent implemetation that is aware of its own buffer scale, it is possible to simplify the event translation routines. Set the geometry scale in MetaSurfaceActor, and stop adjusting the surface scale when translating points. Also remove the now obsoleted meta_wayland_actor_surface_calculate_scale() function. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/wayland/meta-wayland-actor-surface.c | 20 ++++---------------- src/wayland/meta-wayland-actor-surface.h | 4 +--- src/wayland/meta-wayland-shell-surface.c | 12 ++++++------ src/wayland/meta-wayland-surface.c | 2 -- 4 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index 979422bae80..bf964dcae75 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -104,7 +104,7 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor wl_list_init (&pending->frame_callback_list); } -static double +double meta_wayland_actor_surface_get_geometry_scale (MetaWaylandActorSurface *actor_surface) { MetaWaylandSurfaceRole *surface_role = @@ -128,21 +128,6 @@ meta_wayland_actor_surface_get_geometry_scale (MetaWaylandActorSurface *actor_su } } -double -meta_wayland_actor_surface_calculate_scale (MetaWaylandActorSurface *actor_surface) -{ - MetaWaylandSurfaceRole *surface_role = - META_WAYLAND_SURFACE_ROLE (actor_surface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - double geometry_scale; - - geometry_scale = - meta_wayland_actor_surface_get_geometry_scale (actor_surface); - - return geometry_scale / (double) surface->scale; -} - static void meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor_surface) { @@ -164,6 +149,9 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor /* Wayland surface coordinate space -> stage coordinate space */ geometry_scale = meta_wayland_actor_surface_get_geometry_scale (actor_surface); + clutter_actor_set_scale (CLUTTER_ACTOR (surface_actor), + geometry_scale, + geometry_scale); surface_rect = (cairo_rectangle_int_t) { .width = meta_wayland_surface_get_width (surface) * geometry_scale, diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h index 444b3b17856..aa9f8fa5ac2 100644 --- a/src/wayland/meta-wayland-actor-surface.h +++ b/src/wayland/meta-wayland-actor-surface.h @@ -37,9 +37,7 @@ struct _MetaWaylandActorSurfaceClass }; void meta_wayland_actor_surface_sync_actor_state (MetaWaylandActorSurface *actor_surface); - -double meta_wayland_actor_surface_calculate_scale (MetaWaylandActorSurface *actor_surface); - +double meta_wayland_actor_surface_get_geometry_scale (MetaWaylandActorSurface *actor_surface); MetaSurfaceActor * meta_wayland_actor_surface_get_actor (MetaWaylandActorSurface *actor_surface); void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surface); diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index f8354ab7c5e..3ebfdd2843f 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -153,8 +153,7 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole *surface_role MetaWaylandSurfaceRoleClass *surface_role_class; MetaWindow *window; MetaWaylandBuffer *buffer; - CoglTexture *texture; - double scale; + double geometry_scale; surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class); @@ -168,11 +167,12 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole *surface_role if (!window) return; - scale = meta_wayland_actor_surface_calculate_scale (actor_surface); - texture = meta_wayland_surface_get_texture (surface); + geometry_scale = meta_wayland_actor_surface_get_geometry_scale (actor_surface); - window->buffer_rect.width = cogl_texture_get_width (texture) * scale; - window->buffer_rect.height = cogl_texture_get_height (texture) * scale; + window->buffer_rect.width = + meta_wayland_surface_get_width (surface) * geometry_scale; + window->buffer_rect.height = + meta_wayland_surface_get_height (surface) * geometry_scale; } static void diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index f9cc118b658..787265f3360 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1584,8 +1584,6 @@ meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface, CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)); clutter_actor_transform_stage_point (actor, abs_x, abs_y, sx, sy); - *sx /= surface->scale; - *sy /= surface->scale; } } -- GitLab From 425e65049b398a85c5579d8b421d4fdbf0778984 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 27 Dec 2018 14:16:50 -0200 Subject: [PATCH 4/9] shaped-texture: Draw pipeline relative to alloc By implementing ClutterContent, it is expected that MetaShapedTexture can draw on any actor. However, right now this is not possible, since it assumes that the drawing coordinates and sizes of the actor are synchronized with its own reported width and height. It mistakenly draws, for example, when setting an actor's content to it. There is no way to trigger this wrong behavior right now, but it will become a problem in the future where we can collect the paint nodes of MetaShapedTexture as part of other ClutterContent implementations. Use the allocation box passed by the actor to draw the pipelines of MetaShapedTexture. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-shaped-texture.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 667d43d5669..308d9361a9b 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -447,17 +447,27 @@ paint_clipped_rectangle_node (MetaShapedTexture *stex, ClutterActorBox *alloc) { g_autoptr (ClutterPaintNode) node = NULL; + float ratio_h, ratio_v; + float x1, y1, x2, y2; float coords[8]; float alloc_width; float alloc_height; + ratio_h = clutter_actor_box_get_width (alloc) / (float) stex->dst_width; + ratio_v = clutter_actor_box_get_height (alloc) / (float) stex->dst_height; + + x1 = alloc->x1 + rect->x * ratio_h; + y1 = alloc->y1 + rect->y * ratio_v; + x2 = alloc->x1 + (rect->x + rect->width) * ratio_h; + y2 = alloc->y1 + (rect->y + rect->height) * ratio_v; + alloc_width = alloc->x2 - alloc->x1; alloc_height = alloc->y2 - alloc->y1; - coords[0] = rect->x / alloc_width; - coords[1] = rect->y / alloc_height; - coords[2] = (rect->x + rect->width) / alloc_width; - coords[3] = (rect->y + rect->height) / alloc_height; + coords[0] = rect->x / alloc_width * ratio_h; + coords[1] = rect->y / alloc_height * ratio_v; + coords[2] = (rect->x + rect->width) / alloc_width * ratio_h; + coords[3] = (rect->y + rect->height) / alloc_height * ratio_v; coords[4] = coords[0]; coords[5] = coords[1]; @@ -470,10 +480,10 @@ paint_clipped_rectangle_node (MetaShapedTexture *stex, clutter_paint_node_add_multitexture_rectangle (node, &(ClutterActorBox) { - .x1 = rect->x, - .x2 = rect->x + rect->width, - .y1 = rect->y, - .y2 = rect->y + rect->height, + .x1 = x1, + .y1 = y1, + .x2 = x2, + .y2 = y2, }, coords, 8); } -- GitLab From 4c1fde9deb55c67d749c6044435c99e0682feebc Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Tue, 29 Jan 2019 19:53:50 -0200 Subject: [PATCH 5/9] shaped-texture: Move MetaCullable helpers to MetaSurfaceActor Now that MetaShapedTexture is not a ClutterActor anymore, it does not make sense to make it a MetaCullable semi-implementation. This is, naturally, a responsibility of MetaSurfaceActor, since now MetaShapedTexture is a ClutterContent and as such, it only cares about what to draw. Move the MetaCullable implementation of MetaShapedTexture to MetaSurfaceActor. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-shaped-texture-private.h | 6 - src/compositor/meta-shaped-texture.c | 177 +++---------------- src/compositor/meta-surface-actor.c | 150 +++++++++++++++- src/meta/meta-shaped-texture.h | 11 +- 4 files changed, 171 insertions(+), 173 deletions(-) diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h index 42458daa296..6839b0872f2 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 308d9361a9b..f85b55e23b5 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 e50eb80186e..c7256c3b877 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, &clip)) + { + cairo_region_t *unobscured_region; + + unobscured_region = effective_unobscured_region (self); - if (meta_shaped_texture_update_area (priv->texture, x, y, width, height)) + 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 c36b8547f3e..9a4b5e7c62f 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); -- GitLab From 6b35a4901e27b60c530254a4a635b9699493758c Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Mon, 11 Feb 2019 13:25:30 -0200 Subject: [PATCH 6/9] shaped-texture: Move private function to private header meta_shaped_texture_update_area() is a private function that is exposed in the public headers. It is not used anywhere outside Mutter, and should really be in the private header. Move it to the private header. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-shaped-texture-private.h | 7 +++++++ src/meta/meta-shaped-texture.h | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h index 6839b0872f2..8b078229ce5 100644 --- a/src/compositor/meta-shaped-texture-private.h +++ b/src/compositor/meta-shaped-texture-private.h @@ -54,4 +54,11 @@ void meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, int buffer_scale); int meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex); +gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, + int x, + int y, + int width, + int height, + cairo_rectangle_int_t *clip); + #endif diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index 9a4b5e7c62f..d38a6dae17e 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -44,14 +44,6 @@ META_EXPORT 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, - cairo_rectangle_int_t *clip); - META_EXPORT CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); -- GitLab From 2d7adb90c83c1c19e934eb19aec4760f52bb4757 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Tue, 9 Jul 2019 12:36:16 -0300 Subject: [PATCH 7/9] wayland/tablet-tool: Use meta_wayland_surface_get_relative_coordinates() Instead of directly calling into clutter_actor_transform_stage_point(). https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/wayland/meta-wayland-tablet-tool.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index a149b1e670c..52c63dd96c9 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -657,14 +657,10 @@ meta_wayland_tablet_tool_get_relative_coordinates (MetaWaylandTabletTool *tool, wl_fixed_t *sx, wl_fixed_t *sy) { - MetaSurfaceActor *surface_actor; float xf, yf; - surface_actor = meta_wayland_surface_get_actor (surface); - clutter_event_get_coords (event, &xf, &yf); - clutter_actor_transform_stage_point (CLUTTER_ACTOR (surface_actor), - xf, yf, &xf, &yf); + meta_wayland_surface_get_relative_coordinates (surface, xf, yf, &xf, &yf); *sx = wl_fixed_from_double (xf) / surface->scale; *sy = wl_fixed_from_double (yf) / surface->scale; -- GitLab From c747be84d97085f31782879b98d911cac4bd9c40 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 12 Jul 2019 13:56:14 -0300 Subject: [PATCH 8/9] wayland: Don't scale input and opaque regions Leave them at surface coordinates and let MetaSurfaceActor and MetaShapedTexture handle the interactions between buffer and geometry scale. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-surface-actor.c | 24 +++++++++++++++------- src/wayland/meta-wayland-actor-surface.c | 26 ++++++++++-------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index c7256c3b877..79c621214a4 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -22,6 +22,7 @@ #include "clutter/clutter.h" #include "compositor/meta-cullable.h" #include "compositor/meta-shaped-texture-private.h" +#include "compositor/region-utils.h" #include "meta/meta-shaped-texture.h" typedef struct _MetaSurfaceActorPrivate @@ -249,17 +250,26 @@ meta_surface_actor_cull_out (MetaCullable *cullable, if (opacity == 0xff) { + cairo_region_t *scaled_opaque_region; cairo_region_t *opaque_region; + double geometry_scale; 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); - } + if (!opaque_region) + return; + + clutter_actor_get_scale (CLUTTER_ACTOR (surface_actor), + &geometry_scale, + NULL); + scaled_opaque_region = meta_region_scale (opaque_region, geometry_scale); + + if (unobscured_region) + cairo_region_subtract (unobscured_region, scaled_opaque_region); + if (clip_region) + cairo_region_subtract (clip_region, scaled_opaque_region); + + cairo_region_destroy (scaled_opaque_region); } } diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index bf964dcae75..15d00cd9b01 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -160,13 +160,12 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor if (surface->input_region) { - cairo_region_t *scaled_input_region; + cairo_region_t *input_region; - scaled_input_region = meta_region_scale (surface->input_region, - geometry_scale); - cairo_region_intersect_rectangle (scaled_input_region, &surface_rect); - meta_surface_actor_set_input_region (surface_actor, scaled_input_region); - cairo_region_destroy (scaled_input_region); + input_region = cairo_region_copy (surface->input_region); + cairo_region_intersect_rectangle (input_region, &surface_rect); + meta_surface_actor_set_input_region (surface_actor, input_region); + cairo_region_destroy (input_region); } else { @@ -175,15 +174,12 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor if (surface->opaque_region) { - cairo_region_t *scaled_opaque_region; - - /* Wayland surface coordinate space -> stage coordinate space */ - scaled_opaque_region = meta_region_scale (surface->opaque_region, - geometry_scale); - cairo_region_intersect_rectangle (scaled_opaque_region, &surface_rect); - meta_surface_actor_set_opaque_region (surface_actor, - scaled_opaque_region); - cairo_region_destroy (scaled_opaque_region); + cairo_region_t *opaque_region; + + opaque_region = cairo_region_copy (surface->opaque_region); + cairo_region_intersect_rectangle (opaque_region, &surface_rect); + meta_surface_actor_set_opaque_region (surface_actor, opaque_region); + cairo_region_destroy (opaque_region); } else { -- GitLab From fb9e8768a386fa7078e52374a1d81e8849ad9347 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 12 Jul 2019 14:33:17 -0300 Subject: [PATCH 9/9] window-actor: Handle geometry scale Geometry scale is applied to each surface individually, using Clutter scales, and not only this breaks subsurfaces, it also pollutes the toolkit and makes the actor tree slightly too fragile. If GNOME Shell mistakenly tries to set the actor scale of any of these surfaces, for example, various artifacts might happen. Move geometry scale handling to MetaWindowActor. It is applied as a child transform operation, so that the Clutter-managed scale properties are left untouched. In the future where the entirety of the window is managed by a ClutterContent itself, the geometry scale will be applied directly into the transform matrix of MetaWindowActor. However, doing that now would break the various ClutterClones used by GNOME Shell, so the child transform is an acceptable compromise during this transition. https://gitlab.gnome.org/GNOME/mutter/merge_requests/409 --- src/compositor/meta-surface-actor.c | 13 +++++--- src/compositor/meta-window-actor-private.h | 5 +++ src/compositor/meta-window-actor.c | 34 +++++++++++++++++++ src/wayland/meta-wayland-actor-surface.c | 4 --- src/wayland/meta-wayland-subsurface.c | 6 ++-- src/wayland/meta-window-wayland.c | 38 +++++++++++++++++----- 6 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index 79c621214a4..bf5a607ff44 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -22,6 +22,7 @@ #include "clutter/clutter.h" #include "compositor/meta-cullable.h" #include "compositor/meta-shaped-texture-private.h" +#include "compositor/meta-window-actor-private.h" #include "compositor/region-utils.h" #include "meta/meta-shaped-texture.h" @@ -76,7 +77,6 @@ effective_unobscured_region (MetaSurfaceActor *surface_actor) return priv->unobscured_region; } - static void set_unobscured_region (MetaSurfaceActor *surface_actor, cairo_region_t *unobscured_region) @@ -250,18 +250,21 @@ meta_surface_actor_cull_out (MetaCullable *cullable, if (opacity == 0xff) { + MetaWindowActor *window_actor; cairo_region_t *scaled_opaque_region; cairo_region_t *opaque_region; - double geometry_scale; + int geometry_scale = 1; opaque_region = meta_shaped_texture_get_opaque_region (priv->texture); if (!opaque_region) return; - clutter_actor_get_scale (CLUTTER_ACTOR (surface_actor), - &geometry_scale, - NULL); + window_actor = + meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor)); + if (window_actor) + geometry_scale = meta_window_actor_get_geometry_scale (window_actor); + scaled_opaque_region = meta_region_scale (opaque_region, geometry_scale); if (unobscured_region) diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 24a4cfcb6f2..354edd31435 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -88,4 +88,9 @@ void meta_window_actor_assign_surface_actor (MetaWindowActor *self, MetaWindowActor *meta_window_actor_from_window (MetaWindow *window); MetaWindowActor *meta_window_actor_from_actor (ClutterActor *actor); +void meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor, + int geometry_scale); + +int meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor); + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 81aaf4e2e44..312eb9811a8 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -81,6 +81,8 @@ typedef struct _MetaWindowActorPrivate MetaShadowMode shadow_mode; + int geometry_scale; + guint size_changed_id; /* @@ -252,6 +254,10 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) static void meta_window_actor_init (MetaWindowActor *self) { + MetaWindowActorPrivate *priv = + meta_window_actor_get_instance_private (self); + + priv->geometry_scale = 1; } static void @@ -1891,6 +1897,34 @@ meta_window_actor_from_window (MetaWindow *window) return META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); } +void +meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor, + int geometry_scale) +{ + MetaWindowActorPrivate *priv = + meta_window_actor_get_instance_private (window_actor); + CoglMatrix child_transform; + + if (priv->geometry_scale == geometry_scale) + return; + + priv->geometry_scale = geometry_scale; + + cogl_matrix_init_identity (&child_transform); + cogl_matrix_scale (&child_transform, geometry_scale, geometry_scale, 1); + clutter_actor_set_child_transform (CLUTTER_ACTOR (window_actor), + &child_transform); +} + +int +meta_window_actor_get_geometry_scale (MetaWindowActor *window_actor) +{ + MetaWindowActorPrivate *priv = + meta_window_actor_get_instance_private (window_actor); + + return priv->geometry_scale; +} + static void meta_window_actor_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds) diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index 15d00cd9b01..eb909c3b5a7 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -149,10 +149,6 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor /* Wayland surface coordinate space -> stage coordinate space */ geometry_scale = meta_wayland_actor_surface_get_geometry_scale (actor_surface); - clutter_actor_set_scale (CLUTTER_ACTOR (surface_actor), - geometry_scale, - geometry_scale); - surface_rect = (cairo_rectangle_int_t) { .width = meta_wayland_surface_get_width (surface) * geometry_scale, .height = meta_wayland_surface_get_height (surface) * geometry_scale, diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index bde7bef6ea6..3b813a191f9 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -56,7 +56,6 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) { ClutterActor *actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)); MetaWindow *toplevel_window; - int geometry_scale; int x, y; toplevel_window = meta_wayland_surface_get_toplevel_window (surface); @@ -66,9 +65,8 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) if (toplevel_window->client_type == META_WINDOW_CLIENT_TYPE_X11) return; - geometry_scale = meta_window_wayland_get_geometry_scale (toplevel_window); - x = (surface->offset_x + surface->sub.x) * geometry_scale; - y = (surface->offset_y + surface->sub.y) * geometry_scale; + x = surface->offset_x + surface->sub.x; + y = surface->offset_y + surface->sub.y; clutter_actor_set_position (actor, x, y); diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index d72b3bbc198..802b7e22381 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -33,6 +33,7 @@ #include "backends/meta-backend-private.h" #include "backends/meta-logical-monitor.h" #include "compositor/meta-surface-actor-wayland.h" +#include "compositor/meta-window-actor-private.h" #include "core/boxes-private.h" #include "core/stack-tracker.h" #include "core/window-private.h" @@ -69,6 +70,19 @@ struct _MetaWindowWaylandClass G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW) +static void +set_geometry_scale_for_window (MetaWindowWayland *wl_window, + int geometry_scale) +{ + MetaWindowActor *window_actor; + + wl_window->geometry_scale = geometry_scale; + + window_actor = meta_window_actor_from_window (META_WINDOW (wl_window)); + if (window_actor) + meta_window_actor_set_geometry_scale (window_actor, geometry_scale); +} + static int get_window_geometry_scale_for_logical_monitor (MetaLogicalMonitor *logical_monitor) { @@ -526,8 +540,7 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window, meta_wayland_actor_surface_sync_actor_state (actor_surface); } - wl_window->geometry_scale = geometry_scale; - + set_geometry_scale_for_window (wl_window, geometry_scale); meta_window_emit_size_changed (window); } @@ -663,6 +676,8 @@ meta_window_wayland_new (MetaDisplay *display, MetaWaylandSurface *surface) { XWindowAttributes attrs = { 0 }; + MetaWindowWayland *wl_window; + MetaWindow *window; /* * Set attributes used by _meta_window_shared_new, don't bother trying to fake @@ -677,13 +692,18 @@ meta_window_wayland_new (MetaDisplay *display, attrs.map_state = IsUnmapped; attrs.override_redirect = False; - return _meta_window_shared_new (display, - META_WINDOW_CLIENT_TYPE_WAYLAND, - surface, - None, - WithdrawnState, - META_COMP_EFFECT_CREATE, - &attrs); + window = _meta_window_shared_new (display, + META_WINDOW_CLIENT_TYPE_WAYLAND, + surface, + None, + WithdrawnState, + META_COMP_EFFECT_CREATE, + &attrs); + + wl_window = META_WINDOW_WAYLAND (window); + set_geometry_scale_for_window (wl_window, wl_window->geometry_scale); + + return window; } static gboolean -- GitLab