diff --git a/clutter/clutter/clutter-paint-node-private.h b/clutter/clutter/clutter-paint-node-private.h index d61b899514ff7abf05e10ba8333fa10c7bc687ad..b0ac8c56f87a80bf2477e06e93822aa49635d656 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 e731ca60a26b4f5f2c1833542fd63d8da2a1bf45..928c32cced2348b0cfed5d7ccba795f8eb24e586 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 c42abbc3d8a2bc27fb921df3534bb42a3f98cd5e..cd22e431e26c5d4b434d78d84052983d14134ced 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); diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h index a86a2bff0ab1196d2cdac730e881f5d4e6494e36..8b078229ce5142392a3b5c2410ef7b8578e0f033 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, @@ -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,5 +50,15 @@ 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_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/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 90a02210dfed6e8ee7e780a68ca79df53575feee..f85b55e23b56bc42e6f9eb12260db786b042c550 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; @@ -102,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; @@ -123,25 +105,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 +140,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 +171,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 +203,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); } } @@ -246,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) { @@ -298,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); @@ -377,27 +314,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,37 +404,52 @@ 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) { - float coords[8]; + g_autoptr (ClutterPaintNode) node = NULL; + float ratio_h, ratio_v; float x1, y1, x2, y2; + float coords[8]; float alloc_width; float alloc_height; - x1 = rect->x; - y1 = rect->y; - x2 = rect->x + rect->width; - y2 = rect->y + rect->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]; 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 = x1, + .y1 = y1, + .x2 = x2, + .y2 = y2, + }, + coords, 8); } static void @@ -542,6 +492,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 +504,41 @@ 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 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,57 +546,23 @@ 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); - else - blended_tex_region = cairo_region_create_rectangle (&tex_rect); - - cairo_region_subtract (blended_tex_region, opaque_tex_region); + blended_tex_region = cairo_region_create_rectangle (&content_rect); + cairo_region_subtract (blended_tex_region, stex->opaque_region); } else { - if (clip_tex_region) - blended_tex_region = cairo_region_reference (clip_tex_region); - else - blended_tex_region = NULL; + blended_tex_region = NULL; } /* Limit to how many separate rectangles we'll draw; beyond this just @@ -664,41 +584,27 @@ 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) - { - region = cairo_region_copy (clip_tex_region); - cairo_region_intersect (region, opaque_tex_region); - } - else + if (!cairo_region_is_empty (stex->opaque_region)) { - region = cairo_region_reference (opaque_tex_region); - } + CoglPipeline *opaque_pipeline; - if (!cairo_region_is_empty (region)) - { 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); - 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); - paint_clipped_rectangle (stex, - fb, - opaque_pipeline, - &rect, - &alloc); + 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. */ @@ -744,78 +650,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 +710,68 @@ 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); + /* 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; - if (min_width_p) - *min_width_p = stex->dst_width; - if (natural_width_p) - *natural_width_p = stex->dst_width; + 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; -} + if (width) + *width = stex->dst_width; -static cairo_region_t * -effective_unobscured_region (MetaShapedTexture *stex) -{ - ClutterActor *actor; + if (height) + *height = stex->dst_height; - /* 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); - - 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,18 +805,7 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, cogl_object_ref (stex->mask_texture); } - clutter_actor_queue_redraw (CLUTTER_ACTOR (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; + clutter_content_invalidate (CLUTTER_CONTENT (stex)); } /** @@ -948,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. @@ -955,46 +823,47 @@ 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) { 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 +873,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,31 +885,31 @@ 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 }; 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, - 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 (); @@ -1056,34 +925,7 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, stex->fast_updates++; } - unobscured_region = effective_unobscured_region (stex); - if (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_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect); - cairo_region_destroy (intersection); - return TRUE; - } - - cairo_region_destroy (intersection); - return FALSE; - } - else - { - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip); - return TRUE; - } + return TRUE; } /** @@ -1274,6 +1116,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 +1126,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 +1172,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 +1237,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,44 +1328,30 @@ 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) { - MetaShapedTexture *stex = META_SHAPED_TEXTURE (cullable); - - set_unobscured_region (stex, unobscured_region); - set_clip_region (stex, clip_region); - - if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex)) == 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); - } - } + return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); } -static void -meta_shaped_texture_reset_culling (MetaCullable *cullable) +void +meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex, + int buffer_scale) { - MetaShapedTexture *self = META_SHAPED_TEXTURE (cullable); - set_clip_region (self, NULL); -} + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - iface->cull_out = meta_shaped_texture_cull_out; - iface->reset_culling = meta_shaped_texture_reset_culling; + if (buffer_scale == stex->buffer_scale) + return; + + stex->buffer_scale = buffer_scale; + + invalidate_size (stex); } -ClutterActor * -meta_shaped_texture_new (void) +int +meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex) { - return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); + g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 1.0); + + return stex->buffer_scale; } diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index f8d6c32b766000ed92b68534a03190d321c781db..27c600c593e6a7fb60d265fed3b799db0f5234ae 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 ca4ca19a99e75c5ab5ec7b401a362406002014a6..bf5a607ff447e2d5bff1093a1addd52147262cb6 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -22,6 +22,8 @@ #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" typedef struct _MetaSurfaceActorPrivate @@ -30,6 +32,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 +57,77 @@ 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 +203,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 +216,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; @@ -159,13 +240,48 @@ 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)); + + set_unobscured_region (surface_actor, unobscured_region); + set_clip_region (surface_actor, clip_region); + + if (opacity == 0xff) + { + MetaWindowActor *window_actor; + cairo_region_t *scaled_opaque_region; + cairo_region_t *opaque_region; + int geometry_scale = 1; + + opaque_region = meta_shaped_texture_get_opaque_region (priv->texture); + + if (!opaque_region) + return; + + 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) + 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); + } } static void meta_surface_actor_reset_culling (MetaCullable *cullable) { - meta_cullable_reset_culling_children (cullable); + MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (cullable); + + set_clip_region (surface_actor, NULL); } static void @@ -189,10 +305,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 * @@ -220,18 +339,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; + + unobscured_region = effective_unobscured_region (self); - return meta_shaped_texture_is_obscured (priv->texture); + if (unobscured_region) + return cairo_region_is_empty (unobscured_region); + else + return FALSE; } void diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 24a4cfcb6f2a1720c17f604820936c0fa1c56a28..354edd314354222341a59ea068fc322775635eb5 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 375d7bc0a4b1f3f5c634b22b5636f53b6ada814b..312eb9811a82aebdd7388a85a0cd0947ba52fe90 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 @@ -833,14 +839,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; } @@ -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) @@ -1902,19 +1936,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 +1962,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 +1974,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 +2003,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-shaped-texture.h b/src/meta/meta-shaped-texture.h index c36b8547f3ea35e68b80e5b78ef15bad0c7d54e0..d38a6dae17e5401413be6bfdbcbfdaee9caed1cc 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -44,13 +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); - META_EXPORT CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h index 9ba16491054f2bd96e0110a06c971c6ed3f68ed6..ad4b7bf1dc234b44948a6f3ce4656aef5d267fb0 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 bd987e970c65405d7169215ab235b6cd738ef2da..eb909c3b5a7e2fff7b42a7e6372485904940a791 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) { @@ -154,20 +139,16 @@ 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); - surface_rect = (cairo_rectangle_int_t) { .width = meta_wayland_surface_get_width (surface) * geometry_scale, .height = meta_wayland_surface_get_height (surface) * geometry_scale, @@ -175,13 +156,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 { @@ -190,15 +170,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 { diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h index 444b3b1785626ab687c5d8c9fe7a8eb8850a7584..aa9f8fa5ac27c3cafdf222b081bdfeb3a1a8ceb9 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-data-device.c b/src/wayland/meta-wayland-data-device.c index ba9591ec1aa1e954168a783b85f4bdc169a77aa7..7eeac7e3162289fa240c79e1fbee5d19728ebef5 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-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index f8354ab7c5e726bae6de77e8233c24576d22ce39..3ebfdd2843f20cb00a9fd538686a27f8a9d7bad2 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-subsurface.c b/src/wayland/meta-wayland-subsurface.c index bde7bef6ea68cb1648ddfcd1dccd622141a307d7..3b813a191f9160bc30560a25416b0bead3c406d4 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-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 3bf9bc9cea480b6adb8b197f9f44184a934cb448..787265f33605c575ca9eaddc7cc84831c9abd7db 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1581,11 +1581,9 @@ 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; - *sy /= surface->scale; } } @@ -1597,7 +1595,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 d243608cffed1031fa5ec16ff2b681e478412c77..52c63dd96c91c367cc5c2d651bf5245615b4c5ab 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 (meta_surface_actor_get_texture (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; diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index d72b3bbc198534279ae8f9d4e8d578db3771cb2c..802b7e2238151a1b4c8234b2b0b17b5875373577 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