[mutter] clutter: Add API to get the resource scale of an actor
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] clutter: Add API to get the resource scale of an actor
- Date: Fri, 1 Mar 2019 18:07:01 +0000 (UTC)
commit ad5555bf4286ece9844d919d62f8368dce90edf1
Author: Jonas Ådahl <jadahl gmail com>
Date: Fri Apr 7 14:06:36 2017 +0200
clutter: Add API to get the resource scale of an actor
A clutter actor might be painted on a stage view with a view scale
other than 1. In this case, to show the content in full resolution, the
actor must use a higher resolution resource (e.g. texture), which will
be down scaled to the stage coordinate space, then scaled up again to
the stage view framebuffer scale.
Use a 'resource-scale' property to save information and notify when it
changes.
The resource scale is the ceiled value of the highest stage view scale a
actor is visible on. The value is ceiled because using a higher
resolution resource consistently results in better output quality. One
reason for this is that rendering is often not perfectly pixel aligned,
meaning even if we load a resource with a suitable size, due to us still
scaling ever so slightly, the quality is affected. Using a higher
resolution resource avoids this problem.
For situations inside clutter where the actual maximum view scale is
needed, a function _clutter_actor_get_real_resource_scale() is provided,
which returns the non-ceiled value.
Make sure we ignore resource scale computation requests during size
requests or allocation while ensure we've proper resource-scale on
pre-paint.
https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/mutter/merge_requests/3
clutter/clutter/clutter-actor-private.h | 3 +
clutter/clutter/clutter-actor.c | 251 +++++++++++++++++++++-
clutter/clutter/clutter-actor.h | 5 +
clutter/clutter/clutter-mutter.h | 3 +
clutter/clutter/clutter-private.h | 11 +-
clutter/clutter/clutter-stage-private.h | 2 +
clutter/clutter/clutter-stage.c | 14 ++
src/backends/native/meta-stage-native.c | 2 +
src/backends/x11/nested/meta-backend-x11-nested.c | 5 +-
9 files changed, 287 insertions(+), 9 deletions(-)
---
diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h
index 7806894bc..c44f6342f 100644
--- a/clutter/clutter/clutter-actor-private.h
+++ b/clutter/clutter/clutter-actor-private.h
@@ -315,8 +315,11 @@ void _clutter_actor_detach_clone
void _clutter_actor_queue_redraw_on_clones (ClutterActor
*actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor
*actor);
void _clutter_actor_queue_only_relayout (ClutterActor
*actor);
+void _clutter_actor_queue_update_resource_scale_recursive (ClutterActor
*actor);
CoglFramebuffer * _clutter_actor_get_active_framebuffer (ClutterActor
*actor);
+gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
+ float
*resource_scale);
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture
*texture);
diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index 43d58cd14..d0f7434ef 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -699,6 +699,8 @@ struct _ClutterActorPrivate
/* the cached transformation matrix; see apply_transform() */
CoglMatrix transform;
+ float resource_scale;
+
guint8 opacity;
gint opacity_override;
@@ -844,6 +846,7 @@ struct _ClutterActorPrivate
guint needs_y_expand : 1;
guint needs_paint_volume_update : 1;
guint had_effects_on_last_paint_volume_update : 1;
+ guint needs_compute_resource_scale : 1;
};
enum
@@ -916,6 +919,7 @@ enum
PROP_SCALE_CENTER_X, /* XXX:2.0 remove */
PROP_SCALE_CENTER_Y, /* XXX:2.0 remove */
PROP_SCALE_GRAVITY, /* XXX:2.0 remove */
+ PROP_RESOURCE_SCALE,
PROP_ROTATION_ANGLE_X, /* XXX:2.0 rename to rotation-x */
PROP_ROTATION_ANGLE_Y, /* XXX:2.0 rename to rotation-y */
@@ -1095,6 +1099,8 @@ static void clutter_actor_set_child_transform_internal (ClutterActor *sel
static void clutter_actor_realize_internal (ClutterActor *self);
static void clutter_actor_unrealize_internal (ClutterActor *self);
+static gboolean clutter_actor_update_resource_scale (ClutterActor *self);
+static void clutter_actor_ensure_resource_scale (ClutterActor *self);
static void clutter_actor_push_in_cloned_branch (ClutterActor *self,
gulong count);
@@ -1521,6 +1527,8 @@ clutter_actor_real_map (ClutterActor *self)
priv->pick_id,
_clutter_actor_get_debug_name (self));
+ clutter_actor_ensure_resource_scale (self);
+
/* notify on parent mapped before potentially mapping
* children, so apps see a top-down notification.
*/
@@ -2778,6 +2786,16 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
return FALSE;
}
+static inline gboolean
+clutter_actor_needs_relayout (ClutterActor *self)
+{
+ ClutterActorPrivate *priv = self->priv;
+
+ return (priv->needs_width_request ||
+ priv->needs_height_request ||
+ priv->needs_allocation);
+}
+
static void
clutter_actor_real_queue_relayout (ClutterActor *self)
{
@@ -3837,6 +3855,8 @@ clutter_actor_paint (ClutterActor *self)
if (!CLUTTER_ACTOR_IS_MAPPED (self))
return;
+ clutter_actor_ensure_resource_scale (self);
+
stage = (ClutterStage *) _clutter_actor_get_stage_internal (self);
/* mark that we are in the paint process */
@@ -4339,7 +4359,10 @@ clutter_actor_remove_child_internal (ClutterActor *self,
/* clutter_actor_reparent() will emit ::parent-set for us */
if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
- g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
+ {
+ child->priv->needs_compute_resource_scale = TRUE;
+ g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
+ }
/* if the child was mapped then we need to relayout ourselves to account
* for the removed child
@@ -5664,6 +5687,16 @@ clutter_actor_get_property (GObject *object,
g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
break;
+ case PROP_RESOURCE_SCALE:
+ if (priv->needs_compute_resource_scale)
+ {
+ if (!clutter_actor_update_resource_scale (actor))
+ g_warning ("Getting invalid resource scale property");
+ }
+
+ g_value_set_float (value, priv->resource_scale);
+ break;
+
case PROP_REACTIVE:
g_value_set_boolean (value, clutter_actor_get_reactive (actor));
break;
@@ -7117,6 +7150,19 @@ clutter_actor_class_init (ClutterActorClass *klass)
G_PARAM_STATIC_STRINGS |
G_PARAM_DEPRECATED);
+ /**
+ * ClutterActor:resource-scale:
+ *
+ * The resource-scale of the #ClutterActor if any or -1 if not available
+ */
+ obj_props[PROP_RESOURCE_SCALE] =
+ g_param_spec_float ("resource-scale",
+ P_("Resource Scale"),
+ P_("The Scaling factor for resources painting"),
+ -1.0f, G_MAXFLOAT,
+ 1.0f,
+ CLUTTER_PARAM_READABLE);
+
/**
* ClutterActor:rotation-angle-x:
*
@@ -8556,11 +8602,13 @@ clutter_actor_init (ClutterActor *self)
priv->opacity = 0xff;
priv->show_on_set_parent = TRUE;
+ priv->resource_scale = -1.0f;
priv->needs_width_request = TRUE;
priv->needs_height_request = TRUE;
priv->needs_allocation = TRUE;
priv->needs_paint_volume_update = TRUE;
+ priv->needs_compute_resource_scale = TRUE;
priv->cached_width_age = 1;
priv->cached_height_age = 1;
@@ -9520,6 +9568,8 @@ clutter_actor_get_preferred_width (ClutterActor *self,
return;
}
+ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PREF_WIDTH);
+
/* the remaining cases are:
*
* - either min_width or natural_width have been set
@@ -9611,6 +9661,8 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (natural_width_p)
*natural_width_p = request_natural_width;
+
+ CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PREF_WIDTH);
}
/**
@@ -9664,6 +9716,8 @@ clutter_actor_get_preferred_height (ClutterActor *self,
return;
}
+ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PREF_HEIGHT);
+
/* the remaining cases are:
*
* - either min_height or natural_height have been set
@@ -9754,6 +9808,8 @@ clutter_actor_get_preferred_height (ClutterActor *self,
if (natural_height_p)
*natural_height_p = request_natural_height;
+
+ CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PREF_HEIGHT);
}
/**
@@ -10096,6 +10152,9 @@ clutter_actor_allocate (ClutterActor *self,
if (CLUTTER_ACTOR_IS_MAPPED (self))
self->priv->needs_paint_volume_update = TRUE;
+ if (stage_allocation_changed)
+ priv->needs_compute_resource_scale = TRUE;
+
if (!stage_allocation_changed)
{
/* If the actor didn't move but needs_allocation is set, we just
@@ -12944,7 +13003,10 @@ clutter_actor_add_child_internal (ClutterActor *self,
/* clutter_actor_reparent() will emit ::parent-set for us */
if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
- g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
+ {
+ child->priv->needs_compute_resource_scale = TRUE;
+ g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
+ }
if (check_state)
{
@@ -12977,9 +13039,7 @@ clutter_actor_add_child_internal (ClutterActor *self,
/* maintain the invariant that if an actor needs layout,
* its parents do as well
*/
- if (child->priv->needs_width_request ||
- child->priv->needs_height_request ||
- child->priv->needs_allocation)
+ if (clutter_actor_needs_relayout (child))
{
/* we work around the short-circuiting we do
* in clutter_actor_queue_relayout() since we
@@ -13548,6 +13608,8 @@ clutter_actor_reparent (ClutterActor *self,
insert_child_at_depth,
NULL);
+ priv->needs_compute_resource_scale = TRUE;
+
/* we emit the ::parent-set signal once */
g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
@@ -17717,6 +17779,185 @@ clutter_actor_get_paint_box (ClutterActor *self,
return TRUE;
}
+static gboolean
+_clutter_actor_get_resource_scale_for_rect (ClutterActor *self,
+ ClutterRect *bounding_rect,
+ float *resource_scale)
+{
+ ClutterActor *stage;
+ GList *views;
+ GList *l;
+ float max_scale = 0;
+
+ stage = _clutter_actor_get_stage_internal (self);
+ if (!stage)
+ return FALSE;
+
+ views = _clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
+ for (l = views; l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+ cairo_rectangle_int_t view_layout;
+ ClutterRect view_rect;
+
+ clutter_stage_view_get_layout (view, &view_layout);
+ _clutter_util_rect_from_rectangle (&view_layout, &view_rect);
+
+ if (clutter_rect_intersection (&view_rect, bounding_rect, NULL))
+ max_scale = MAX (clutter_stage_view_get_scale (view), max_scale);
+ }
+
+ if (max_scale == 0)
+ return FALSE;
+
+ *resource_scale = max_scale;
+
+ return TRUE;
+}
+
+static gboolean
+_clutter_actor_compute_resource_scale (ClutterActor *self,
+ float *resource_scale)
+{
+ ClutterRect bounding_rect;
+ ClutterActorPrivate *priv = self->priv;
+
+ if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
+ CLUTTER_ACTOR_IN_PREF_SIZE (self) ||
+ !clutter_actor_is_mapped (self))
+ {
+ return FALSE;
+ }
+
+ clutter_actor_get_transformed_position (self,
+ &bounding_rect.origin.x,
+ &bounding_rect.origin.y);
+ clutter_actor_get_transformed_size (self,
+ &bounding_rect.size.width,
+ &bounding_rect.size.height);
+
+ if (bounding_rect.size.width == 0.0 ||
+ bounding_rect.size.height == 0.0 ||
+ !_clutter_actor_get_resource_scale_for_rect (self,
+ &bounding_rect,
+ resource_scale))
+ {
+ if (priv->parent)
+ return _clutter_actor_compute_resource_scale (priv->parent,
+ resource_scale);
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static ClutterActorTraverseVisitFlags
+queue_update_resource_scale_cb (ClutterActor *actor,
+ int depth,
+ void *user_data)
+{
+ actor->priv->needs_compute_resource_scale = TRUE;
+ return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
+}
+
+void
+_clutter_actor_queue_update_resource_scale_recursive (ClutterActor *self)
+{
+ _clutter_actor_traverse (self,
+ CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
+ queue_update_resource_scale_cb,
+ NULL,
+ NULL);
+}
+
+static gboolean
+clutter_actor_update_resource_scale (ClutterActor *self)
+{
+ ClutterActorPrivate *priv;
+ float resource_scale;
+ float old_resource_scale;
+ priv = self->priv;
+
+ g_return_val_if_fail (priv->needs_compute_resource_scale, FALSE);
+
+ old_resource_scale = priv->resource_scale;
+ priv->resource_scale = -1.0f;
+
+ if (_clutter_actor_compute_resource_scale (self, &resource_scale))
+ {
+ priv->resource_scale = resource_scale;
+ priv->needs_compute_resource_scale = FALSE;
+
+ return fabsf (old_resource_scale - resource_scale) > FLT_EPSILON;
+ }
+
+ return FALSE;
+}
+
+static void
+clutter_actor_ensure_resource_scale (ClutterActor *self)
+{
+ ClutterActorPrivate *priv = self->priv;
+
+ if (!priv->needs_compute_resource_scale)
+ return;
+
+ if (clutter_actor_update_resource_scale (self))
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_RESOURCE_SCALE]);
+}
+
+gboolean
+_clutter_actor_get_real_resource_scale (ClutterActor *self,
+ gfloat *resource_scale)
+{
+ ClutterActorPrivate *priv = self->priv;
+
+ clutter_actor_ensure_resource_scale (self);
+
+ if (!priv->needs_compute_resource_scale)
+ {
+ *resource_scale = priv->resource_scale;
+ return TRUE;
+ }
+
+ *resource_scale = -1.0f;
+ return FALSE;
+}
+
+/**
+ * clutter_actor_get_resource_scale:
+ * @self: A #ClutterActor
+ * @resource_scale: (out): return location for the resource scale
+ *
+ * Retrieves the resource scale for this actor, if available.
+ *
+ * The resource scale refers to the scale the actor should use for its resources.
+ * For example if an actor draws a a picture of size 100 x 100 in the stage
+ * coordinate space, it should use a texture of twice the size (i.e. 200 x 200)
+ * if the resource scale is 2.
+ *
+ * The resource scale is determined by calculating the highest #ClutterStageView
+ * scale the actor will get painted on.
+ *
+ * Returns: TRUE if resource scale is set for the actor, otherwise FALSE
+ */
+gboolean
+clutter_actor_get_resource_scale (ClutterActor *self,
+ gfloat *resource_scale)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
+ g_return_val_if_fail (resource_scale != NULL, FALSE);
+
+ if (_clutter_actor_get_real_resource_scale (self, resource_scale))
+ {
+ *resource_scale = ceilf (*resource_scale);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/**
* clutter_actor_has_overlaps:
* @self: A #ClutterActor
diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h
index ade912485..7d2168af1 100644
--- a/clutter/clutter/clutter-actor.h
+++ b/clutter/clutter/clutter-actor.h
@@ -584,6 +584,11 @@ gboolean clutter_actor_is_in_clone_paint
CLUTTER_EXPORT
gboolean clutter_actor_get_paint_box (ClutterActor
*self,
ClutterActorBox
*box);
+
+CLUTTER_EXPORT
+gboolean clutter_actor_get_resource_scale (ClutterActor *self,
+ gfloat
*resource_scale);
+
CLUTTER_EXPORT
gboolean clutter_actor_has_overlaps (ClutterActor
*self);
diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h
index 788757140..a53080457 100644
--- a/clutter/clutter/clutter-mutter.h
+++ b/clutter/clutter/clutter-mutter.h
@@ -49,6 +49,9 @@ void clutter_stage_freeze_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_thaw_updates (ClutterStage *stage);
+CLUTTER_EXPORT
+void clutter_stage_update_resource_scales (ClutterStage *stage);
+
CLUTTER_EXPORT
gboolean clutter_actor_has_damage (ClutterActor *actor);
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index 891a5612b..cbfaaa7f0 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -69,6 +69,9 @@ typedef struct _ClutterVertex4 ClutterVertex4;
#define CLUTTER_ACTOR_IN_REPARENT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_REPARENT) != FALSE)
#define CLUTTER_ACTOR_IN_PAINT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PAINT) != FALSE)
#define CLUTTER_ACTOR_IN_RELAYOUT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_RELAYOUT) != FALSE)
+#define CLUTTER_ACTOR_IN_PREF_WIDTH(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PREF_WIDTH) !=
FALSE)
+#define CLUTTER_ACTOR_IN_PREF_HEIGHT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PREF_HEIGHT) !=
FALSE)
+#define CLUTTER_ACTOR_IN_PREF_SIZE(a) ((CLUTTER_PRIVATE_FLAGS (a) &
(CLUTTER_IN_PREF_HEIGHT|CLUTTER_IN_PREF_WIDTH)) != FALSE)
#define CLUTTER_PARAM_READABLE (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)
#define CLUTTER_PARAM_WRITABLE (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)
@@ -98,15 +101,17 @@ typedef enum
CLUTTER_IN_DESTRUCTION = 1 << 0,
CLUTTER_IS_TOPLEVEL = 1 << 1,
CLUTTER_IN_REPARENT = 1 << 2,
+ CLUTTER_IN_PREF_WIDTH = 1 << 3,
+ CLUTTER_IN_PREF_HEIGHT = 1 << 4,
/* Used to avoid recursion */
- CLUTTER_IN_PAINT = 1 << 3,
+ CLUTTER_IN_PAINT = 1 << 5,
/* Used to avoid recursion */
- CLUTTER_IN_RELAYOUT = 1 << 4,
+ CLUTTER_IN_RELAYOUT = 1 << 6,
/* a flag for internal children of Containers (DEPRECATED) */
- CLUTTER_INTERNAL_CHILD = 1 << 5
+ CLUTTER_INTERNAL_CHILD = 1 << 7
} ClutterPrivateFlags;
/*
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index dde8d4e21..688768bac 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -129,6 +129,8 @@ void _clutter_stage_presented (ClutterStage *stag
CoglFrameEvent frame_event,
ClutterFrameInfo *frame_info);
+GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
+
G_END_DECLS
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index a10069eb1..67992d816 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -5003,3 +5003,17 @@ clutter_stage_thaw_updates (ClutterStage *stage)
_clutter_master_clock_set_paused (master_clock, FALSE);
}
}
+
+GList *
+_clutter_stage_peek_stage_views (ClutterStage *stage)
+{
+ ClutterStagePrivate *priv = stage->priv;
+
+ return _clutter_stage_window_get_views (priv->impl);
+}
+
+void
+clutter_stage_update_resource_scales (ClutterStage *stage)
+{
+ _clutter_actor_queue_update_resource_scale_recursive (CLUTTER_ACTOR (stage));
+}
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index c8afa752c..add3e81fd 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -137,9 +137,11 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native)
{
MetaBackend *backend = meta_get_backend ();
MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ ClutterActor *stage = meta_backend_get_stage (backend);
meta_renderer_rebuild_views (renderer);
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
+ clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
ensure_frame_callbacks (stage_native);
}
diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c
b/src/backends/x11/nested/meta-backend-x11-nested.c
index 81a95bae8..172c4d9ac 100644
--- a/src/backends/x11/nested/meta-backend-x11-nested.c
+++ b/src/backends/x11/nested/meta-backend-x11-nested.c
@@ -68,7 +68,10 @@ meta_backend_x11_nested_update_screen_size (MetaBackend *backend,
MetaRenderer *renderer = meta_backend_get_renderer (backend);
if (meta_is_stage_views_enabled ())
- meta_renderer_rebuild_views (renderer);
+ {
+ meta_renderer_rebuild_views (renderer);
+ clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
+ }
clutter_actor_set_size (stage, width, height);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]