[mutter/wip/wayland-work: 20/22] wayland: implement HW cursors
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/wayland-work: 20/22] wayland: implement HW cursors
- Date: Mon, 9 Sep 2013 13:42:17 +0000 (UTC)
commit cae3884f19a62d64b40cec19baa283eabf44a0cc
Author: Giovanni Campagna <gcampagn redhat com>
Date: Thu Sep 5 16:45:41 2013 +0200
wayland: implement HW cursors
Use the DRM API and libgbm to upload cursor buffers to the
appropriate HW plane, saving on GL calls and compositing.
https://bugzilla.gnome.org/show_bug.cgi?id=707573
src/core/meta-cursor-tracker-private.h | 9 +-
src/core/meta-cursor-tracker.c | 615 +++++++++++++++++++++++++++++---
src/core/monitor-private.h | 3 +
src/core/monitor.c | 21 +-
src/wayland/meta-wayland-seat.c | 15 +-
5 files changed, 582 insertions(+), 81 deletions(-)
---
diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/meta-cursor-tracker-private.h
index 7b92c6a..e18d315 100644
--- a/src/core/meta-cursor-tracker-private.h
+++ b/src/core/meta-cursor-tracker-private.h
@@ -25,6 +25,7 @@
#define META_CURSOR_TRACKER_PRIVATE_H
#include <meta/meta-cursor-tracker.h>
+#include <wayland-server.h>
#include <clutter/clutter.h>
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
@@ -33,10 +34,10 @@ gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker);
-void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
- CoglTexture2D *texture,
- int hot_x,
- int hot_y);
+void meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
+ struct wl_resource *buffer,
+ int hot_x,
+ int hot_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c
index 8c3815e..41583f0 100644
--- a/src/core/meta-cursor-tracker.c
+++ b/src/core/meta-cursor-tracker.c
@@ -30,12 +30,15 @@
*/
#include <config.h>
+#include <string.h>
#include <meta/main.h>
#include <meta/util.h>
#include <meta/errors.h>
#include <cogl/cogl.h>
+#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
+#include <gbm.h>
#include <gdk/gdk.h>
@@ -43,35 +46,41 @@
#include "meta-cursor-tracker-private.h"
#include "screen-private.h"
-
-#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
-#endif
+#include "monitor-private.h"
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
+typedef struct {
+ CoglTexture2D *texture;
+ struct gbm_bo *bo;
+ int hot_x, hot_y;
+
+ int ref_count;
+} MetaCursorReference;
+
struct _MetaCursorTracker {
GObject parent_instance;
MetaScreen *screen;
gboolean is_showing;
+ gboolean has_cursor;
+ gboolean has_hw_cursor;
- CoglTexture2D *sprite;
- int hot_x, hot_y;
-
- CoglTexture2D *root_cursor;
- int root_hot_x, root_hot_y;
-
- CoglTexture2D *default_cursor;
+ MetaCursorReference *sprite;
+ MetaCursorReference *root_cursor;
+ MetaCursorReference *default_cursor;
int current_x, current_y;
- cairo_rectangle_int_t current_rect;
- cairo_rectangle_int_t previous_rect;
+ MetaRectangle current_rect;
+ MetaRectangle previous_rect;
gboolean previous_is_valid;
CoglPipeline *pipeline;
+ int drm_fd;
+ struct gbm_device *gbm;
};
struct _MetaCursorTrackerClass {
@@ -87,6 +96,321 @@ enum {
static guint signals[LAST_SIGNAL];
+static void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
+ MetaCursorReference *sprite);
+
+static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
+ MetaCRTC *crtc,
+ gboolean has_hw_cursor);
+
+static MetaCursorReference *
+meta_cursor_reference_ref (MetaCursorReference *self)
+{
+ g_assert (self->ref_count > 0);
+ self->ref_count++;
+
+ return self;
+}
+
+static void
+meta_cursor_reference_unref (MetaCursorReference *self)
+{
+ self->ref_count--;
+
+ if (self->ref_count == 0)
+ {
+ cogl_object_unref (self->texture);
+ if (self->bo)
+ gbm_bo_destroy (self->bo);
+
+ g_slice_free (MetaCursorReference, self);
+ }
+}
+
+static MetaCursorReference *
+meta_cursor_reference_load_file (MetaCursorTracker *tracker,
+ const char *filename,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ int width, height, rowstride;
+ int bits_per_sample;
+ int n_channels;
+ gboolean has_alpha;
+ CoglPixelFormat cogl_format;
+ uint32_t gbm_format;
+ ClutterBackend *clutter_backend;
+ CoglContext *cogl_context;
+ MetaCursorReference *self;
+
+ pixbuf = gdk_pixbuf_new_from_file (filename, error);
+ if (!pixbuf)
+ return NULL;
+
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
+ n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ g_assert (bits_per_sample == 8);
+ if (has_alpha)
+ {
+ g_assert (n_channels == 4);
+ cogl_format = COGL_PIXEL_FORMAT_RGBA_8888;
+ gbm_format = GBM_FORMAT_ARGB8888;
+ }
+ else
+ {
+ g_assert (n_channels == 3);
+ cogl_format = COGL_PIXEL_FORMAT_RGB_888;
+ gbm_format = GBM_FORMAT_XRGB8888;
+ }
+
+ self = g_slice_new0 (MetaCursorReference);
+ self->ref_count = 1;
+
+ clutter_backend = clutter_get_default_backend ();
+ cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+ self->texture = cogl_texture_2d_new_from_data (cogl_context,
+ width, height,
+ cogl_format,
+ COGL_PIXEL_FORMAT_ANY,
+ rowstride,
+ gdk_pixbuf_get_pixels (pixbuf),
+ NULL);
+
+ if (tracker->gbm)
+ {
+ if (width > 64 || height > 64)
+ {
+ meta_warning ("Invalid default cursor size (must be at most 64x64)\n");
+ goto out;
+ }
+
+ if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
+ GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
+ {
+ uint8_t *data;
+ uint8_t buf[4 * 64 * 64];
+ int i, j;
+
+ self->bo = gbm_bo_create (tracker->gbm, 64, 64,
+ gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
+
+ data = gdk_pixbuf_get_pixels (pixbuf);
+ memset (buf, 0, sizeof(buf));
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ /* The byte order is B G R (A) */
+ buf[i * 4 * 64 + j * 4 + 0] = data[i * rowstride + j * n_channels + 2];
+ buf[i * 4 * 64 + j * 4 + 1] = data[i * rowstride + j * n_channels + 1];
+ buf[i * 4 * 64 + j * 4 + 2] = data[i * rowstride + j * n_channels + 0];
+ if (has_alpha)
+ buf[i * 4 * 64 + j * 4 + 3] = data[i * rowstride + j * n_channels + 3];
+ else
+ buf[i * 4 * 64 + j * 4 + 3] = 0;
+#else
+ /* The byte order is (A) R G B */
+ buf[i * 4 * 64 + j * 4 + 3] = data[i * rowstride + j * n_channels + 2];
+ buf[i * 4 * 64 + j * 4 + 2] = data[i * rowstride + j * n_channels + 1];
+ buf[i * 4 * 64 + j * 4 + 1] = data[i * rowstride + j * n_channels + 0];
+ if (has_alpha)
+ buf[i * 4 * 64 + j * 4 + 0] = data[i * rowstride + j * n_channels + 3];
+ else
+ buf[i * 4 * 64 + j * 4 + 0] = 0;
+#endif
+ }
+ }
+
+ gbm_bo_write (self->bo, buf, 64 * 64 * 4);
+ }
+ else
+ meta_warning ("HW cursor for format %d not supported\n", gbm_format);
+ }
+
+ out:
+ g_object_unref (pixbuf);
+
+ return self;
+}
+
+static MetaCursorReference *
+meta_cursor_reference_take_texture (CoglTexture2D *texture)
+{
+ MetaCursorReference *self;
+
+ self = g_slice_new0 (MetaCursorReference);
+ self->ref_count = 1;
+
+ self->texture = texture;
+
+ return self;
+}
+
+static MetaCursorReference *
+meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
+ struct wl_resource *buffer,
+ int hot_x,
+ int hot_y)
+{
+ ClutterBackend *backend;
+ CoglContext *cogl_context;
+ MetaCursorReference *self;
+ CoglPixelFormat cogl_format, cogl_internal_format;
+ struct wl_shm_buffer *shm_buffer;
+ uint32_t gbm_format;
+
+ self = g_slice_new0 (MetaCursorReference);
+ self->ref_count = 1;
+
+ backend = clutter_get_default_backend ();
+ cogl_context = clutter_backend_get_cogl_context (backend);
+
+ shm_buffer = wl_shm_buffer_get (buffer);
+ if (shm_buffer)
+ {
+ int rowstride = wl_shm_buffer_get_stride (shm_buffer);
+ int width = wl_shm_buffer_get_width (shm_buffer);
+ int height = wl_shm_buffer_get_height (shm_buffer);
+
+ switch (wl_shm_buffer_get_format (shm_buffer))
+ {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ case WL_SHM_FORMAT_ARGB8888:
+ cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
+ cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
+ gbm_format = GBM_FORMAT_ARGB8888;
+ break;
+ case WL_SHM_FORMAT_XRGB32:
+ cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+ cogl_internal_format = COGL_PIXEL_FORMAT_RGB_888;
+ gbm_format = GBM_FORMAT_XRGB8888;
+ break;
+#else
+ case WL_SHM_FORMAT_ARGB8888:
+ cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
+ cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
+ gbm_format = GBM_FORMAT_ARGB8888;
+ break;
+ case WL_SHM_FORMAT_XRGB8888:
+ cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
+ cogl_internal_format = COGL_PIXEL_FORMAT_BGR_888;
+ gbm_format = GBM_FORMAT_XRGB8888;
+ break;
+#endif
+ default:
+ g_warn_if_reached ();
+ cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+ cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
+ gbm_format = GBM_FORMAT_ARGB8888;
+ }
+
+ self->texture = cogl_texture_2d_new_from_data (cogl_context,
+ width, height,
+ cogl_format,
+ cogl_internal_format,
+ rowstride,
+ wl_shm_buffer_get_data (shm_buffer),
+ NULL);
+
+ if (width > 64 || height > 64)
+ {
+ meta_warning ("Invalid cursor size (must be at most 64x64), falling back to GL cursors\n");
+ return self;
+ }
+
+ if (tracker->gbm)
+ {
+ if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
+ GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
+ {
+ uint8_t *data;
+ uint8_t buf[4 * 64 * 64];
+ int i;
+
+ self->bo = gbm_bo_create (tracker->gbm, 64, 64,
+ gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
+
+ data = wl_shm_buffer_get_data (shm_buffer);
+ memset (buf, 0, sizeof(buf));
+ for (i = 0; i < height; i++)
+ memcpy (buf + i * 4 * 64, data + i * rowstride, 4 * width);
+
+ gbm_bo_write (self->bo, buf, 64 * 64 * 4);
+ }
+ else
+ meta_warning ("HW cursor for format %d not supported\n", gbm_format);
+ }
+ }
+ else
+ {
+ int width, height;
+
+ self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
+ width = cogl_texture_get_width (COGL_TEXTURE (self->texture));
+ height = cogl_texture_get_height (COGL_TEXTURE (self->texture));
+
+ /* We can't complete EGL buffers, so they must be the right size from the start */
+ if (width != 64 || height != 64)
+ {
+ meta_warning ("Invalid cursor size (must be 64x64), falling back to GL cursors\n");
+ return self;
+ }
+
+ if (tracker->gbm)
+ {
+ cogl_format = cogl_texture_get_format (COGL_TEXTURE (self->texture));
+ switch (cogl_format)
+ {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
+ case COGL_PIXEL_FORMAT_ARGB_8888:
+ gbm_format = GBM_FORMAT_BGRA8888;
+ break;
+ case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
+ case COGL_PIXEL_FORMAT_BGRA_8888:
+ break;
+ case COGL_PIXEL_FORMAT_RGB_888:
+ break;
+#else
+ case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
+ case COGL_PIXEL_FORMAT_ARGB_8888:
+ gbm_format = GBM_FORMAT_ARGB8888;
+ break;
+ case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
+ case COGL_PIXEL_FORMAT_BGRA_8888:
+ gbm_format = GBM_FORMAT_BGRA8888;
+ break;
+ case COGL_PIXEL_FORMAT_RGB_888:
+ gbm_format = GBM_FORMAT_RGB888;
+ break;
+#endif
+ default:
+ meta_warning ("Unknown cogl format %d\n", cogl_format);
+ return self;
+ }
+
+ if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
+ GBM_BO_USE_CURSOR_64X64))
+ {
+ self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ buffer, GBM_BO_USE_CURSOR_64X64);
+ if (!self->bo)
+ meta_warning ("Importing HW cursor from wl_buffer failed\n");
+ }
+ else
+ meta_warning ("HW cursor for format %d not supported\n", gbm_format);
+ }
+ }
+
+ return self;
+}
+
static void
meta_cursor_tracker_init (MetaCursorTracker *self)
{
@@ -104,13 +428,15 @@ meta_cursor_tracker_finalize (GObject *object)
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
if (self->sprite)
- cogl_object_unref (self->sprite);
+ meta_cursor_reference_unref (self->sprite);
if (self->root_cursor)
- cogl_object_unref (self->root_cursor);
+ meta_cursor_reference_unref (self->root_cursor);
if (self->default_cursor)
- cogl_object_unref (self->default_cursor);
+ meta_cursor_reference_unref (self->default_cursor);
if (self->pipeline)
cogl_object_unref (self->pipeline);
+ if (self->gbm)
+ gbm_device_destroy (self->gbm);
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
}
@@ -130,13 +456,41 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
G_TYPE_NONE, 0);
}
-#ifdef HAVE_WAYLAND
+static void
+on_monitors_changed (MetaMonitorManager *monitors,
+ MetaCursorTracker *tracker)
+{
+ MetaCRTC *crtcs;
+ unsigned int i, n_crtcs;
+
+ if (!tracker->has_hw_cursor)
+ return;
+
+ /* Go through the new list of monitors, find out where the cursor is */
+ meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
+
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaRectangle *rect = &crtcs[i].rect;
+ gboolean has;
+
+ has = meta_rectangle_overlap (&tracker->current_rect, rect);
+
+ /* Need to do it unconditionally here, our tracking is
+ wrong because we reloaded the CRTCs */
+ meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
+ }
+}
+
static MetaCursorTracker *
make_wayland_cursor_tracker (MetaScreen *screen)
{
MetaWaylandCompositor *compositor;
CoglContext *ctx;
- MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
+ MetaMonitorManager *monitors;
+ MetaCursorTracker *self;
+
+ self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
self->screen = screen;
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
@@ -145,9 +499,16 @@ make_wayland_cursor_tracker (MetaScreen *screen)
compositor = meta_wayland_compositor_get_default ();
compositor->seat->cursor_tracker = self;
+ self->drm_fd = compositor->drm_fd;
+ if (self->drm_fd >= 0)
+ self->gbm = gbm_create_device (compositor->drm_fd);
+
+ monitors = meta_monitor_manager_get ();
+ g_signal_connect_object (monitors, "monitors-changed",
+ G_CALLBACK (on_monitors_changed), self, 0);
+
return self;
}
-#endif
static MetaCursorTracker *
make_x11_cursor_tracker (MetaScreen *screen)
@@ -205,7 +566,7 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
if (notify_event->subtype != XFixesDisplayCursorNotify)
return FALSE;
- g_clear_pointer (&tracker->sprite, cogl_object_unref);
+ g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
return TRUE;
@@ -268,9 +629,9 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
if (sprite != NULL)
{
- tracker->sprite = sprite;
- tracker->hot_x = cursor_image->xhot;
- tracker->hot_y = cursor_image->yhot;
+ tracker->sprite = meta_cursor_reference_take_texture (sprite);
+ tracker->sprite->hot_x = cursor_image->xhot;
+ tracker->sprite->hot_y = cursor_image->yhot;
}
XFree (cursor_image);
}
@@ -288,7 +649,10 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
- return COGL_TEXTURE (tracker->sprite);
+ if (tracker->sprite)
+ return COGL_TEXTURE (tracker->sprite->texture);
+ else
+ return NULL;
}
/**
@@ -308,17 +672,27 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
- if (x)
- *x = tracker->hot_x;
- if (y)
- *y = tracker->hot_y;
+ if (tracker->sprite)
+ {
+ if (x)
+ *x = tracker->sprite->hot_x;
+ if (y)
+ *y = tracker->sprite->hot_y;
+ }
+ else
+ {
+ if (x)
+ *x = 0;
+ if (y)
+ *y = 0;
+ }
}
static void
ensure_wayland_cursor (MetaCursorTracker *tracker)
{
- CoglBitmap *bitmap;
char *filename;
+ GError *error;
if (tracker->default_cursor)
return;
@@ -327,12 +701,19 @@ ensure_wayland_cursor (MetaCursorTracker *tracker)
"cursors/left_ptr.png",
NULL);
- bitmap = cogl_bitmap_new_from_file (filename, NULL);
- tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap,
- COGL_PIXEL_FORMAT_ANY,
- NULL);
+ error = NULL;
+ tracker->default_cursor = meta_cursor_reference_load_file (tracker, filename, &error);
+ if (!tracker->default_cursor)
+ {
+ if (error)
+ g_error ("Failed to load default cursor: %s", error->message);
+ else
+ g_error ("Failed to load default cursor");
+ }
+
+ tracker->default_cursor->hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
+ tracker->default_cursor->hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
- cogl_object_unref (bitmap);
g_free (filename);
}
@@ -356,42 +737,111 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
/* FIXME! We need to load all the other cursors too */
ensure_wayland_cursor (tracker);
- g_clear_pointer (&tracker->root_cursor, cogl_object_unref);
- tracker->root_cursor = cogl_object_ref (tracker->default_cursor);
- tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
- tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
+ g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
+ tracker->root_cursor = meta_cursor_reference_ref (tracker->default_cursor);
}
}
void
meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
{
- meta_cursor_tracker_set_sprite (tracker,
- tracker->root_cursor,
- tracker->root_hot_x,
- tracker->root_hot_y);
+ meta_cursor_tracker_set_sprite (tracker, tracker->root_cursor);
+}
+
+static void
+update_hw_cursor (MetaCursorTracker *tracker)
+{
+ MetaMonitorManager *monitors;
+ MetaCRTC *crtcs;
+ unsigned int i, n_crtcs;
+ gboolean enabled;
+
+ enabled = tracker->has_cursor && tracker->sprite->bo != NULL;
+ tracker->has_hw_cursor = enabled;
+
+ monitors = meta_monitor_manager_get ();
+ meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
+
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaRectangle *rect = &crtcs[i].rect;
+ gboolean has;
+
+ has = enabled && meta_rectangle_overlap (&tracker->current_rect, rect);
+
+ if (has || crtcs[i].has_hw_cursor)
+ meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
+ }
+}
+
+static void
+move_hw_cursor (MetaCursorTracker *tracker)
+{
+ MetaMonitorManager *monitors;
+ MetaCRTC *crtcs;
+ unsigned int i, n_crtcs;
+
+ monitors = meta_monitor_manager_get ();
+ meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
+
+ g_assert (tracker->has_hw_cursor);
+
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaRectangle *rect = &crtcs[i].rect;
+ gboolean has;
+
+ has = meta_rectangle_overlap (&tracker->current_rect, rect);
+
+ if (has != crtcs[i].has_hw_cursor)
+ meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
+ if (has)
+ drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id,
+ tracker->current_rect.x - rect->x,
+ tracker->current_rect.y - rect->y);
+ }
}
void
-meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
- CoglTexture2D *sprite,
- int hot_x,
- int hot_y)
+meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
+ struct wl_resource *buffer,
+ int hot_x,
+ int hot_y)
+{
+ MetaCursorReference *new_cursor;
+
+ if (buffer)
+ {
+ new_cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y);
+ meta_cursor_tracker_set_sprite (tracker, new_cursor);
+ meta_cursor_reference_unref (new_cursor);
+ }
+ else
+ meta_cursor_tracker_set_sprite (tracker, NULL);
+}
+
+static void
+meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
+ MetaCursorReference *sprite)
{
g_assert (meta_is_wayland_compositor ());
- g_clear_pointer (&tracker->sprite, cogl_object_unref);
+ if (sprite == tracker->sprite)
+ return;
+
+ g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
if (sprite)
{
- tracker->sprite = cogl_object_ref (sprite);
- tracker->hot_x = hot_x;
- tracker->hot_y = hot_y;
- cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite));
+ tracker->sprite = meta_cursor_reference_ref (sprite);
+ cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite->texture));
}
else
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
+ tracker->has_cursor = tracker->sprite != NULL && tracker->is_showing;
+ update_hw_cursor (tracker);
+
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
@@ -406,19 +856,24 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
tracker->current_x = new_x;
tracker->current_y = new_y;
- tracker->current_rect.x = tracker->current_x - tracker->hot_x;
- tracker->current_rect.y = tracker->current_y - tracker->hot_y;
if (tracker->sprite)
{
- tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite));
- tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite));
+ tracker->current_rect.x = tracker->current_x - tracker->sprite->hot_x;
+ tracker->current_rect.y = tracker->current_y - tracker->sprite->hot_y;
+ tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite->texture));
+ tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite->texture));
}
else
{
+ tracker->current_rect.x = 0;
+ tracker->current_rect.y = 0;
tracker->current_rect.width = 0;
tracker->current_rect.height = 0;
}
+
+ if (tracker->has_hw_cursor)
+ move_hw_cursor (tracker);
}
void
@@ -426,10 +881,9 @@ meta_cursor_tracker_paint (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
- if (tracker->sprite == NULL || tracker->is_showing == FALSE)
+ if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
- /* FIXME: try to use a DRM cursor when possible */
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
tracker->pipeline,
tracker->current_rect.x,
@@ -447,18 +901,58 @@ void
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
ClutterActor *stage)
{
+ cairo_rectangle_int_t clip;
+
g_assert (meta_is_wayland_compositor ());
if (tracker->previous_is_valid)
{
- clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect);
+ cairo_rectangle_int_t clip = {
+ .x = tracker->previous_rect.x,
+ .y = tracker->previous_rect.y,
+ .width = tracker->previous_rect.width,
+ .height = tracker->previous_rect.height
+ };
+ clutter_actor_queue_redraw_with_clip (stage, &clip);
tracker->previous_is_valid = FALSE;
}
- if (tracker->sprite == NULL)
+ if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
- clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect);
+ clip.x = tracker->current_rect.x;
+ clip.y = tracker->current_rect.y;
+ clip.width = tracker->current_rect.width;
+ clip.height = tracker->current_rect.height;
+ clutter_actor_queue_redraw_with_clip (stage, &clip);
+}
+
+static void
+meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
+ MetaCRTC *crtc,
+ gboolean has)
+{
+ if (has)
+ {
+ union gbm_bo_handle handle;
+ int width, height;
+ int hot_x, hot_y;
+
+ handle = gbm_bo_get_handle (tracker->sprite->bo);
+ width = gbm_bo_get_width (tracker->sprite->bo);
+ height = gbm_bo_get_height (tracker->sprite->bo);
+ hot_x = tracker->sprite->hot_x;
+ hot_y = tracker->sprite->hot_y;
+
+ drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32,
+ width, height, hot_x, hot_y);
+ crtc->has_hw_cursor = TRUE;
+ }
+ else
+ {
+ drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
+ crtc->has_hw_cursor = FALSE;
+ }
}
static void
@@ -527,6 +1021,9 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
+
+ tracker->has_cursor = tracker->sprite != NULL && visible;
+ update_hw_cursor (tracker);
meta_cursor_tracker_queue_redraw (tracker, compositor->stage);
}
else
diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h
index 2b1cea1..a8eeb67 100644
--- a/src/core/monitor-private.h
+++ b/src/core/monitor-private.h
@@ -136,6 +136,9 @@ struct _MetaCRTC
/* Used when changing configuration */
gboolean is_dirty;
+
+ /* Updated by MetaCursorTracker */
+ gboolean has_hw_cursor;
};
struct _MetaMonitorMode
diff --git a/src/core/monitor.c b/src/core/monitor.c
index 68ae9bf..1f522a3 100644
--- a/src/core/monitor.c
+++ b/src/core/monitor.c
@@ -1361,12 +1361,21 @@ meta_monitor_manager_get_resources (MetaMonitorManager *manager,
MetaOutput **outputs,
unsigned int *n_outputs)
{
- *modes = manager->modes;
- *n_modes = manager->n_modes;
- *crtcs = manager->crtcs;
- *n_crtcs = manager->n_crtcs;
- *outputs = manager->outputs;
- *n_outputs = manager->n_outputs;
+ if (modes)
+ {
+ *modes = manager->modes;
+ *n_modes = manager->n_modes;
+ }
+ if (crtcs)
+ {
+ *crtcs = manager->crtcs;
+ *n_crtcs = manager->n_crtcs;
+ }
+ if (outputs)
+ {
+ *outputs = manager->outputs;
+ *n_outputs = manager->n_outputs;
+ }
}
int
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
index 2442c78..cf898cc 100644
--- a/src/wayland/meta-wayland-seat.c
+++ b/src/wayland/meta-wayland-seat.c
@@ -77,7 +77,7 @@ pointer_unmap_sprite (MetaWaylandSeat *seat)
{
if (seat->cursor_tracker)
{
- meta_cursor_tracker_set_sprite (seat->cursor_tracker,
+ meta_cursor_tracker_set_buffer (seat->cursor_tracker,
NULL, 0, 0);
if (seat->current_stage)
@@ -95,29 +95,20 @@ pointer_unmap_sprite (MetaWaylandSeat *seat)
void
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
{
- ClutterBackend *backend;
- CoglContext *context;
struct wl_resource *buffer;
- CoglTexture2D *texture;
if (seat->cursor_tracker == NULL)
return;
- backend = clutter_get_default_backend ();
- context = clutter_backend_get_cogl_context (backend);
buffer = seat->sprite->buffer_ref.buffer->resource;
- texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
-
- meta_cursor_tracker_set_sprite (seat->cursor_tracker,
- texture,
+ meta_cursor_tracker_set_buffer (seat->cursor_tracker,
+ buffer,
seat->hotspot_x,
seat->hotspot_y);
if (seat->current_stage)
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
CLUTTER_ACTOR (seat->current_stage));
-
- cogl_object_unref (texture);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]