backends: Allow multiple "SW" cursor overlays on the stage

All the upper layers are prepared for multiple onscreen cursors, but
this. All MetaCursorRenderers created would poke the same internal
MetaOverlay in the stage.

This will lead to multiple cursor renderers resorting to the "SW"
rendering paths (as it can be seen with tablet support) to reuse the
same overlay, thus leading to flickering when a different
MetaCursorRenderer takes over the overlay.

Fix this by allowing per-cursor-renderer overlays, their lifetime
is attached to the cursor renderer, so is expected to be tear down
if the relevant device (eg. tablet) disappears.
This commit is contained in:
Carlos Garnacho 2016-05-02 13:49:13 +02:00
parent 2cec7ac596
commit 362ab781dd
3 changed files with 86 additions and 21 deletions

View File

@ -40,6 +40,7 @@ struct _MetaCursorRendererPrivate
int current_x, current_y; int current_x, current_y;
MetaCursorSprite *displayed_cursor; MetaCursorSprite *displayed_cursor;
MetaOverlay *stage_overlay;
gboolean handled_by_backend; gboolean handled_by_backend;
}; };
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate; typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@ -63,12 +64,16 @@ queue_redraw (MetaCursorRenderer *renderer,
if (!stage) if (!stage)
return; return;
if (!priv->stage_overlay)
priv->stage_overlay = meta_stage_create_cursor_overlay (META_STAGE (stage));
if (cursor_sprite && !priv->handled_by_backend) if (cursor_sprite && !priv->handled_by_backend)
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
else else
texture = NULL; texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &rect); meta_stage_update_cursor_overlay (META_STAGE (stage), priv->stage_overlay,
texture, &rect);
} }
static gboolean static gboolean
@ -81,9 +86,26 @@ meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer,
return FALSE; return FALSE;
} }
static void
meta_cursor_renderer_finalize (GObject *object)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (object);
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
if (priv->stage_overlay)
meta_stage_remove_cursor_overlay (META_STAGE (stage), priv->stage_overlay);
G_OBJECT_CLASS (meta_cursor_renderer_parent_class)->finalize (object);
}
static void static void
meta_cursor_renderer_class_init (MetaCursorRendererClass *klass) meta_cursor_renderer_class_init (MetaCursorRendererClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_cursor_renderer_finalize;
klass->update_cursor = meta_cursor_renderer_real_update_cursor; klass->update_cursor = meta_cursor_renderer_real_update_cursor;
} }

View File

@ -27,7 +27,7 @@
#include <meta/meta-backend.h> #include <meta/meta-backend.h>
#include <meta/util.h> #include <meta/util.h>
typedef struct { struct _MetaOverlay {
gboolean enabled; gboolean enabled;
CoglPipeline *pipeline; CoglPipeline *pipeline;
@ -36,22 +36,26 @@ typedef struct {
MetaRectangle current_rect; MetaRectangle current_rect;
MetaRectangle previous_rect; MetaRectangle previous_rect;
gboolean previous_is_valid; gboolean previous_is_valid;
} MetaOverlay; };
struct _MetaStagePrivate { struct _MetaStagePrivate {
MetaOverlay cursor_overlay; GList *overlays;
gboolean is_active; gboolean is_active;
}; };
typedef struct _MetaStagePrivate MetaStagePrivate; typedef struct _MetaStagePrivate MetaStagePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaStage, meta_stage, CLUTTER_TYPE_STAGE); G_DEFINE_TYPE_WITH_PRIVATE (MetaStage, meta_stage, CLUTTER_TYPE_STAGE);
static void static MetaOverlay *
meta_overlay_init (MetaOverlay *overlay) meta_overlay_new ()
{ {
MetaOverlay *overlay;
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
overlay = g_slice_new0 (MetaOverlay);
overlay->pipeline = cogl_pipeline_new (ctx); overlay->pipeline = cogl_pipeline_new (ctx);
return overlay;
} }
static void static void
@ -59,6 +63,8 @@ meta_overlay_free (MetaOverlay *overlay)
{ {
if (overlay->pipeline) if (overlay->pipeline)
cogl_object_unref (overlay->pipeline); cogl_object_unref (overlay->pipeline);
g_slice_free (MetaOverlay, overlay);
} }
static void static void
@ -111,8 +117,15 @@ meta_stage_finalize (GObject *object)
{ {
MetaStage *stage = META_STAGE (object); MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage); MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *l = priv->overlays;
meta_overlay_free (&priv->cursor_overlay); while (l)
{
meta_overlay_free (l->data);
l = g_list_delete_link (l, l);
}
G_OBJECT_CLASS (meta_stage_parent_class)->finalize (object);
} }
static void static void
@ -120,10 +133,12 @@ meta_stage_paint (ClutterActor *actor)
{ {
MetaStage *stage = META_STAGE (actor); MetaStage *stage = META_STAGE (actor);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage); MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor); CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
meta_overlay_paint (&priv->cursor_overlay); for (l = priv->overlays; l; l = l->next)
meta_overlay_paint (l->data);
} }
static void static void
@ -166,10 +181,6 @@ meta_stage_class_init (MetaStageClass *klass)
static void static void
meta_stage_init (MetaStage *stage) meta_stage_init (MetaStage *stage)
{ {
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_init (&priv->cursor_overlay);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
} }
@ -209,17 +220,43 @@ queue_redraw_for_overlay (MetaStage *stage,
} }
} }
void MetaOverlay *
meta_stage_set_cursor (MetaStage *stage, meta_stage_create_cursor_overlay (MetaStage *stage)
CoglTexture *texture,
MetaRectangle *rect)
{ {
MetaStagePrivate *priv = meta_stage_get_instance_private (stage); MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaOverlay *overlay;
overlay = meta_overlay_new ();
priv->overlays = g_list_prepend (priv->overlays, overlay);
return overlay;
}
void
meta_stage_remove_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *link;
link = g_list_find (priv->overlays, overlay);
if (!link)
return;
priv->overlays = g_list_delete_link (priv->overlays, link);
meta_overlay_free (overlay);
}
void
meta_stage_update_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay,
CoglTexture *texture,
MetaRectangle *rect)
{
g_assert (meta_is_wayland_compositor () || texture == NULL); g_assert (meta_is_wayland_compositor () || texture == NULL);
meta_overlay_set (&priv->cursor_overlay, texture, rect); meta_overlay_set (overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->cursor_overlay); queue_redraw_for_overlay (stage, overlay);
} }
void void

View File

@ -36,6 +36,7 @@ G_BEGIN_DECLS
typedef struct _MetaStage MetaStage; typedef struct _MetaStage MetaStage;
typedef struct _MetaStageClass MetaStageClass; typedef struct _MetaStageClass MetaStageClass;
typedef struct _MetaOverlay MetaOverlay;
struct _MetaStageClass struct _MetaStageClass
{ {
@ -51,9 +52,14 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void); ClutterActor *meta_stage_new (void);
void meta_stage_set_cursor (MetaStage *stage, MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage);
CoglTexture *texture, void meta_stage_remove_cursor_overlay (MetaStage *stage,
MetaRectangle *rect); MetaOverlay *overlay);
void meta_stage_update_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_set_active (MetaStage *stage, void meta_stage_set_active (MetaStage *stage,
gboolean is_active); gboolean is_active);