2092 lines
72 KiB
Diff
2092 lines
72 KiB
Diff
|
From ac946bf95ce3e4dc900f72dcb4189dd49bdb3155 Mon Sep 17 00:00:00 2001
|
|||
|
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
|||
|
Date: Thu, 18 Jul 2019 16:56:41 +0800
|
|||
|
Subject: [PATCH 1/4] clutter/point: Add ClutterPoint quarilateral testing API
|
|||
|
|
|||
|
Add a function to check whether a point is inside a quadrilateral
|
|||
|
by checking the cross product of vectors with the quadrilateral
|
|||
|
points, and the point being checked.
|
|||
|
|
|||
|
If the passed quadrilateral is zero-sized, no point is ever reported
|
|||
|
to be inside it.
|
|||
|
|
|||
|
This will be used by the next commit when comparing the transformed
|
|||
|
actor vertices.
|
|||
|
|
|||
|
[feaneron: add a commit message and remove unecessary code]
|
|||
|
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/merge_requests/189
|
|||
|
---
|
|||
|
clutter/clutter/clutter-base-types.c | 62 ++++++++++++++++++++++++++++
|
|||
|
clutter/clutter/clutter-types.h | 3 ++
|
|||
|
2 files changed, 65 insertions(+)
|
|||
|
|
|||
|
diff --git a/clutter/clutter/clutter-base-types.c b/clutter/clutter/clutter-base-types.c
|
|||
|
index aeb25c90ef..c84f9aa64b 100644
|
|||
|
--- a/clutter/clutter/clutter-base-types.c
|
|||
|
+++ b/clutter/clutter/clutter-base-types.c
|
|||
|
@@ -570,6 +570,68 @@ G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterPoint, clutter_point,
|
|||
|
clutter_point_free,
|
|||
|
CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_point_progress))
|
|||
|
|
|||
|
+static int
|
|||
|
+clutter_point_compare_line (const ClutterPoint *p,
|
|||
|
+ const ClutterPoint *a,
|
|||
|
+ const ClutterPoint *b)
|
|||
|
+{
|
|||
|
+ float x1 = b->x - a->x;
|
|||
|
+ float y1 = b->y - a->y;
|
|||
|
+ float x2 = p->x - a->x;
|
|||
|
+ float y2 = p->y - a->y;
|
|||
|
+ float cross_z = x1 * y2 - y1 * x2;
|
|||
|
+
|
|||
|
+ if (cross_z > 0.f)
|
|||
|
+ return 1;
|
|||
|
+ else if (cross_z < 0.f)
|
|||
|
+ return -1;
|
|||
|
+ else
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/**
|
|||
|
+ * clutter_point_inside_quadrilateral:
|
|||
|
+ * @point: a #ClutterPoint to test
|
|||
|
+ * @vertices: array of vertices of the quadrilateral, in clockwise order,
|
|||
|
+ * from top-left to bottom-left
|
|||
|
+ *
|
|||
|
+ * Determines whether a point is inside the convex quadrilateral provided,
|
|||
|
+ * and not on any of its edges or vertices.
|
|||
|
+ *
|
|||
|
+ * Returns: %TRUE if @point is inside the quadrilateral
|
|||
|
+ */
|
|||
|
+gboolean
|
|||
|
+clutter_point_inside_quadrilateral (const ClutterPoint *point,
|
|||
|
+ const ClutterPoint *vertices)
|
|||
|
+{
|
|||
|
+ unsigned int i;
|
|||
|
+ int first_side;
|
|||
|
+
|
|||
|
+ first_side = 0;
|
|||
|
+
|
|||
|
+ for (i = 0; i < 4; i++)
|
|||
|
+ {
|
|||
|
+ int side;
|
|||
|
+
|
|||
|
+ side = clutter_point_compare_line (point,
|
|||
|
+ &vertices[i],
|
|||
|
+ &vertices[(i + 1) % 4]);
|
|||
|
+
|
|||
|
+ if (side)
|
|||
|
+ {
|
|||
|
+ if (first_side == 0)
|
|||
|
+ first_side = side;
|
|||
|
+ else if (side != first_side)
|
|||
|
+ return FALSE;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (first_side == 0)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
diff --git a/clutter/clutter/clutter-types.h b/clutter/clutter/clutter-types.h
|
|||
|
index 0f0fb1c2ac..0508028273 100644
|
|||
|
--- a/clutter/clutter/clutter-types.h
|
|||
|
+++ b/clutter/clutter/clutter-types.h
|
|||
|
@@ -200,6 +200,9 @@ float clutter_point_distance (const ClutterPoint *a,
|
|||
|
const ClutterPoint *b,
|
|||
|
float *x_distance,
|
|||
|
float *y_distance);
|
|||
|
+CLUTTER_EXPORT
|
|||
|
+gboolean clutter_point_inside_quadrilateral (const ClutterPoint *point,
|
|||
|
+ const ClutterPoint *vertices);
|
|||
|
|
|||
|
/**
|
|||
|
* ClutterSize:
|
|||
|
--
|
|||
|
2.29.2
|
|||
|
|
|||
|
|
|||
|
From 8abac81711cfef8317bb675349d6b5b0a79eb05d Mon Sep 17 00:00:00 2001
|
|||
|
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
|||
|
Date: Thu, 2 Aug 2018 19:03:30 +0800
|
|||
|
Subject: [PATCH 2/4] clutter: Introduce geometric picking
|
|||
|
|
|||
|
Currently, Clutter does picking by drawing with Cogl and reading
|
|||
|
the pixel that's beneath the given point. Since Cogl has a journal
|
|||
|
that records drawing operations, and has optimizations to read a
|
|||
|
single pixel from a list of rectangle, it would be expected that
|
|||
|
we would hit this fast path and not flush the journal while picking.
|
|||
|
|
|||
|
However, that's not the case: dithering, clipping with scissors, etc,
|
|||
|
can all flush the journal, issuing commands to the GPU and making
|
|||
|
picking slow. On NVidia-based systems, this glReadPixels() call is
|
|||
|
extremely costly.
|
|||
|
|
|||
|
Introduce geometric picking, and avoid using the Cogl journal entirely.
|
|||
|
Do this by introducing a stack of actors in ClutterStage. This stack
|
|||
|
is cached, but for now, don't use the cache as much as possible.
|
|||
|
|
|||
|
The picking routines are still tied to painting.
|
|||
|
|
|||
|
When projecting the actor vertexes, do it manually and take the modelview
|
|||
|
matrix of the framebuffer into account as well.
|
|||
|
|
|||
|
CPU usage on an Intel i7-7700, tested with two different GPUs/drivers:
|
|||
|
|
|||
|
| | Intel | Nvidia |
|
|||
|
| ------: | --------: | -----: |
|
|||
|
| Moving the mouse: |
|
|||
|
| Before | 10% | 10% |
|
|||
|
| After | 6% | 6% |
|
|||
|
| Moving a window: |
|
|||
|
| Before | 23% | 81% |
|
|||
|
| After | 19% | 40% |
|
|||
|
|
|||
|
Closes: https://gitlab.gnome.org/GNOME/mutter/issues/154,
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/issues/691
|
|||
|
|
|||
|
Helps significantly with: https://gitlab.gnome.org/GNOME/mutter/issues/283,
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/issues/590,
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/issues/700
|
|||
|
|
|||
|
v2: Fix code style issues
|
|||
|
Simplify quadrilateral checks
|
|||
|
Remove the 0.5f hack
|
|||
|
Differentiate axis-aligned rectangles
|
|||
|
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/merge_requests/189
|
|||
|
---
|
|||
|
clutter/clutter/clutter-actor-private.h | 2 -
|
|||
|
clutter/clutter/clutter-actor.c | 232 ++++++----
|
|||
|
clutter/clutter/clutter-actor.h | 4 +
|
|||
|
clutter/clutter/clutter-debug.h | 1 -
|
|||
|
clutter/clutter/clutter-main.c | 120 -----
|
|||
|
clutter/clutter/clutter-private.h | 5 -
|
|||
|
clutter/clutter/clutter-stage-private.h | 16 +-
|
|||
|
clutter/clutter/clutter-stage-window.c | 18 -
|
|||
|
clutter/clutter/clutter-stage-window.h | 8 -
|
|||
|
clutter/clutter/clutter-stage.c | 459 +++++++++++--------
|
|||
|
clutter/clutter/cogl/clutter-stage-cogl.c | 52 ---
|
|||
|
clutter/clutter/deprecated/clutter-texture.c | 93 +---
|
|||
|
clutter/tests/conform/actor-pick.c | 99 +---
|
|||
|
clutter/tests/conform/meson.build | 1 -
|
|||
|
clutter/tests/conform/texture.c | 84 ----
|
|||
|
src/compositor/meta-surface-actor.c | 27 +-
|
|||
|
16 files changed, 439 insertions(+), 782 deletions(-)
|
|||
|
delete mode 100644 clutter/tests/conform/texture.c
|
|||
|
|
|||
|
diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h
|
|||
|
index c44f6342fd..9bf1a30493 100644
|
|||
|
--- a/clutter/clutter/clutter-actor-private.h
|
|||
|
+++ b/clutter/clutter/clutter-actor-private.h
|
|||
|
@@ -297,8 +297,6 @@ const gchar * _clutter_actor_get_debug_name
|
|||
|
void _clutter_actor_push_clone_paint (void);
|
|||
|
void _clutter_actor_pop_clone_paint (void);
|
|||
|
|
|||
|
-guint32 _clutter_actor_get_pick_id (ClutterActor *self);
|
|||
|
-
|
|||
|
void _clutter_actor_shader_pre_paint (ClutterActor *actor,
|
|||
|
gboolean repeat);
|
|||
|
void _clutter_actor_shader_post_paint (ClutterActor *actor);
|
|||
|
diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
|
|||
|
index 43093fe79d..01ffa51caa 100644
|
|||
|
--- a/clutter/clutter/clutter-actor.c
|
|||
|
+++ b/clutter/clutter/clutter-actor.c
|
|||
|
@@ -730,8 +730,6 @@ struct _ClutterActorPrivate
|
|||
|
|
|||
|
gchar *name; /* a non-unique name, used for debugging */
|
|||
|
|
|||
|
- gint32 pick_id; /* per-stage unique id, used for picking */
|
|||
|
-
|
|||
|
/* a back-pointer to the Pango context that we can use
|
|||
|
* to create pre-configured PangoLayout
|
|||
|
*/
|
|||
|
@@ -1281,6 +1279,105 @@ clutter_actor_verify_map_state (ClutterActor *self)
|
|||
|
|
|||
|
#endif /* CLUTTER_ENABLE_DEBUG */
|
|||
|
|
|||
|
+static gboolean
|
|||
|
+_clutter_actor_transform_local_box_to_stage (ClutterActor *self,
|
|||
|
+ ClutterStage *stage,
|
|||
|
+ const ClutterActorBox *box,
|
|||
|
+ ClutterPoint vertices[4])
|
|||
|
+{
|
|||
|
+ CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
|
|||
|
+ CoglMatrix stage_transform, inv_stage_transform;
|
|||
|
+ CoglMatrix modelview, transform_to_stage;
|
|||
|
+ int v;
|
|||
|
+
|
|||
|
+ clutter_actor_get_transform (CLUTTER_ACTOR (stage), &stage_transform);
|
|||
|
+ if (!cogl_matrix_get_inverse (&stage_transform, &inv_stage_transform))
|
|||
|
+ return FALSE;
|
|||
|
+ cogl_framebuffer_get_modelview_matrix (fb, &modelview);
|
|||
|
+ cogl_matrix_multiply (&transform_to_stage, &inv_stage_transform, &modelview);
|
|||
|
+
|
|||
|
+ vertices[0].x = box->x1;
|
|||
|
+ vertices[0].y = box->y1;
|
|||
|
+
|
|||
|
+ vertices[1].x = box->x2;
|
|||
|
+ vertices[1].y = box->y1;
|
|||
|
+
|
|||
|
+ vertices[2].x = box->x2;
|
|||
|
+ vertices[2].y = box->y2;
|
|||
|
+
|
|||
|
+ vertices[3].x = box->x1;
|
|||
|
+ vertices[3].y = box->y2;
|
|||
|
+
|
|||
|
+ for (v = 0; v < 4; v++)
|
|||
|
+ {
|
|||
|
+ float z = 0.f;
|
|||
|
+ float w = 1.f;
|
|||
|
+
|
|||
|
+ cogl_matrix_transform_point (&transform_to_stage,
|
|||
|
+ &vertices[v].x,
|
|||
|
+ &vertices[v].y,
|
|||
|
+ &z,
|
|||
|
+ &w);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/**
|
|||
|
+ * clutter_actor_pick_box:
|
|||
|
+ * @self: The #ClutterActor being "pick" painted.
|
|||
|
+ * @box: A rectangle in the actor's own local coordinates.
|
|||
|
+ *
|
|||
|
+ * Logs (does a virtual paint of) a rectangle for picking. Note that @box is
|
|||
|
+ * in the actor's own local coordinates, so is usually {0,0,width,height}
|
|||
|
+ * to include the whole actor. That is unless the actor has a shaped input
|
|||
|
+ * region in which case you may wish to log the (multiple) smaller rectangles
|
|||
|
+ * that make up the input region.
|
|||
|
+ */
|
|||
|
+void
|
|||
|
+clutter_actor_pick_box (ClutterActor *self,
|
|||
|
+ const ClutterActorBox *box)
|
|||
|
+{
|
|||
|
+ ClutterStage *stage;
|
|||
|
+ ClutterPoint vertices[4];
|
|||
|
+
|
|||
|
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|||
|
+ g_return_if_fail (box != NULL);
|
|||
|
+
|
|||
|
+ if (box->x1 >= box->x2 || box->y1 >= box->y2)
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
|
|||
|
+
|
|||
|
+ if (_clutter_actor_transform_local_box_to_stage (self, stage, box, vertices))
|
|||
|
+ clutter_stage_log_pick (stage, vertices, self);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+_clutter_actor_push_pick_clip (ClutterActor *self,
|
|||
|
+ const ClutterActorBox *clip)
|
|||
|
+{
|
|||
|
+ ClutterStage *stage;
|
|||
|
+ ClutterPoint vertices[4];
|
|||
|
+
|
|||
|
+ stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
|
|||
|
+
|
|||
|
+ if (!_clutter_actor_transform_local_box_to_stage (self, stage, clip, vertices))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ clutter_stage_push_pick_clip (stage, vertices);
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void
|
|||
|
+_clutter_actor_pop_pick_clip (ClutterActor *self)
|
|||
|
+{
|
|||
|
+ ClutterActor *stage;
|
|||
|
+
|
|||
|
+ stage = _clutter_actor_get_stage_internal (self);
|
|||
|
+ clutter_stage_pop_pick_clip (CLUTTER_STAGE (stage));
|
|||
|
+}
|
|||
|
+
|
|||
|
static void
|
|||
|
clutter_actor_set_mapped (ClutterActor *self,
|
|||
|
gboolean mapped)
|
|||
|
@@ -1509,8 +1606,7 @@ clutter_actor_update_map_state (ClutterActor *self,
|
|||
|
static void
|
|||
|
clutter_actor_real_map (ClutterActor *self)
|
|||
|
{
|
|||
|
- ClutterActorPrivate *priv = self->priv;
|
|||
|
- ClutterActor *stage, *iter;
|
|||
|
+ ClutterActor *iter;
|
|||
|
|
|||
|
g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
|
|||
|
|
|||
|
@@ -1521,13 +1617,6 @@ clutter_actor_real_map (ClutterActor *self)
|
|||
|
|
|||
|
self->priv->needs_paint_volume_update = TRUE;
|
|||
|
|
|||
|
- stage = _clutter_actor_get_stage_internal (self);
|
|||
|
- priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
|
|||
|
-
|
|||
|
- CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
|
|||
|
- priv->pick_id,
|
|||
|
- _clutter_actor_get_debug_name (self));
|
|||
|
-
|
|||
|
clutter_actor_ensure_resource_scale (self);
|
|||
|
|
|||
|
/* notify on parent mapped before potentially mapping
|
|||
|
@@ -1632,11 +1721,6 @@ clutter_actor_real_unmap (ClutterActor *self)
|
|||
|
|
|||
|
stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
|
|||
|
|
|||
|
- if (stage != NULL)
|
|||
|
- _clutter_stage_release_pick_id (stage, priv->pick_id);
|
|||
|
-
|
|||
|
- priv->pick_id = -1;
|
|||
|
-
|
|||
|
if (stage != NULL &&
|
|||
|
clutter_stage_get_key_focus (stage) == self)
|
|||
|
{
|
|||
|
@@ -2255,46 +2339,16 @@ static void
|
|||
|
clutter_actor_real_pick (ClutterActor *self,
|
|||
|
const ClutterColor *color)
|
|||
|
{
|
|||
|
- CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
|
|||
|
-
|
|||
|
- /* the default implementation is just to paint a rectangle
|
|||
|
- * with the same size of the actor using the passed color
|
|||
|
- */
|
|||
|
if (clutter_actor_should_pick_paint (self))
|
|||
|
{
|
|||
|
- static CoglPipeline *default_pick_pipeline = NULL;
|
|||
|
- ClutterActorBox box = { 0, };
|
|||
|
- CoglPipeline *pick_pipeline;
|
|||
|
- float width, height;
|
|||
|
-
|
|||
|
- if (G_UNLIKELY (default_pick_pipeline == NULL))
|
|||
|
- {
|
|||
|
- CoglContext *ctx =
|
|||
|
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|||
|
-
|
|||
|
- default_pick_pipeline = cogl_pipeline_new (ctx);
|
|||
|
- }
|
|||
|
-
|
|||
|
- g_assert (default_pick_pipeline != NULL);
|
|||
|
- pick_pipeline = cogl_pipeline_copy (default_pick_pipeline);
|
|||
|
+ ClutterActorBox box = {
|
|||
|
+ .x1 = 0,
|
|||
|
+ .y1 = 0,
|
|||
|
+ .x2 = clutter_actor_get_width (self),
|
|||
|
+ .y2 = clutter_actor_get_height (self),
|
|||
|
+ };
|
|||
|
|
|||
|
- clutter_actor_get_allocation_box (self, &box);
|
|||
|
-
|
|||
|
- width = box.x2 - box.x1;
|
|||
|
- height = box.y2 - box.y1;
|
|||
|
-
|
|||
|
- cogl_pipeline_set_color4ub (pick_pipeline,
|
|||
|
- color->red,
|
|||
|
- color->green,
|
|||
|
- color->blue,
|
|||
|
- color->alpha);
|
|||
|
-
|
|||
|
- cogl_framebuffer_draw_rectangle (framebuffer,
|
|||
|
- pick_pipeline,
|
|||
|
- 0, 0,
|
|||
|
- width, height);
|
|||
|
-
|
|||
|
- cogl_object_unref (pick_pipeline);
|
|||
|
+ clutter_actor_pick_box (self, &box);
|
|||
|
}
|
|||
|
|
|||
|
/* XXX - this thoroughly sucks, but we need to maintain compatibility
|
|||
|
@@ -3585,15 +3639,6 @@ _clutter_actor_update_last_paint_volume (ClutterActor *self)
|
|||
|
priv->last_paint_volume_valid = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
-guint32
|
|||
|
-_clutter_actor_get_pick_id (ClutterActor *self)
|
|||
|
-{
|
|||
|
- if (self->priv->pick_id < 0)
|
|||
|
- return 0;
|
|||
|
-
|
|||
|
- return self->priv->pick_id;
|
|||
|
-}
|
|||
|
-
|
|||
|
/* This is the same as clutter_actor_add_effect except that it doesn't
|
|||
|
queue a redraw and it doesn't notify on the effect property */
|
|||
|
static void
|
|||
|
@@ -3826,6 +3871,7 @@ clutter_actor_paint (ClutterActor *self)
|
|||
|
ClutterActorPrivate *priv;
|
|||
|
ClutterPickMode pick_mode;
|
|||
|
gboolean culling_inhibited;
|
|||
|
+ ClutterActorBox clip;
|
|||
|
gboolean clip_set = FALSE;
|
|||
|
ClutterStage *stage;
|
|||
|
|
|||
|
@@ -3919,24 +3965,38 @@ clutter_actor_paint (ClutterActor *self)
|
|||
|
|
|||
|
if (priv->has_clip)
|
|||
|
{
|
|||
|
- CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage);
|
|||
|
- cogl_framebuffer_push_rectangle_clip (fb,
|
|||
|
- priv->clip.origin.x,
|
|||
|
- priv->clip.origin.y,
|
|||
|
- priv->clip.origin.x + priv->clip.size.width,
|
|||
|
- priv->clip.origin.y + priv->clip.size.height);
|
|||
|
+ clip.x1 = priv->clip.origin.x;
|
|||
|
+ clip.y1 = priv->clip.origin.y;
|
|||
|
+ clip.x2 = priv->clip.origin.x + priv->clip.size.width;
|
|||
|
+ clip.y2 = priv->clip.origin.y + priv->clip.size.height;
|
|||
|
clip_set = TRUE;
|
|||
|
}
|
|||
|
else if (priv->clip_to_allocation)
|
|||
|
{
|
|||
|
- CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage);
|
|||
|
- gfloat width, height;
|
|||
|
+ clip.x1 = 0.f;
|
|||
|
+ clip.y1 = 0.f;
|
|||
|
+ clip.x2 = priv->allocation.x2 - priv->allocation.x1;
|
|||
|
+ clip.y2 = priv->allocation.y2 - priv->allocation.y1;
|
|||
|
+ clip_set = TRUE;
|
|||
|
+ }
|
|||
|
|
|||
|
- width = priv->allocation.x2 - priv->allocation.x1;
|
|||
|
- height = priv->allocation.y2 - priv->allocation.y1;
|
|||
|
+ if (clip_set)
|
|||
|
+ {
|
|||
|
+ if (pick_mode == CLUTTER_PICK_NONE)
|
|||
|
+ {
|
|||
|
+ CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage);
|
|||
|
|
|||
|
- cogl_framebuffer_push_rectangle_clip (fb, 0, 0, width, height);
|
|||
|
- clip_set = TRUE;
|
|||
|
+ cogl_framebuffer_push_rectangle_clip (fb,
|
|||
|
+ clip.x1,
|
|||
|
+ clip.y1,
|
|||
|
+ clip.x2,
|
|||
|
+ clip.y2);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ {
|
|||
|
+ if (!_clutter_actor_push_pick_clip (self, &clip))
|
|||
|
+ clip_set = FALSE;
|
|||
|
+ }
|
|||
|
}
|
|||
|
|
|||
|
if (pick_mode == CLUTTER_PICK_NONE)
|
|||
|
@@ -4020,9 +4080,16 @@ clutter_actor_paint (ClutterActor *self)
|
|||
|
done:
|
|||
|
if (clip_set)
|
|||
|
{
|
|||
|
- CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage);
|
|||
|
+ if (pick_mode == CLUTTER_PICK_NONE)
|
|||
|
+ {
|
|||
|
+ CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage);
|
|||
|
|
|||
|
- cogl_framebuffer_pop_clip (fb);
|
|||
|
+ cogl_framebuffer_pop_clip (fb);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ {
|
|||
|
+ _clutter_actor_pop_pick_clip (self);
|
|||
|
+ }
|
|||
|
}
|
|||
|
|
|||
|
cogl_pop_matrix ();
|
|||
|
@@ -4093,11 +4160,12 @@ clutter_actor_continue_paint (ClutterActor *self)
|
|||
|
{
|
|||
|
ClutterColor col = { 0, };
|
|||
|
|
|||
|
- _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
|
|||
|
-
|
|||
|
- /* Actor will then paint silhouette of itself in supplied
|
|||
|
- * color. See clutter_stage_get_actor_at_pos() for where
|
|||
|
- * picking is enabled.
|
|||
|
+ /* The actor will log a silhouette of itself to the stage pick log.
|
|||
|
+ * Note that the picking color is no longer used as the "log" instead
|
|||
|
+ * keeps a weak pointer to the actor itself. But we keep the color
|
|||
|
+ * parameter for now so as to maintain ABI compatibility. The color
|
|||
|
+ * parameter can be removed when someone feels like breaking the ABI
|
|||
|
+ * along with gnome-shell.
|
|||
|
*
|
|||
|
* XXX:2.0 - Call the pick() virtual directly
|
|||
|
*/
|
|||
|
@@ -8603,8 +8671,6 @@ clutter_actor_init (ClutterActor *self)
|
|||
|
|
|||
|
self->priv = priv = clutter_actor_get_instance_private (self);
|
|||
|
|
|||
|
- priv->pick_id = -1;
|
|||
|
-
|
|||
|
priv->opacity = 0xff;
|
|||
|
priv->show_on_set_parent = TRUE;
|
|||
|
priv->resource_scale = -1.0f;
|
|||
|
diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h
|
|||
|
index 3e7a59ac0c..16b438ba64 100644
|
|||
|
--- a/clutter/clutter/clutter-actor.h
|
|||
|
+++ b/clutter/clutter/clutter-actor.h
|
|||
|
@@ -910,6 +910,10 @@ void clutter_actor_bind_model_with_properties
|
|||
|
const char *first_model_property,
|
|||
|
...);
|
|||
|
|
|||
|
+CLUTTER_EXPORT
|
|||
|
+void clutter_actor_pick_box (ClutterActor *self,
|
|||
|
+ const ClutterActorBox *box);
|
|||
|
+
|
|||
|
G_END_DECLS
|
|||
|
|
|||
|
#endif /* __CLUTTER_ACTOR_H__ */
|
|||
|
diff --git a/clutter/clutter/clutter-debug.h b/clutter/clutter/clutter-debug.h
|
|||
|
index 2462385f65..7d170d2d54 100644
|
|||
|
--- a/clutter/clutter/clutter-debug.h
|
|||
|
+++ b/clutter/clutter/clutter-debug.h
|
|||
|
@@ -30,7 +30,6 @@ typedef enum
|
|||
|
typedef enum
|
|||
|
{
|
|||
|
CLUTTER_DEBUG_NOP_PICKING = 1 << 0,
|
|||
|
- CLUTTER_DEBUG_DUMP_PICK_BUFFERS = 1 << 1
|
|||
|
} ClutterPickDebugFlag;
|
|||
|
|
|||
|
typedef enum
|
|||
|
diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c
|
|||
|
index 645c8bceb6..11c221a65b 100644
|
|||
|
--- a/clutter/clutter/clutter-main.c
|
|||
|
+++ b/clutter/clutter/clutter-main.c
|
|||
|
@@ -131,7 +131,6 @@ static const GDebugKey clutter_debug_keys[] = {
|
|||
|
|
|||
|
static const GDebugKey clutter_pick_debug_keys[] = {
|
|||
|
{ "nop-picking", CLUTTER_DEBUG_NOP_PICKING },
|
|||
|
- { "dump-pick-buffers", CLUTTER_DEBUG_DUMP_PICK_BUFFERS },
|
|||
|
};
|
|||
|
|
|||
|
static const GDebugKey clutter_paint_debug_keys[] = {
|
|||
|
@@ -533,125 +532,6 @@ clutter_get_motion_events_enabled (void)
|
|||
|
return _clutter_context_get_motion_events_enabled ();
|
|||
|
}
|
|||
|
|
|||
|
-void
|
|||
|
-_clutter_id_to_color (guint id_,
|
|||
|
- ClutterColor *col)
|
|||
|
-{
|
|||
|
- ClutterMainContext *ctx;
|
|||
|
- gint red, green, blue;
|
|||
|
-
|
|||
|
- ctx = _clutter_context_get_default ();
|
|||
|
-
|
|||
|
- if (ctx->fb_g_mask == 0)
|
|||
|
- {
|
|||
|
- /* Figure out framebuffer masks used for pick */
|
|||
|
- cogl_get_bitmasks (&ctx->fb_r_mask,
|
|||
|
- &ctx->fb_g_mask,
|
|||
|
- &ctx->fb_b_mask, NULL);
|
|||
|
-
|
|||
|
- ctx->fb_r_mask_used = ctx->fb_r_mask;
|
|||
|
- ctx->fb_g_mask_used = ctx->fb_g_mask;
|
|||
|
- ctx->fb_b_mask_used = ctx->fb_b_mask;
|
|||
|
-
|
|||
|
- /* XXX - describe what "fuzzy picking" is */
|
|||
|
- if (clutter_use_fuzzy_picking)
|
|||
|
- {
|
|||
|
- ctx->fb_r_mask_used--;
|
|||
|
- ctx->fb_g_mask_used--;
|
|||
|
- ctx->fb_b_mask_used--;
|
|||
|
- }
|
|||
|
- }
|
|||
|
-
|
|||
|
- /* compute the numbers we'll store in the components */
|
|||
|
- red = (id_ >> (ctx->fb_g_mask_used+ctx->fb_b_mask_used))
|
|||
|
- & (0xff >> (8-ctx->fb_r_mask_used));
|
|||
|
- green = (id_ >> ctx->fb_b_mask_used)
|
|||
|
- & (0xff >> (8-ctx->fb_g_mask_used));
|
|||
|
- blue = (id_)
|
|||
|
- & (0xff >> (8-ctx->fb_b_mask_used));
|
|||
|
-
|
|||
|
- /* shift left bits a bit and add one, this circumvents
|
|||
|
- * at least some potential rounding errors in GL/GLES
|
|||
|
- * driver / hw implementation.
|
|||
|
- */
|
|||
|
- if (ctx->fb_r_mask_used != ctx->fb_r_mask)
|
|||
|
- red = red * 2;
|
|||
|
- if (ctx->fb_g_mask_used != ctx->fb_g_mask)
|
|||
|
- green = green * 2;
|
|||
|
- if (ctx->fb_b_mask_used != ctx->fb_b_mask)
|
|||
|
- blue = blue * 2;
|
|||
|
-
|
|||
|
- /* shift up to be full 8bit values */
|
|||
|
- red = (red << (8 - ctx->fb_r_mask)) | (0x7f >> (ctx->fb_r_mask_used));
|
|||
|
- green = (green << (8 - ctx->fb_g_mask)) | (0x7f >> (ctx->fb_g_mask_used));
|
|||
|
- blue = (blue << (8 - ctx->fb_b_mask)) | (0x7f >> (ctx->fb_b_mask_used));
|
|||
|
-
|
|||
|
- col->red = red;
|
|||
|
- col->green = green;
|
|||
|
- col->blue = blue;
|
|||
|
- col->alpha = 0xff;
|
|||
|
-
|
|||
|
- /* XXX: We rotate the nibbles of the colors here so that there is a
|
|||
|
- * visible variation between colors of sequential actor identifiers;
|
|||
|
- * otherwise pick buffers dumped to an image will pretty much just look
|
|||
|
- * black.
|
|||
|
- */
|
|||
|
- if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
|
|||
|
- {
|
|||
|
- col->red = (col->red << 4) | (col->red >> 4);
|
|||
|
- col->green = (col->green << 4) | (col->green >> 4);
|
|||
|
- col->blue = (col->blue << 4) | (col->blue >> 4);
|
|||
|
- }
|
|||
|
-}
|
|||
|
-
|
|||
|
-guint
|
|||
|
-_clutter_pixel_to_id (guchar pixel[4])
|
|||
|
-{
|
|||
|
- ClutterMainContext *ctx;
|
|||
|
- gint red, green, blue;
|
|||
|
- guint retval;
|
|||
|
-
|
|||
|
- ctx = _clutter_context_get_default ();
|
|||
|
-
|
|||
|
- /* reduce the pixel components to the number of bits actually used of the
|
|||
|
- * 8bits.
|
|||
|
- */
|
|||
|
- if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
|
|||
|
- {
|
|||
|
- guchar tmp;
|
|||
|
-
|
|||
|
- /* XXX: In _clutter_id_to_color we rotated the nibbles of the colors so
|
|||
|
- * that there is a visible variation between colors of sequential actor
|
|||
|
- * identifiers (otherwise pick buffers dumped to an image will pretty
|
|||
|
- * much just look black.) Here we reverse that rotation.
|
|||
|
- */
|
|||
|
- tmp = ((pixel[0] << 4) | (pixel[0] >> 4));
|
|||
|
- red = tmp >> (8 - ctx->fb_r_mask);
|
|||
|
- tmp = ((pixel[1] << 4) | (pixel[1] >> 4));
|
|||
|
- green = tmp >> (8 - ctx->fb_g_mask);
|
|||
|
- tmp = ((pixel[2] << 4) | (pixel[2] >> 4));
|
|||
|
- blue = tmp >> (8 - ctx->fb_b_mask);
|
|||
|
- }
|
|||
|
- else
|
|||
|
- {
|
|||
|
- red = pixel[0] >> (8 - ctx->fb_r_mask);
|
|||
|
- green = pixel[1] >> (8 - ctx->fb_g_mask);
|
|||
|
- blue = pixel[2] >> (8 - ctx->fb_b_mask);
|
|||
|
- }
|
|||
|
-
|
|||
|
- /* divide potentially by two if 'fuzzy' */
|
|||
|
- red = red >> (ctx->fb_r_mask - ctx->fb_r_mask_used);
|
|||
|
- green = green >> (ctx->fb_g_mask - ctx->fb_g_mask_used);
|
|||
|
- blue = blue >> (ctx->fb_b_mask - ctx->fb_b_mask_used);
|
|||
|
-
|
|||
|
- /* combine the correct per component values into the final id */
|
|||
|
- retval = blue
|
|||
|
- + (green << ctx->fb_b_mask_used)
|
|||
|
- + (red << (ctx->fb_b_mask_used + ctx->fb_g_mask_used));
|
|||
|
-
|
|||
|
- return retval;
|
|||
|
-}
|
|||
|
-
|
|||
|
static CoglPangoFontMap *
|
|||
|
clutter_context_get_pango_fontmap (void)
|
|||
|
{
|
|||
|
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
|
|||
|
index 5a0fed85c9..f2f870b014 100644
|
|||
|
--- a/clutter/clutter/clutter-private.h
|
|||
|
+++ b/clutter/clutter/clutter-private.h
|
|||
|
@@ -210,11 +210,6 @@ gboolean _clutter_feature_init (GError **error);
|
|||
|
gboolean _clutter_diagnostic_enabled (void);
|
|||
|
void _clutter_diagnostic_message (const char *fmt, ...) G_GNUC_PRINTF (1, 2);
|
|||
|
|
|||
|
-/* Picking code */
|
|||
|
-guint _clutter_pixel_to_id (guchar pixel[4]);
|
|||
|
-void _clutter_id_to_color (guint id,
|
|||
|
- ClutterColor *col);
|
|||
|
-
|
|||
|
void _clutter_set_sync_to_vblank (gboolean sync_to_vblank);
|
|||
|
|
|||
|
/* use this function as the accumulator if you have a signal with
|
|||
|
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
|
|||
|
index 42474687ad..51ae47af1d 100644
|
|||
|
--- a/clutter/clutter/clutter-stage-private.h
|
|||
|
+++ b/clutter/clutter/clutter-stage-private.h
|
|||
|
@@ -75,6 +75,15 @@ gint64 _clutter_stage_get_update_time (ClutterStage *stage);
|
|||
|
void _clutter_stage_clear_update_time (ClutterStage *stage);
|
|||
|
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
|
|||
|
|
|||
|
+void clutter_stage_log_pick (ClutterStage *stage,
|
|||
|
+ const ClutterPoint *vertices,
|
|||
|
+ ClutterActor *actor);
|
|||
|
+
|
|||
|
+void clutter_stage_push_pick_clip (ClutterStage *stage,
|
|||
|
+ const ClutterPoint *vertices);
|
|||
|
+
|
|||
|
+void clutter_stage_pop_pick_clip (ClutterStage *stage);
|
|||
|
+
|
|||
|
ClutterActor *_clutter_stage_do_pick (ClutterStage *stage,
|
|||
|
gint x,
|
|||
|
gint y,
|
|||
|
@@ -93,13 +102,6 @@ void _clutter_stage_queue_redraw_entry_invalidate (Clut
|
|||
|
|
|||
|
CoglFramebuffer *_clutter_stage_get_active_framebuffer (ClutterStage *stage);
|
|||
|
|
|||
|
-gint32 _clutter_stage_acquire_pick_id (ClutterStage *stage,
|
|||
|
- ClutterActor *actor);
|
|||
|
-void _clutter_stage_release_pick_id (ClutterStage *stage,
|
|||
|
- gint32 pick_id);
|
|||
|
-ClutterActor * _clutter_stage_get_actor_by_pick_id (ClutterStage *stage,
|
|||
|
- gint32 pick_id);
|
|||
|
-
|
|||
|
void _clutter_stage_add_pointer_drag_actor (ClutterStage *stage,
|
|||
|
ClutterInputDevice *device,
|
|||
|
ClutterActor *actor);
|
|||
|
diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c
|
|||
|
index e8fa976a7d..4c4ef9d643 100644
|
|||
|
--- a/clutter/clutter/clutter-stage-window.c
|
|||
|
+++ b/clutter/clutter/clutter-stage-window.c
|
|||
|
@@ -293,24 +293,6 @@ _clutter_stage_window_redraw (ClutterStageWindow *window)
|
|||
|
iface->redraw (window);
|
|||
|
}
|
|||
|
|
|||
|
-
|
|||
|
-void
|
|||
|
-_clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
|
|||
|
- ClutterStageView *view,
|
|||
|
- int *x, int *y)
|
|||
|
-{
|
|||
|
- ClutterStageWindowInterface *iface;
|
|||
|
-
|
|||
|
- *x = 0;
|
|||
|
- *y = 0;
|
|||
|
-
|
|||
|
- g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
|
|||
|
-
|
|||
|
- iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
|||
|
- if (iface->get_dirty_pixel)
|
|||
|
- iface->get_dirty_pixel (window, view, x, y);
|
|||
|
-}
|
|||
|
-
|
|||
|
gboolean
|
|||
|
_clutter_stage_window_can_clip_redraws (ClutterStageWindow *window)
|
|||
|
{
|
|||
|
diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h
|
|||
|
index 6c3601745f..aa0c5f71cc 100644
|
|||
|
--- a/clutter/clutter/clutter-stage-window.h
|
|||
|
+++ b/clutter/clutter/clutter-stage-window.h
|
|||
|
@@ -68,10 +68,6 @@ struct _ClutterStageWindowInterface
|
|||
|
|
|||
|
void (* redraw) (ClutterStageWindow *stage_window);
|
|||
|
|
|||
|
- void (* get_dirty_pixel) (ClutterStageWindow *stage_window,
|
|||
|
- ClutterStageView *view,
|
|||
|
- int *x, int *y);
|
|||
|
-
|
|||
|
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
|
|||
|
|
|||
|
GList *(* get_views) (ClutterStageWindow *stage_window);
|
|||
|
@@ -119,10 +115,6 @@ void _clutter_stage_window_set_accept_focus (ClutterStageWin
|
|||
|
|
|||
|
void _clutter_stage_window_redraw (ClutterStageWindow *window);
|
|||
|
|
|||
|
-void _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
|
|||
|
- ClutterStageView *view,
|
|||
|
- int *x, int *y);
|
|||
|
-
|
|||
|
gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window);
|
|||
|
|
|||
|
GList * _clutter_stage_window_get_views (ClutterStageWindow *window);
|
|||
|
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
|
|||
|
index aaa77d9ede..7d88d5752f 100644
|
|||
|
--- a/clutter/clutter/clutter-stage.c
|
|||
|
+++ b/clutter/clutter/clutter-stage.c
|
|||
|
@@ -97,6 +97,11 @@ typedef enum /*< prefix=CLUTTER_STAGE >*/
|
|||
|
|
|||
|
#define STAGE_NO_CLEAR_ON_PAINT(s) ((((ClutterStage *) (s))->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0)
|
|||
|
|
|||
|
+#ifndef G_APPROX_VALUE
|
|||
|
+#define G_APPROX_VALUE(a, b, epsilon) \
|
|||
|
+ (((a) > (b) ? (a) - (b) : (b) - (a)) < (epsilon))
|
|||
|
+#endif
|
|||
|
+
|
|||
|
struct _ClutterStageQueueRedrawEntry
|
|||
|
{
|
|||
|
ClutterActor *actor;
|
|||
|
@@ -104,6 +109,19 @@ struct _ClutterStageQueueRedrawEntry
|
|||
|
ClutterPaintVolume clip;
|
|||
|
};
|
|||
|
|
|||
|
+typedef struct _PickRecord
|
|||
|
+{
|
|||
|
+ ClutterPoint vertex[4];
|
|||
|
+ ClutterActor *actor;
|
|||
|
+ int clip_stack_top;
|
|||
|
+} PickRecord;
|
|||
|
+
|
|||
|
+typedef struct _PickClipRecord
|
|||
|
+{
|
|||
|
+ int prev;
|
|||
|
+ ClutterPoint vertex[4];
|
|||
|
+} PickClipRecord;
|
|||
|
+
|
|||
|
struct _ClutterStagePrivate
|
|||
|
{
|
|||
|
/* the stage implementation */
|
|||
|
@@ -137,7 +155,11 @@ struct _ClutterStagePrivate
|
|||
|
GTimer *fps_timer;
|
|||
|
gint32 timer_n_frames;
|
|||
|
|
|||
|
- ClutterIDPool *pick_id_pool;
|
|||
|
+ GArray *pick_stack;
|
|||
|
+ GArray *pick_clip_stack;
|
|||
|
+ int pick_clip_stack_top;
|
|||
|
+ gboolean pick_stack_frozen;
|
|||
|
+ ClutterPickMode cached_pick_mode;
|
|||
|
|
|||
|
#ifdef CLUTTER_ENABLE_DEBUG
|
|||
|
gulong redraw_count;
|
|||
|
@@ -326,6 +348,211 @@ clutter_stage_get_preferred_height (ClutterActor *self,
|
|||
|
*natural_height_p = geom.height;
|
|||
|
}
|
|||
|
|
|||
|
+static void
|
|||
|
+add_pick_stack_weak_refs (ClutterStage *stage)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv = stage->priv;
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ if (priv->pick_stack_frozen)
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ for (i = 0; i < priv->pick_stack->len; i++)
|
|||
|
+ {
|
|||
|
+ PickRecord *rec = &g_array_index (priv->pick_stack, PickRecord, i);
|
|||
|
+
|
|||
|
+ if (rec->actor)
|
|||
|
+ g_object_add_weak_pointer (G_OBJECT (rec->actor),
|
|||
|
+ (gpointer) &rec->actor);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ priv->pick_stack_frozen = TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void
|
|||
|
+remove_pick_stack_weak_refs (ClutterStage *stage)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv = stage->priv;
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ if (!priv->pick_stack_frozen)
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ for (i = 0; i < priv->pick_stack->len; i++)
|
|||
|
+ {
|
|||
|
+ PickRecord *rec = &g_array_index (priv->pick_stack, PickRecord, i);
|
|||
|
+
|
|||
|
+ if (rec->actor)
|
|||
|
+ g_object_remove_weak_pointer (G_OBJECT (rec->actor),
|
|||
|
+ (gpointer) &rec->actor);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ priv->pick_stack_frozen = FALSE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void
|
|||
|
+_clutter_stage_clear_pick_stack (ClutterStage *stage)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv = stage->priv;
|
|||
|
+
|
|||
|
+ remove_pick_stack_weak_refs (stage);
|
|||
|
+ g_array_set_size (priv->pick_stack, 0);
|
|||
|
+ g_array_set_size (priv->pick_clip_stack, 0);
|
|||
|
+ priv->pick_clip_stack_top = -1;
|
|||
|
+ priv->cached_pick_mode = CLUTTER_PICK_NONE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void
|
|||
|
+clutter_stage_log_pick (ClutterStage *stage,
|
|||
|
+ const ClutterPoint *vertices,
|
|||
|
+ ClutterActor *actor)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv;
|
|||
|
+ PickRecord rec;
|
|||
|
+
|
|||
|
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
|||
|
+ g_return_if_fail (actor != NULL);
|
|||
|
+
|
|||
|
+ priv = stage->priv;
|
|||
|
+
|
|||
|
+ g_assert (!priv->pick_stack_frozen);
|
|||
|
+
|
|||
|
+ memcpy (rec.vertex, vertices, 4 * sizeof (ClutterPoint));
|
|||
|
+ rec.actor = actor;
|
|||
|
+ rec.clip_stack_top = priv->pick_clip_stack_top;
|
|||
|
+
|
|||
|
+ g_array_append_val (priv->pick_stack, rec);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void
|
|||
|
+clutter_stage_push_pick_clip (ClutterStage *stage,
|
|||
|
+ const ClutterPoint *vertices)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv;
|
|||
|
+ PickClipRecord clip;
|
|||
|
+
|
|||
|
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
|||
|
+
|
|||
|
+ priv = stage->priv;
|
|||
|
+
|
|||
|
+ g_assert (!priv->pick_stack_frozen);
|
|||
|
+
|
|||
|
+ clip.prev = priv->pick_clip_stack_top;
|
|||
|
+ memcpy (clip.vertex, vertices, 4 * sizeof (ClutterPoint));
|
|||
|
+
|
|||
|
+ g_array_append_val (priv->pick_clip_stack, clip);
|
|||
|
+ priv->pick_clip_stack_top = priv->pick_clip_stack->len - 1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void
|
|||
|
+clutter_stage_pop_pick_clip (ClutterStage *stage)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv;
|
|||
|
+ const PickClipRecord *top;
|
|||
|
+
|
|||
|
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
|||
|
+
|
|||
|
+ priv = stage->priv;
|
|||
|
+
|
|||
|
+ g_assert (!priv->pick_stack_frozen);
|
|||
|
+ g_assert (priv->pick_clip_stack_top >= 0);
|
|||
|
+
|
|||
|
+ /* Individual elements of pick_clip_stack are not freed. This is so they
|
|||
|
+ * can be shared as part of a tree of different stacks used by different
|
|||
|
+ * actors in the pick_stack. The whole pick_clip_stack does however get
|
|||
|
+ * freed later in _clutter_stage_clear_pick_stack.
|
|||
|
+ */
|
|||
|
+
|
|||
|
+ top = &g_array_index (priv->pick_clip_stack,
|
|||
|
+ PickClipRecord,
|
|||
|
+ priv->pick_clip_stack_top);
|
|||
|
+
|
|||
|
+ priv->pick_clip_stack_top = top->prev;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+is_quadrilateral_axis_aligned_rectangle (const ClutterPoint *vertices)
|
|||
|
+{
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ for (i = 0; i < 4; i++)
|
|||
|
+ {
|
|||
|
+ if (!G_APPROX_VALUE (vertices[i].x,
|
|||
|
+ vertices[(i + 1) % 4].x,
|
|||
|
+ FLT_EPSILON) &&
|
|||
|
+ !G_APPROX_VALUE (vertices[i].y,
|
|||
|
+ vertices[(i + 1) % 4].y,
|
|||
|
+ FLT_EPSILON))
|
|||
|
+ return FALSE;
|
|||
|
+ }
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+is_inside_axis_aligned_rectangle (const ClutterPoint *point,
|
|||
|
+ const ClutterPoint *vertices)
|
|||
|
+{
|
|||
|
+ float min_x = FLT_MAX;
|
|||
|
+ float max_x = FLT_MIN;
|
|||
|
+ float min_y = FLT_MAX;
|
|||
|
+ float max_y = FLT_MIN;
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ for (i = 0; i < 3; i++)
|
|||
|
+ {
|
|||
|
+ min_x = MIN (min_x, vertices[i].x);
|
|||
|
+ min_y = MIN (min_y, vertices[i].y);
|
|||
|
+ max_x = MAX (max_x, vertices[i].x);
|
|||
|
+ max_y = MAX (max_y, vertices[i].y);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return (point->x >= min_x &&
|
|||
|
+ point->y >= min_y &&
|
|||
|
+ point->x < max_x &&
|
|||
|
+ point->y < max_y);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+is_inside_input_region (const ClutterPoint *point,
|
|||
|
+ const ClutterPoint *vertices)
|
|||
|
+{
|
|||
|
+
|
|||
|
+ if (is_quadrilateral_axis_aligned_rectangle (vertices))
|
|||
|
+ return is_inside_axis_aligned_rectangle (point, vertices);
|
|||
|
+ else
|
|||
|
+ return clutter_point_inside_quadrilateral (point, vertices);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+pick_record_contains_pixel (ClutterStage *stage,
|
|||
|
+ const PickRecord *rec,
|
|||
|
+ int x,
|
|||
|
+ int y)
|
|||
|
+{
|
|||
|
+ const ClutterPoint point = CLUTTER_POINT_INIT (x, y);
|
|||
|
+ ClutterStagePrivate *priv;
|
|||
|
+ int clip_index;
|
|||
|
+
|
|||
|
+ if (!is_inside_input_region (&point, rec->vertex))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ priv = stage->priv;
|
|||
|
+ clip_index = rec->clip_stack_top;
|
|||
|
+ while (clip_index >= 0)
|
|||
|
+ {
|
|||
|
+ const PickClipRecord *clip = &g_array_index (priv->pick_clip_stack,
|
|||
|
+ PickClipRecord,
|
|||
|
+ clip_index);
|
|||
|
+
|
|||
|
+ if (!is_inside_input_region (&point, clip->vertex))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ clip_index = clip->prev;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
static inline void
|
|||
|
queue_full_redraw (ClutterStage *stage)
|
|||
|
{
|
|||
|
@@ -636,6 +863,12 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
|||
|
float viewport[4];
|
|||
|
cairo_rectangle_int_t geom;
|
|||
|
|
|||
|
+ /* Any mode of painting/picking invalidates the pick cache, unless we're
|
|||
|
+ * in the middle of building it. So we reset the cached flag but don't
|
|||
|
+ * completely clear the pick stack.
|
|||
|
+ */
|
|||
|
+ priv->cached_pick_mode = CLUTTER_PICK_NONE;
|
|||
|
+
|
|||
|
_clutter_stage_window_get_geometry (priv->impl, &geom);
|
|||
|
|
|||
|
viewport[0] = priv->viewport[0];
|
|||
|
@@ -1414,40 +1647,6 @@ clutter_stage_get_redraw_clip_bounds (ClutterStage *stage,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
-static void
|
|||
|
-read_pixels_to_file (CoglFramebuffer *fb,
|
|||
|
- char *filename_stem,
|
|||
|
- int x,
|
|||
|
- int y,
|
|||
|
- int width,
|
|||
|
- int height)
|
|||
|
-{
|
|||
|
- guint8 *data;
|
|||
|
- cairo_surface_t *surface;
|
|||
|
- static int read_count = 0;
|
|||
|
- char *filename = g_strdup_printf ("%s-%05d.png",
|
|||
|
- filename_stem,
|
|||
|
- read_count);
|
|||
|
-
|
|||
|
- data = g_malloc (4 * width * height);
|
|||
|
- cogl_framebuffer_read_pixels (fb,
|
|||
|
- x, y, width, height,
|
|||
|
- CLUTTER_CAIRO_FORMAT_ARGB32,
|
|||
|
- data);
|
|||
|
-
|
|||
|
- surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
|
|||
|
- width, height,
|
|||
|
- width * 4);
|
|||
|
-
|
|||
|
- cairo_surface_write_to_png (surface, filename);
|
|||
|
- cairo_surface_destroy (surface);
|
|||
|
-
|
|||
|
- g_free (data);
|
|||
|
- g_free (filename);
|
|||
|
-
|
|||
|
- read_count++;
|
|||
|
-}
|
|||
|
-
|
|||
|
static ClutterActor *
|
|||
|
_clutter_stage_do_pick_on_view (ClutterStage *stage,
|
|||
|
gint x,
|
|||
|
@@ -1455,140 +1654,42 @@ _clutter_stage_do_pick_on_view (ClutterStage *stage,
|
|||
|
ClutterPickMode mode,
|
|||
|
ClutterStageView *view)
|
|||
|
{
|
|||
|
- ClutterActor *actor = CLUTTER_ACTOR (stage);
|
|||
|
+ ClutterMainContext *context = _clutter_context_get_default ();
|
|||
|
ClutterStagePrivate *priv = stage->priv;
|
|||
|
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
|
|||
|
- cairo_rectangle_int_t view_layout;
|
|||
|
- ClutterMainContext *context;
|
|||
|
- guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
|
|||
|
- CoglColor stage_pick_id;
|
|||
|
- gboolean dither_enabled_save;
|
|||
|
- ClutterActor *retval;
|
|||
|
- gint dirty_x;
|
|||
|
- gint dirty_y;
|
|||
|
- gint read_x;
|
|||
|
- gint read_y;
|
|||
|
- float fb_width, fb_height;
|
|||
|
- float fb_scale;
|
|||
|
- float viewport_offset_x;
|
|||
|
- float viewport_offset_y;
|
|||
|
-
|
|||
|
- priv = stage->priv;
|
|||
|
-
|
|||
|
- context = _clutter_context_get_default ();
|
|||
|
- fb_scale = clutter_stage_view_get_scale (view);
|
|||
|
- clutter_stage_view_get_layout (view, &view_layout);
|
|||
|
-
|
|||
|
- fb_width = view_layout.width * fb_scale;
|
|||
|
- fb_height = view_layout.height * fb_scale;
|
|||
|
- cogl_push_framebuffer (fb);
|
|||
|
-
|
|||
|
- /* needed for when a context switch happens */
|
|||
|
- _clutter_stage_maybe_setup_viewport (stage, view);
|
|||
|
-
|
|||
|
- /* FIXME: For some reason leaving the cogl clip stack empty causes the
|
|||
|
- * picking to not work at all, so setting it the whole framebuffer content
|
|||
|
- * for now. */
|
|||
|
- cogl_framebuffer_push_scissor_clip (fb, 0, 0,
|
|||
|
- view_layout.width * fb_scale,
|
|||
|
- view_layout.height * fb_scale);
|
|||
|
-
|
|||
|
- _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
|
|||
|
+ int i;
|
|||
|
|
|||
|
- if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
|||
|
- {
|
|||
|
- CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
|
|||
|
- (int) (dirty_x * fb_scale),
|
|||
|
- (int) (dirty_y * fb_scale));
|
|||
|
- cogl_framebuffer_push_scissor_clip (fb, dirty_x * fb_scale, dirty_y * fb_scale, 1, 1);
|
|||
|
- }
|
|||
|
+ g_assert (context->pick_mode == CLUTTER_PICK_NONE);
|
|||
|
|
|||
|
- viewport_offset_x = x * fb_scale - dirty_x * fb_scale;
|
|||
|
- viewport_offset_y = y * fb_scale - dirty_y * fb_scale;
|
|||
|
- CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
|
|||
|
- priv->viewport[0] * fb_scale - viewport_offset_x,
|
|||
|
- priv->viewport[1] * fb_scale - viewport_offset_y,
|
|||
|
- priv->viewport[2] * fb_scale,
|
|||
|
- priv->viewport[3] * fb_scale);
|
|||
|
- cogl_framebuffer_set_viewport (fb,
|
|||
|
- priv->viewport[0] * fb_scale - viewport_offset_x,
|
|||
|
- priv->viewport[1] * fb_scale - viewport_offset_y,
|
|||
|
- priv->viewport[2] * fb_scale,
|
|||
|
- priv->viewport[3] * fb_scale);
|
|||
|
-
|
|||
|
- read_x = dirty_x * fb_scale;
|
|||
|
- read_y = dirty_y * fb_scale;
|
|||
|
-
|
|||
|
- CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d s: %f",
|
|||
|
- x, y,
|
|||
|
- view_layout.width, view_layout.height,
|
|||
|
- view_layout.x, view_layout.y, fb_scale);
|
|||
|
-
|
|||
|
- cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
|
|||
|
- cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH, &stage_pick_id);
|
|||
|
-
|
|||
|
- /* Disable dithering (if any) when doing the painting in pick mode */
|
|||
|
- dither_enabled_save = cogl_framebuffer_get_dither_enabled (fb);
|
|||
|
- cogl_framebuffer_set_dither_enabled (fb, FALSE);
|
|||
|
-
|
|||
|
- /* Render the entire scence in pick mode - just single colored silhouette's
|
|||
|
- * are drawn offscreen (as we never swap buffers)
|
|||
|
- */
|
|||
|
- context->pick_mode = mode;
|
|||
|
-
|
|||
|
- clutter_stage_do_paint_view (stage, view, NULL);
|
|||
|
- context->pick_mode = CLUTTER_PICK_NONE;
|
|||
|
-
|
|||
|
- /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
|
|||
|
- even though we don't care about the alpha component because under
|
|||
|
- GLES this is the only format that is guaranteed to work so Cogl
|
|||
|
- will end up having to do a conversion if any other format is
|
|||
|
- used. The format is requested as pre-multiplied because Cogl
|
|||
|
- assumes that all pixels in the framebuffer are premultiplied so
|
|||
|
- it avoids a conversion. */
|
|||
|
- cogl_framebuffer_read_pixels (fb,
|
|||
|
- read_x, read_y, 1, 1,
|
|||
|
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
|||
|
- pixel);
|
|||
|
-
|
|||
|
- if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
|
|||
|
+ if (mode != priv->cached_pick_mode)
|
|||
|
{
|
|||
|
- char *file_name =
|
|||
|
- g_strdup_printf ("pick-buffer-%s-view-x-%d",
|
|||
|
- _clutter_actor_get_debug_name (actor),
|
|||
|
- view_layout.x);
|
|||
|
+ _clutter_stage_clear_pick_stack (stage);
|
|||
|
|
|||
|
- read_pixels_to_file (fb, file_name, 0, 0, fb_width, fb_height);
|
|||
|
+ cogl_push_framebuffer (fb);
|
|||
|
|
|||
|
- g_free (file_name);
|
|||
|
- }
|
|||
|
-
|
|||
|
- /* Restore whether GL_DITHER was enabled */
|
|||
|
- cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save);
|
|||
|
-
|
|||
|
- if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
|||
|
- cogl_framebuffer_pop_clip (fb);
|
|||
|
+ context->pick_mode = mode;
|
|||
|
+ clutter_stage_do_paint_view (stage, view, NULL);
|
|||
|
+ context->pick_mode = CLUTTER_PICK_NONE;
|
|||
|
+ priv->cached_pick_mode = mode;
|
|||
|
|
|||
|
- cogl_framebuffer_pop_clip (fb);
|
|||
|
+ cogl_pop_framebuffer ();
|
|||
|
|
|||
|
- _clutter_stage_dirty_viewport (stage);
|
|||
|
+ add_pick_stack_weak_refs (stage);
|
|||
|
+ }
|
|||
|
|
|||
|
- if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
|
|||
|
- retval = actor;
|
|||
|
- else
|
|||
|
+ /* Search all "painted" pickable actors from front to back. A linear search
|
|||
|
+ * is required, and also performs fine since there is typically only
|
|||
|
+ * on the order of dozens of actors in the list (on screen) at a time.
|
|||
|
+ */
|
|||
|
+ for (i = priv->pick_stack->len - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
- guint32 id_ = _clutter_pixel_to_id (pixel);
|
|||
|
+ const PickRecord *rec = &g_array_index (priv->pick_stack, PickRecord, i);
|
|||
|
|
|||
|
- retval = _clutter_stage_get_actor_by_pick_id (stage, id_);
|
|||
|
- CLUTTER_NOTE (PICK, "Picking actor %s with id %u (pixel: 0x%x%x%x%x",
|
|||
|
- G_OBJECT_TYPE_NAME (retval),
|
|||
|
- id_,
|
|||
|
- pixel[0], pixel[1], pixel[2], pixel[3]);
|
|||
|
+ if (rec->actor && pick_record_contains_pixel (stage, rec, x, y))
|
|||
|
+ return rec->actor;
|
|||
|
}
|
|||
|
|
|||
|
- cogl_pop_framebuffer ();
|
|||
|
-
|
|||
|
- return retval;
|
|||
|
+ return CLUTTER_ACTOR (stage);
|
|||
|
}
|
|||
|
|
|||
|
static ClutterStageView *
|
|||
|
@@ -1901,7 +2002,9 @@ clutter_stage_finalize (GObject *object)
|
|||
|
|
|||
|
g_array_free (priv->paint_volume_stack, TRUE);
|
|||
|
|
|||
|
- _clutter_id_pool_free (priv->pick_id_pool);
|
|||
|
+ _clutter_stage_clear_pick_stack (stage);
|
|||
|
+ g_array_free (priv->pick_clip_stack, TRUE);
|
|||
|
+ g_array_free (priv->pick_stack, TRUE);
|
|||
|
|
|||
|
if (priv->fps_timer != NULL)
|
|||
|
g_timer_destroy (priv->fps_timer);
|
|||
|
@@ -2435,7 +2538,10 @@ clutter_stage_init (ClutterStage *self)
|
|||
|
priv->paint_volume_stack =
|
|||
|
g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
|
|||
|
|
|||
|
- priv->pick_id_pool = _clutter_id_pool_new (256);
|
|||
|
+ priv->pick_stack = g_array_new (FALSE, FALSE, sizeof (PickRecord));
|
|||
|
+ priv->pick_clip_stack = g_array_new (FALSE, FALSE, sizeof (PickClipRecord));
|
|||
|
+ priv->pick_clip_stack_top = -1;
|
|||
|
+ priv->cached_pick_mode = CLUTTER_PICK_NONE;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
@@ -4253,6 +4359,12 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage,
|
|||
|
CLUTTER_NOTE (CLIPPING, "stage_queue_actor_redraw (actor=%s, clip=%p): ",
|
|||
|
_clutter_actor_get_debug_name (actor), clip);
|
|||
|
|
|||
|
+ /* Queuing a redraw or clip change invalidates the pick cache, unless we're
|
|||
|
+ * in the middle of building it. So we reset the cached flag but don't
|
|||
|
+ * completely clear the pick stack...
|
|||
|
+ */
|
|||
|
+ priv->cached_pick_mode = CLUTTER_PICK_NONE;
|
|||
|
+
|
|||
|
if (!priv->redraw_pending)
|
|||
|
{
|
|||
|
ClutterMasterClock *master_clock;
|
|||
|
@@ -4513,39 +4625,6 @@ _clutter_stage_get_active_framebuffer (ClutterStage *stage)
|
|||
|
return stage->priv->active_framebuffer;
|
|||
|
}
|
|||
|
|
|||
|
-gint32
|
|||
|
-_clutter_stage_acquire_pick_id (ClutterStage *stage,
|
|||
|
- ClutterActor *actor)
|
|||
|
-{
|
|||
|
- ClutterStagePrivate *priv = stage->priv;
|
|||
|
-
|
|||
|
- g_assert (priv->pick_id_pool != NULL);
|
|||
|
-
|
|||
|
- return _clutter_id_pool_add (priv->pick_id_pool, actor);
|
|||
|
-}
|
|||
|
-
|
|||
|
-void
|
|||
|
-_clutter_stage_release_pick_id (ClutterStage *stage,
|
|||
|
- gint32 pick_id)
|
|||
|
-{
|
|||
|
- ClutterStagePrivate *priv = stage->priv;
|
|||
|
-
|
|||
|
- g_assert (priv->pick_id_pool != NULL);
|
|||
|
-
|
|||
|
- _clutter_id_pool_remove (priv->pick_id_pool, pick_id);
|
|||
|
-}
|
|||
|
-
|
|||
|
-ClutterActor *
|
|||
|
-_clutter_stage_get_actor_by_pick_id (ClutterStage *stage,
|
|||
|
- gint32 pick_id)
|
|||
|
-{
|
|||
|
- ClutterStagePrivate *priv = stage->priv;
|
|||
|
-
|
|||
|
- g_assert (priv->pick_id_pool != NULL);
|
|||
|
-
|
|||
|
- return _clutter_id_pool_lookup (priv->pick_id_pool, pick_id);
|
|||
|
-}
|
|||
|
-
|
|||
|
void
|
|||
|
_clutter_stage_add_pointer_drag_actor (ClutterStage *stage,
|
|||
|
ClutterInputDevice *device,
|
|||
|
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
|
|||
|
index 3f1f609c4e..effed79759 100644
|
|||
|
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
|
|||
|
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
|
|||
|
@@ -926,57 +926,6 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
|||
|
stage_cogl->frame_count++;
|
|||
|
}
|
|||
|
|
|||
|
-static void
|
|||
|
-clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
|
|||
|
- ClutterStageView *view,
|
|||
|
- int *x,
|
|||
|
- int *y)
|
|||
|
-{
|
|||
|
- CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
|
|||
|
- ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
|
|||
|
- ClutterStageViewCoglPrivate *view_priv =
|
|||
|
- clutter_stage_view_cogl_get_instance_private (view_cogl);
|
|||
|
- gboolean has_buffer_age =
|
|||
|
- cogl_is_onscreen (onscreen) &&
|
|||
|
- is_buffer_age_enabled ();
|
|||
|
- float fb_scale;
|
|||
|
- gboolean scale_is_fractional;
|
|||
|
-
|
|||
|
- fb_scale = clutter_stage_view_get_scale (view);
|
|||
|
- if (fb_scale != floorf (fb_scale))
|
|||
|
- scale_is_fractional = TRUE;
|
|||
|
- else
|
|||
|
- scale_is_fractional = FALSE;
|
|||
|
-
|
|||
|
- /*
|
|||
|
- * Buffer damage is tracked in the framebuffer coordinate space
|
|||
|
- * using the damage history. When fractional scaling is used, a
|
|||
|
- * coordinate on the stage might not correspond to the exact position of any
|
|||
|
- * physical pixel, which causes issues when painting using the pick mode.
|
|||
|
- *
|
|||
|
- * For now, always use the (0, 0) pixel for picking when using fractional
|
|||
|
- * framebuffer scaling.
|
|||
|
- */
|
|||
|
- if (!has_buffer_age ||
|
|||
|
- scale_is_fractional ||
|
|||
|
- !clutter_damage_history_is_age_valid (view_priv->damage_history, 0))
|
|||
|
- {
|
|||
|
- *x = 0;
|
|||
|
- *y = 0;
|
|||
|
- }
|
|||
|
- else
|
|||
|
- {
|
|||
|
- cairo_rectangle_int_t view_layout;
|
|||
|
- const cairo_rectangle_int_t *fb_damage;
|
|||
|
-
|
|||
|
- clutter_stage_view_get_layout (view, &view_layout);
|
|||
|
-
|
|||
|
- fb_damage = clutter_damage_history_lookup (view_priv->damage_history, 0);
|
|||
|
- *x = fb_damage->x / fb_scale;
|
|||
|
- *y = fb_damage->y / fb_scale;
|
|||
|
- }
|
|||
|
-}
|
|||
|
-
|
|||
|
static void
|
|||
|
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
|
|||
|
{
|
|||
|
@@ -994,7 +943,6 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
|
|||
|
iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips;
|
|||
|
iface->get_redraw_clip_bounds = clutter_stage_cogl_get_redraw_clip_bounds;
|
|||
|
iface->redraw = clutter_stage_cogl_redraw;
|
|||
|
- iface->get_dirty_pixel = clutter_stage_cogl_get_dirty_pixel;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
diff --git a/clutter/clutter/deprecated/clutter-texture.c b/clutter/clutter/deprecated/clutter-texture.c
|
|||
|
index bea239f454..2c677b8a44 100644
|
|||
|
--- a/clutter/clutter/deprecated/clutter-texture.c
|
|||
|
+++ b/clutter/clutter/deprecated/clutter-texture.c
|
|||
|
@@ -572,83 +572,6 @@ gen_texcoords_and_draw_cogl_rectangle (ClutterActor *self,
|
|||
|
0, 0, t_w, t_h);
|
|||
|
}
|
|||
|
|
|||
|
-static CoglPipeline *
|
|||
|
-create_pick_pipeline (ClutterActor *self)
|
|||
|
-{
|
|||
|
- ClutterTexture *texture = CLUTTER_TEXTURE (self);
|
|||
|
- ClutterTexturePrivate *priv = texture->priv;
|
|||
|
- CoglPipeline *pick_pipeline = cogl_pipeline_copy (texture_template_pipeline);
|
|||
|
- GError *error = NULL;
|
|||
|
-
|
|||
|
- if (!cogl_pipeline_set_layer_combine (pick_pipeline, 0,
|
|||
|
- "RGBA = "
|
|||
|
- " MODULATE (CONSTANT, TEXTURE[A])",
|
|||
|
- &error))
|
|||
|
- {
|
|||
|
- if (!priv->seen_create_pick_pipeline_warning)
|
|||
|
- g_warning ("Error setting up texture combine for shaped "
|
|||
|
- "texture picking: %s", error->message);
|
|||
|
- priv->seen_create_pick_pipeline_warning = TRUE;
|
|||
|
- g_error_free (error);
|
|||
|
- cogl_object_unref (pick_pipeline);
|
|||
|
- return NULL;
|
|||
|
- }
|
|||
|
-
|
|||
|
- cogl_pipeline_set_blend (pick_pipeline,
|
|||
|
- "RGBA = ADD (SRC_COLOR[RGBA], 0)",
|
|||
|
- NULL);
|
|||
|
-
|
|||
|
- cogl_pipeline_set_alpha_test_function (pick_pipeline,
|
|||
|
- COGL_PIPELINE_ALPHA_FUNC_EQUAL,
|
|||
|
- 1.0);
|
|||
|
-
|
|||
|
- return pick_pipeline;
|
|||
|
-}
|
|||
|
-
|
|||
|
-static void
|
|||
|
-clutter_texture_pick (ClutterActor *self,
|
|||
|
- const ClutterColor *color)
|
|||
|
-{
|
|||
|
- ClutterTexture *texture = CLUTTER_TEXTURE (self);
|
|||
|
- ClutterTexturePrivate *priv = texture->priv;
|
|||
|
- CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
|
|||
|
-
|
|||
|
- if (!clutter_actor_should_pick_paint (self))
|
|||
|
- return;
|
|||
|
-
|
|||
|
- if (G_LIKELY (priv->pick_with_alpha_supported) && priv->pick_with_alpha)
|
|||
|
- {
|
|||
|
- CoglColor pick_color;
|
|||
|
-
|
|||
|
- if (priv->pick_pipeline == NULL)
|
|||
|
- priv->pick_pipeline = create_pick_pipeline (self);
|
|||
|
-
|
|||
|
- if (priv->pick_pipeline == NULL)
|
|||
|
- {
|
|||
|
- priv->pick_with_alpha_supported = FALSE;
|
|||
|
- CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->pick (self,
|
|||
|
- color);
|
|||
|
- return;
|
|||
|
- }
|
|||
|
-
|
|||
|
- if (priv->fbo_handle != NULL)
|
|||
|
- update_fbo (self);
|
|||
|
-
|
|||
|
- cogl_color_init_from_4ub (&pick_color,
|
|||
|
- color->red,
|
|||
|
- color->green,
|
|||
|
- color->blue,
|
|||
|
- 0xff);
|
|||
|
- cogl_pipeline_set_layer_combine_constant (priv->pick_pipeline,
|
|||
|
- 0, &pick_color);
|
|||
|
- cogl_pipeline_set_layer_texture (priv->pick_pipeline, 0,
|
|||
|
- clutter_texture_get_cogl_texture (texture));
|
|||
|
- gen_texcoords_and_draw_cogl_rectangle (self, priv->pick_pipeline, framebuffer);
|
|||
|
- }
|
|||
|
- else
|
|||
|
- CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->pick (self, color);
|
|||
|
-}
|
|||
|
-
|
|||
|
static void
|
|||
|
clutter_texture_paint (ClutterActor *self)
|
|||
|
{
|
|||
|
@@ -767,12 +690,6 @@ clutter_texture_dispose (GObject *object)
|
|||
|
priv->pipeline = NULL;
|
|||
|
}
|
|||
|
|
|||
|
- if (priv->pick_pipeline != NULL)
|
|||
|
- {
|
|||
|
- cogl_object_unref (priv->pick_pipeline);
|
|||
|
- priv->pick_pipeline = NULL;
|
|||
|
- }
|
|||
|
-
|
|||
|
G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object);
|
|||
|
}
|
|||
|
|
|||
|
@@ -944,7 +861,6 @@ clutter_texture_class_init (ClutterTextureClass *klass)
|
|||
|
GParamSpec *pspec;
|
|||
|
|
|||
|
actor_class->paint = clutter_texture_paint;
|
|||
|
- actor_class->pick = clutter_texture_pick;
|
|||
|
actor_class->get_paint_volume = clutter_texture_get_paint_volume;
|
|||
|
actor_class->realize = clutter_texture_realize;
|
|||
|
actor_class->unrealize = clutter_texture_unrealize;
|
|||
|
@@ -1263,11 +1179,9 @@ clutter_texture_init (ClutterTexture *self)
|
|||
|
priv->repeat_y = FALSE;
|
|||
|
priv->sync_actor_size = TRUE;
|
|||
|
priv->fbo_handle = NULL;
|
|||
|
- priv->pick_pipeline = NULL;
|
|||
|
priv->keep_aspect_ratio = FALSE;
|
|||
|
priv->pick_with_alpha = FALSE;
|
|||
|
priv->pick_with_alpha_supported = TRUE;
|
|||
|
- priv->seen_create_pick_pipeline_warning = FALSE;
|
|||
|
|
|||
|
if (G_UNLIKELY (texture_template_pipeline == NULL))
|
|||
|
{
|
|||
|
@@ -3052,13 +2966,8 @@ clutter_texture_set_pick_with_alpha (ClutterTexture *texture,
|
|||
|
if (priv->pick_with_alpha == pick_with_alpha)
|
|||
|
return;
|
|||
|
|
|||
|
- if (!pick_with_alpha && priv->pick_pipeline != NULL)
|
|||
|
- {
|
|||
|
- cogl_object_unref (priv->pick_pipeline);
|
|||
|
- priv->pick_pipeline = NULL;
|
|||
|
- }
|
|||
|
+ g_assert (!pick_with_alpha); /* No longer supported */
|
|||
|
|
|||
|
- /* NB: the pick pipeline is created lazily when we first pick */
|
|||
|
priv->pick_with_alpha = pick_with_alpha;
|
|||
|
|
|||
|
/* NB: actors are expected to call clutter_actor_queue_redraw when
|
|||
|
diff --git a/clutter/tests/conform/actor-pick.c b/clutter/tests/conform/actor-pick.c
|
|||
|
index 969b4920ac..2bf5954c73 100644
|
|||
|
--- a/clutter/tests/conform/actor-pick.c
|
|||
|
+++ b/clutter/tests/conform/actor-pick.c
|
|||
|
@@ -5,7 +5,6 @@
|
|||
|
#define STAGE_HEIGHT 480
|
|||
|
#define ACTORS_X 12
|
|||
|
#define ACTORS_Y 16
|
|||
|
-#define SHIFT_STEP STAGE_WIDTH / ACTORS_X
|
|||
|
|
|||
|
typedef struct _State State;
|
|||
|
|
|||
|
@@ -20,84 +19,11 @@ struct _State
|
|||
|
gboolean pass;
|
|||
|
};
|
|||
|
|
|||
|
-struct _ShiftEffect
|
|||
|
-{
|
|||
|
- ClutterShaderEffect parent_instance;
|
|||
|
-};
|
|||
|
-
|
|||
|
-struct _ShiftEffectClass
|
|||
|
-{
|
|||
|
- ClutterShaderEffectClass parent_class;
|
|||
|
-};
|
|||
|
-
|
|||
|
-typedef struct _ShiftEffect ShiftEffect;
|
|||
|
-typedef struct _ShiftEffectClass ShiftEffectClass;
|
|||
|
-
|
|||
|
-#define TYPE_SHIFT_EFFECT (shift_effect_get_type ())
|
|||
|
-
|
|||
|
-GType shift_effect_get_type (void);
|
|||
|
-
|
|||
|
-G_DEFINE_TYPE (ShiftEffect,
|
|||
|
- shift_effect,
|
|||
|
- CLUTTER_TYPE_SHADER_EFFECT);
|
|||
|
-
|
|||
|
-static void
|
|||
|
-shader_paint (ClutterEffect *effect,
|
|||
|
- ClutterEffectPaintFlags flags)
|
|||
|
-{
|
|||
|
- ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect);
|
|||
|
- float tex_width;
|
|||
|
- ClutterActor *actor =
|
|||
|
- clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
|
|||
|
-
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_debug ("shader_paint");
|
|||
|
-
|
|||
|
- clutter_shader_effect_set_shader_source (shader,
|
|||
|
- "uniform sampler2D tex;\n"
|
|||
|
- "uniform float step;\n"
|
|||
|
- "void main (void)\n"
|
|||
|
- "{\n"
|
|||
|
- " cogl_color_out = texture2D(tex, vec2 (cogl_tex_coord_in[0].s + step,\n"
|
|||
|
- " cogl_tex_coord_in[0].t));\n"
|
|||
|
- "}\n");
|
|||
|
-
|
|||
|
- tex_width = clutter_actor_get_width (actor);
|
|||
|
-
|
|||
|
- clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0);
|
|||
|
- clutter_shader_effect_set_uniform (shader, "step", G_TYPE_FLOAT, 1,
|
|||
|
- SHIFT_STEP / tex_width);
|
|||
|
-
|
|||
|
- CLUTTER_EFFECT_CLASS (shift_effect_parent_class)->paint (effect, flags);
|
|||
|
-}
|
|||
|
-
|
|||
|
-static void
|
|||
|
-shader_pick (ClutterEffect *effect,
|
|||
|
- ClutterEffectPaintFlags flags)
|
|||
|
-{
|
|||
|
- shader_paint (effect, flags);
|
|||
|
-}
|
|||
|
-
|
|||
|
-static void
|
|||
|
-shift_effect_class_init (ShiftEffectClass *klass)
|
|||
|
-{
|
|||
|
- ClutterEffectClass *shader_class = CLUTTER_EFFECT_CLASS (klass);
|
|||
|
-
|
|||
|
- shader_class->paint = shader_paint;
|
|||
|
- shader_class->pick = shader_pick;
|
|||
|
-}
|
|||
|
-
|
|||
|
-static void
|
|||
|
-shift_effect_init (ShiftEffect *self)
|
|||
|
-{
|
|||
|
-}
|
|||
|
-
|
|||
|
static const char *test_passes[] = {
|
|||
|
"No covering actor",
|
|||
|
"Invisible covering actor",
|
|||
|
"Clipped covering actor",
|
|||
|
"Blur effect",
|
|||
|
- "Shift effect",
|
|||
|
};
|
|||
|
|
|||
|
static gboolean
|
|||
|
@@ -165,30 +91,10 @@ on_timeout (gpointer data)
|
|||
|
if (g_test_verbose ())
|
|||
|
g_print ("With blur effect:\n");
|
|||
|
}
|
|||
|
- else if (test_num == 4)
|
|||
|
- {
|
|||
|
- if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
|||
|
- continue;
|
|||
|
-
|
|||
|
- clutter_actor_hide (over_actor);
|
|||
|
- clutter_actor_remove_effect_by_name (CLUTTER_ACTOR (state->stage),
|
|||
|
- "blur");
|
|||
|
-
|
|||
|
- clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
|
|||
|
- "shift",
|
|||
|
- g_object_new (TYPE_SHIFT_EFFECT,
|
|||
|
- NULL));
|
|||
|
-
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("With shift effect:\n");
|
|||
|
- }
|
|||
|
|
|||
|
for (y = 0; y < ACTORS_Y; y++)
|
|||
|
{
|
|||
|
- if (test_num == 4)
|
|||
|
- x = 1;
|
|||
|
- else
|
|||
|
- x = 0;
|
|||
|
+ x = 0;
|
|||
|
|
|||
|
for (; x < ACTORS_X; x++)
|
|||
|
{
|
|||
|
@@ -198,9 +104,6 @@ on_timeout (gpointer data)
|
|||
|
|
|||
|
pick_x = x * state->actor_width + state->actor_width / 2;
|
|||
|
|
|||
|
- if (test_num == 4)
|
|||
|
- pick_x -= SHIFT_STEP;
|
|||
|
-
|
|||
|
actor =
|
|||
|
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
|
|||
|
CLUTTER_PICK_ALL,
|
|||
|
diff --git a/clutter/tests/conform/meson.build b/clutter/tests/conform/meson.build
|
|||
|
index a9f2d7e20c..fffc9014c4 100644
|
|||
|
--- a/clutter/tests/conform/meson.build
|
|||
|
+++ b/clutter/tests/conform/meson.build
|
|||
|
@@ -42,7 +42,6 @@ clutter_conform_tests_deprecated_tests = [
|
|||
|
'behaviours',
|
|||
|
'group',
|
|||
|
'rectangle',
|
|||
|
- 'texture',
|
|||
|
]
|
|||
|
|
|||
|
clutter_conform_tests = []
|
|||
|
diff --git a/clutter/tests/conform/texture.c b/clutter/tests/conform/texture.c
|
|||
|
deleted file mode 100644
|
|||
|
index 392fd5c47e..0000000000
|
|||
|
--- a/clutter/tests/conform/texture.c
|
|||
|
+++ /dev/null
|
|||
|
@@ -1,84 +0,0 @@
|
|||
|
-#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
|
|||
|
-#include <clutter/clutter.h>
|
|||
|
-#include <string.h>
|
|||
|
-
|
|||
|
-static CoglHandle
|
|||
|
-make_texture (void)
|
|||
|
-{
|
|||
|
- guint32 *data = g_malloc (100 * 100 * 4);
|
|||
|
- int x;
|
|||
|
- int y;
|
|||
|
-
|
|||
|
- for (y = 0; y < 100; y ++)
|
|||
|
- for (x = 0; x < 100; x++)
|
|||
|
- {
|
|||
|
- if (x < 50 && y < 50)
|
|||
|
- data[y * 100 + x] = 0xff00ff00;
|
|||
|
- else
|
|||
|
- data[y * 100 + x] = 0xff00ffff;
|
|||
|
- }
|
|||
|
- return cogl_texture_new_from_data (100,
|
|||
|
- 100,
|
|||
|
- COGL_TEXTURE_NONE,
|
|||
|
- COGL_PIXEL_FORMAT_ARGB_8888,
|
|||
|
- COGL_PIXEL_FORMAT_ARGB_8888,
|
|||
|
- 400,
|
|||
|
- (guchar *)data);
|
|||
|
-}
|
|||
|
-
|
|||
|
-static void
|
|||
|
-texture_pick_with_alpha (void)
|
|||
|
-{
|
|||
|
- ClutterTexture *tex = CLUTTER_TEXTURE (clutter_texture_new ());
|
|||
|
- ClutterStage *stage = CLUTTER_STAGE (clutter_test_get_stage ());
|
|||
|
- ClutterActor *actor;
|
|||
|
-
|
|||
|
- clutter_texture_set_cogl_texture (tex, make_texture ());
|
|||
|
-
|
|||
|
- clutter_actor_add_child (CLUTTER_ACTOR (stage), CLUTTER_ACTOR (tex));
|
|||
|
-
|
|||
|
- clutter_actor_show (CLUTTER_ACTOR (stage));
|
|||
|
-
|
|||
|
- if (g_test_verbose ())
|
|||
|
- {
|
|||
|
- g_print ("\nstage = %p\n", stage);
|
|||
|
- g_print ("texture = %p\n\n", tex);
|
|||
|
- }
|
|||
|
-
|
|||
|
- clutter_texture_set_pick_with_alpha (tex, TRUE);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("Testing with pick-with-alpha enabled:\n");
|
|||
|
-
|
|||
|
- /* This should fall through and hit the stage: */
|
|||
|
- actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("actor @ (10, 10) = %p\n", actor);
|
|||
|
- g_assert (actor == CLUTTER_ACTOR (stage));
|
|||
|
-
|
|||
|
- /* The rest should hit the texture */
|
|||
|
- actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 10);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("actor @ (90, 10) = %p\n", actor);
|
|||
|
- g_assert (actor == CLUTTER_ACTOR (tex));
|
|||
|
- actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 90);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("actor @ (90, 90) = %p\n", actor);
|
|||
|
- g_assert (actor == CLUTTER_ACTOR (tex));
|
|||
|
- actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 90);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("actor @ (10, 90) = %p\n", actor);
|
|||
|
- g_assert (actor == CLUTTER_ACTOR (tex));
|
|||
|
-
|
|||
|
- clutter_texture_set_pick_with_alpha (tex, FALSE);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("Testing with pick-with-alpha disabled:\n");
|
|||
|
-
|
|||
|
- actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
|
|||
|
- if (g_test_verbose ())
|
|||
|
- g_print ("actor @ (10, 10) = %p\n", actor);
|
|||
|
- g_assert (actor == CLUTTER_ACTOR (tex));
|
|||
|
-}
|
|||
|
-
|
|||
|
-CLUTTER_TEST_SUITE (
|
|||
|
- CLUTTER_TEST_UNIT ("/texture/pick-with-alpha", texture_pick_with_alpha)
|
|||
|
-)
|
|||
|
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
|
|||
|
index ca4ca19a99..814199145a 100644
|
|||
|
--- a/src/compositor/meta-surface-actor.c
|
|||
|
+++ b/src/compositor/meta-surface-actor.c
|
|||
|
@@ -70,38 +70,23 @@ meta_surface_actor_pick (ClutterActor *actor,
|
|||
|
else
|
|||
|
{
|
|||
|
int n_rects;
|
|||
|
- float *rectangles;
|
|||
|
int i;
|
|||
|
- CoglPipeline *pipeline;
|
|||
|
- CoglContext *ctx;
|
|||
|
- CoglFramebuffer *fb;
|
|||
|
- CoglColor cogl_color;
|
|||
|
|
|||
|
n_rects = cairo_region_num_rectangles (priv->input_region);
|
|||
|
- rectangles = g_alloca (sizeof (float) * 4 * n_rects);
|
|||
|
|
|||
|
for (i = 0; i < n_rects; i++)
|
|||
|
{
|
|||
|
cairo_rectangle_int_t rect;
|
|||
|
- int pos = i * 4;
|
|||
|
+ ClutterActorBox box;
|
|||
|
|
|||
|
cairo_region_get_rectangle (priv->input_region, i, &rect);
|
|||
|
|
|||
|
- rectangles[pos + 0] = rect.x;
|
|||
|
- rectangles[pos + 1] = rect.y;
|
|||
|
- rectangles[pos + 2] = rect.x + rect.width;
|
|||
|
- rectangles[pos + 3] = rect.y + rect.height;
|
|||
|
+ box.x1 = rect.x;
|
|||
|
+ box.y1 = rect.y;
|
|||
|
+ box.x2 = rect.x + rect.width;
|
|||
|
+ box.y2 = rect.y + rect.height;
|
|||
|
+ clutter_actor_pick_box (actor, &box);
|
|||
|
}
|
|||
|
-
|
|||
|
- ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|||
|
- fb = cogl_get_draw_framebuffer ();
|
|||
|
-
|
|||
|
- cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
|
|||
|
-
|
|||
|
- pipeline = cogl_pipeline_new (ctx);
|
|||
|
- cogl_pipeline_set_color (pipeline, &cogl_color);
|
|||
|
- cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
|
|||
|
- cogl_object_unref (pipeline);
|
|||
|
}
|
|||
|
|
|||
|
clutter_actor_iter_init (&iter, actor);
|
|||
|
--
|
|||
|
2.29.2
|
|||
|
|
|||
|
|
|||
|
From 254e93de8d60393ca94fa430c0acc6f6a7b9516e Mon Sep 17 00:00:00 2001
|
|||
|
From: Iain Lane <laney@debian.org>
|
|||
|
Date: Mon, 9 Sep 2019 10:17:22 +0100
|
|||
|
Subject: [PATCH 3/4] build: Compile with `-ffloat-store` on x86 (32 bit)
|
|||
|
|
|||
|
GCC's manpage says that this flag does the following:
|
|||
|
|
|||
|
Do not store floating-point variables in registers, and inhibit other
|
|||
|
options that might change whether a floating-point value is taken from
|
|||
|
a register or memory.
|
|||
|
|
|||
|
This option prevents undesirable excess precision on machines such as
|
|||
|
the 68000 where the floating registers (of the 68881) keep more
|
|||
|
precision than a "double" is supposed to have. Similarly for the x86
|
|||
|
architecture. For most programs, the excess precision does only good,
|
|||
|
but a few programs rely on the precise definition of IEEE floating
|
|||
|
point.
|
|||
|
|
|||
|
We rely on this behaviour in our fork of clutter. When performing
|
|||
|
floating point computations on x86, we are getting the wrong results
|
|||
|
because of this architecture's use of the CPU's extended (x87, non-IEEE
|
|||
|
confirming) precision by default. If we enable `-ffloat-store` here,
|
|||
|
then we'll get the same results everywhere by storing into variables
|
|||
|
instead of registers. This does not remove the need to be correct when
|
|||
|
handling floats, but it does mean we don't need to be more correct than
|
|||
|
the IEEE spec requires.
|
|||
|
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/merge_requests/785
|
|||
|
---
|
|||
|
meson.build | 3 +++
|
|||
|
1 file changed, 3 insertions(+)
|
|||
|
|
|||
|
diff --git a/meson.build b/meson.build
|
|||
|
index 8ef592bc58..e1edb78ba7 100644
|
|||
|
--- a/meson.build
|
|||
|
+++ b/meson.build
|
|||
|
@@ -267,6 +267,9 @@ foreach function : required_functions
|
|||
|
endif
|
|||
|
endforeach
|
|||
|
|
|||
|
+if host_machine.cpu_family() == 'x86'
|
|||
|
+ add_project_arguments('-ffloat-store', language: 'c')
|
|||
|
+endif
|
|||
|
add_project_arguments('-D_GNU_SOURCE', language: 'c')
|
|||
|
|
|||
|
all_warnings = [
|
|||
|
--
|
|||
|
2.29.2
|
|||
|
|
|||
|
|
|||
|
From 2d42caef14772984344e62ce40957d3b40e1f2b6 Mon Sep 17 00:00:00 2001
|
|||
|
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
|
|||
|
Date: Thu, 19 Sep 2019 11:27:50 +0200
|
|||
|
Subject: [PATCH 4/4] stage: Compute view perspective when parameters changed
|
|||
|
|
|||
|
Clutter stage used to compute the initial projection using a fixed z
|
|||
|
translation which wasn't matching the one we computed in
|
|||
|
calculate_z_translation().
|
|||
|
This caused to have a wrong initial projection on startup which was then
|
|||
|
correctly recomputed only at the first paint.
|
|||
|
|
|||
|
However, since this calculation doesn't depend on view, but only on viewport
|
|||
|
size, perspective's fovy and z_near we can safely do this at startup and
|
|||
|
only when any of those parameters change.
|
|||
|
|
|||
|
Then we can move the computation out _clutter_stage_maybe_setup_viewport()
|
|||
|
since the cogl framebuffer viewport sizes aren't affecting this.
|
|||
|
|
|||
|
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1639
|
|||
|
https://gitlab.gnome.org/GNOME/mutter/merge_requests/803
|
|||
|
---
|
|||
|
clutter/clutter/clutter-stage.c | 104 +++++++++++++++-----------------
|
|||
|
1 file changed, 47 insertions(+), 57 deletions(-)
|
|||
|
|
|||
|
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
|
|||
|
index 7d88d5752f..0cfa87486e 100644
|
|||
|
--- a/clutter/clutter/clutter-stage.c
|
|||
|
+++ b/clutter/clutter/clutter-stage.c
|
|||
|
@@ -234,6 +234,7 @@ static void capture_view_into (ClutterStage *stage,
|
|||
|
cairo_rectangle_int_t *rect,
|
|||
|
uint8_t *data,
|
|||
|
int stride);
|
|||
|
+static void clutter_stage_update_view_perspective (ClutterStage *stage);
|
|||
|
|
|||
|
static void clutter_container_iface_init (ClutterContainerIface *iface);
|
|||
|
|
|||
|
@@ -2492,29 +2493,6 @@ clutter_stage_init (ClutterStage *self)
|
|||
|
clutter_actor_set_background_color (CLUTTER_ACTOR (self),
|
|||
|
&default_stage_color);
|
|||
|
|
|||
|
- priv->perspective.fovy = 60.0; /* 60 Degrees */
|
|||
|
- priv->perspective.aspect = (float) geom.width / (float) geom.height;
|
|||
|
- priv->perspective.z_near = 0.1;
|
|||
|
- priv->perspective.z_far = 100.0;
|
|||
|
-
|
|||
|
- cogl_matrix_init_identity (&priv->projection);
|
|||
|
- cogl_matrix_perspective (&priv->projection,
|
|||
|
- priv->perspective.fovy,
|
|||
|
- priv->perspective.aspect,
|
|||
|
- priv->perspective.z_near,
|
|||
|
- priv->perspective.z_far);
|
|||
|
- cogl_matrix_get_inverse (&priv->projection,
|
|||
|
- &priv->inverse_projection);
|
|||
|
- cogl_matrix_init_identity (&priv->view);
|
|||
|
- cogl_matrix_view_2d_in_perspective (&priv->view,
|
|||
|
- priv->perspective.fovy,
|
|||
|
- priv->perspective.aspect,
|
|||
|
- priv->perspective.z_near,
|
|||
|
- 50, /* distance to 2d plane */
|
|||
|
- geom.width,
|
|||
|
- geom.height);
|
|||
|
-
|
|||
|
-
|
|||
|
/* FIXME - remove for 2.0 */
|
|||
|
priv->fog.z_near = 1.0;
|
|||
|
priv->fog.z_far = 2.0;
|
|||
|
@@ -2682,6 +2660,7 @@ clutter_stage_set_perspective (ClutterStage *stage,
|
|||
|
priv->has_custom_perspective = TRUE;
|
|||
|
|
|||
|
clutter_stage_set_perspective_internal (stage, perspective);
|
|||
|
+ clutter_stage_update_view_perspective (stage);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
@@ -2808,6 +2787,7 @@ _clutter_stage_set_viewport (ClutterStage *stage,
|
|||
|
priv->viewport[2] = width;
|
|||
|
priv->viewport[3] = height;
|
|||
|
|
|||
|
+ clutter_stage_update_view_perspective (stage);
|
|||
|
_clutter_stage_dirty_viewport (stage);
|
|||
|
|
|||
|
queue_full_redraw (stage);
|
|||
|
@@ -3788,6 +3768,50 @@ calculate_z_translation (float z_near)
|
|||
|
+ z_near;
|
|||
|
}
|
|||
|
|
|||
|
+static void
|
|||
|
+clutter_stage_update_view_perspective (ClutterStage *stage)
|
|||
|
+{
|
|||
|
+ ClutterStagePrivate *priv = stage->priv;
|
|||
|
+ ClutterPerspective perspective;
|
|||
|
+ float z_2d;
|
|||
|
+
|
|||
|
+ perspective = priv->perspective;
|
|||
|
+
|
|||
|
+ /* Ideally we want to regenerate the perspective matrix whenever
|
|||
|
+ * the size changes but if the user has provided a custom matrix
|
|||
|
+ * then we don't want to override it */
|
|||
|
+ if (!priv->has_custom_perspective)
|
|||
|
+ {
|
|||
|
+ perspective.fovy = 60.0; /* 60 Degrees */
|
|||
|
+ perspective.z_near = 0.1;
|
|||
|
+ perspective.aspect = priv->viewport[2] / priv->viewport[3];
|
|||
|
+ z_2d = calculate_z_translation (perspective.z_near);
|
|||
|
+
|
|||
|
+ /* NB: z_2d is only enough room for 85% of the stage_height between
|
|||
|
+ * the stage and the z_near plane. For behind the stage plane we
|
|||
|
+ * want a more consistent gap of 10 times the stage_height before
|
|||
|
+ * hitting the far plane so we calculate that relative to the final
|
|||
|
+ * height of the stage plane at the z_2d_distance we got... */
|
|||
|
+ perspective.z_far = z_2d +
|
|||
|
+ tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f;
|
|||
|
+
|
|||
|
+ clutter_stage_set_perspective_internal (stage, &perspective);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ {
|
|||
|
+ z_2d = calculate_z_translation (perspective.z_near);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ cogl_matrix_init_identity (&priv->view);
|
|||
|
+ cogl_matrix_view_2d_in_perspective (&priv->view,
|
|||
|
+ perspective.fovy,
|
|||
|
+ perspective.aspect,
|
|||
|
+ perspective.z_near,
|
|||
|
+ z_2d,
|
|||
|
+ priv->viewport[2],
|
|||
|
+ priv->viewport[3]);
|
|||
|
+}
|
|||
|
+
|
|||
|
void
|
|||
|
_clutter_stage_maybe_setup_viewport (ClutterStage *stage,
|
|||
|
ClutterStageView *view)
|
|||
|
@@ -3797,7 +3821,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
|
|||
|
if (clutter_stage_view_is_dirty_viewport (view))
|
|||
|
{
|
|||
|
cairo_rectangle_int_t view_layout;
|
|||
|
- ClutterPerspective perspective;
|
|||
|
float fb_scale;
|
|||
|
float viewport_offset_x;
|
|||
|
float viewport_offset_y;
|
|||
|
@@ -3805,7 +3828,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
|
|||
|
float viewport_y;
|
|||
|
float viewport_width;
|
|||
|
float viewport_height;
|
|||
|
- float z_2d;
|
|||
|
|
|||
|
CLUTTER_NOTE (PAINT,
|
|||
|
"Setting up the viewport { w:%f, h:%f }",
|
|||
|
@@ -3825,38 +3847,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
|
|||
|
clutter_stage_view_set_viewport (view,
|
|||
|
viewport_x, viewport_y,
|
|||
|
viewport_width, viewport_height);
|
|||
|
-
|
|||
|
- perspective = priv->perspective;
|
|||
|
-
|
|||
|
- /* Ideally we want to regenerate the perspective matrix whenever
|
|||
|
- * the size changes but if the user has provided a custom matrix
|
|||
|
- * then we don't want to override it */
|
|||
|
- if (!priv->has_custom_perspective)
|
|||
|
- {
|
|||
|
- perspective.aspect = priv->viewport[2] / priv->viewport[3];
|
|||
|
- z_2d = calculate_z_translation (perspective.z_near);
|
|||
|
-
|
|||
|
- /* NB: z_2d is only enough room for 85% of the stage_height between
|
|||
|
- * the stage and the z_near plane. For behind the stage plane we
|
|||
|
- * want a more consistent gap of 10 times the stage_height before
|
|||
|
- * hitting the far plane so we calculate that relative to the final
|
|||
|
- * height of the stage plane at the z_2d_distance we got... */
|
|||
|
- perspective.z_far = z_2d +
|
|||
|
- tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f;
|
|||
|
-
|
|||
|
- clutter_stage_set_perspective_internal (stage, &perspective);
|
|||
|
- }
|
|||
|
- else
|
|||
|
- z_2d = calculate_z_translation (perspective.z_near);
|
|||
|
-
|
|||
|
- cogl_matrix_init_identity (&priv->view);
|
|||
|
- cogl_matrix_view_2d_in_perspective (&priv->view,
|
|||
|
- perspective.fovy,
|
|||
|
- perspective.aspect,
|
|||
|
- perspective.z_near,
|
|||
|
- z_2d,
|
|||
|
- priv->viewport[2],
|
|||
|
- priv->viewport[3]);
|
|||
|
}
|
|||
|
|
|||
|
if (clutter_stage_view_is_dirty_projection (view))
|
|||
|
--
|
|||
|
2.29.2
|
|||
|
|