cursor-renderer-native: Support HW cursors on multiple GPUs

On hybrid GPU systems, hardware cursors needs to be realized on all the
GPUs, as scanout cursor planes cannot be shared. Do this by moving gbm
buffer and drm buffer ID management to a per GPU struct, realizing a
cursor on each GPU when previously only realized on the primary GPU.

https://bugzilla.gnome.org/show_bug.cgi?id=785381
This commit is contained in:
Jonas Ådahl 2017-07-25 10:31:25 +08:00
parent c9259c2b15
commit 78e6258b44

View File

@ -76,18 +76,19 @@ struct _MetaCursorRendererNativePrivate
gboolean hw_state_invalidated; gboolean hw_state_invalidated;
gboolean has_hw_cursor; gboolean has_hw_cursor;
gboolean hw_cursor_broken;
MetaCursorSprite *last_cursor; MetaCursorSprite *last_cursor;
guint animation_timeout_id; guint animation_timeout_id;
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
int drm_fd; typedef struct _MetaCursorRendererNativeGpuData
struct gbm_device *gbm; {
gboolean hw_cursor_broken;
uint64_t cursor_width; uint64_t cursor_width;
uint64_t cursor_height; uint64_t cursor_height;
}; } MetaCursorRendererNativeGpuData;
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
typedef enum _MetaCursorGbmBoState typedef enum _MetaCursorGbmBoState
{ {
@ -96,18 +97,57 @@ typedef enum _MetaCursorGbmBoState
META_CURSOR_GBM_BO_STATE_INVALIDATED, META_CURSOR_GBM_BO_STATE_INVALIDATED,
} MetaCursorGbmBoState; } MetaCursorGbmBoState;
typedef struct _MetaCursorNativePrivate typedef struct _MetaCursorNativeGpuState
{ {
guint active_bo; guint active_bo;
MetaCursorGbmBoState pending_bo_state; MetaCursorGbmBoState pending_bo_state;
struct gbm_bo *bos[HW_CURSOR_BUFFER_COUNT]; struct gbm_bo *bos[HW_CURSOR_BUFFER_COUNT];
} MetaCursorNativeGpuState;
typedef struct _MetaCursorNativePrivate
{
GHashTable *gpu_states;
} MetaCursorNativePrivate; } MetaCursorNativePrivate;
static GQuark quark_cursor_renderer_native_gpu_data = 0;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER); G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
static MetaCursorNativeGpuState *
get_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
MetaGpuKms *gpu_kms);
static MetaCursorNativeGpuState *
ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
MetaGpuKms *gpu_kms);
static MetaCursorNativePrivate * static MetaCursorNativePrivate *
ensure_cursor_priv (MetaCursorSprite *cursor_sprite); ensure_cursor_priv (MetaCursorSprite *cursor_sprite);
static MetaCursorNativePrivate *
get_cursor_priv (MetaCursorSprite *cursor_sprite);
static MetaCursorRendererNativeGpuData *
meta_cursor_renderer_native_gpu_data_from_gpu (MetaGpuKms *gpu_kms)
{
return g_object_get_qdata (G_OBJECT (gpu_kms),
quark_cursor_renderer_native_gpu_data);
}
static MetaCursorRendererNativeGpuData *
meta_create_cursor_renderer_native_gpu_data (MetaGpuKms *gpu_kms)
{
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
cursor_renderer_gpu_data = g_new0 (MetaCursorRendererNativeGpuData, 1);
g_object_set_qdata_full (G_OBJECT (gpu_kms),
quark_cursor_renderer_native_gpu_data,
cursor_renderer_gpu_data,
g_free);
return cursor_renderer_gpu_data;
}
static void static void
meta_cursor_renderer_native_finalize (GObject *object) meta_cursor_renderer_native_finalize (GObject *object)
{ {
@ -121,52 +161,41 @@ meta_cursor_renderer_native_finalize (GObject *object)
} }
static guint static guint
get_pending_cursor_sprite_gbm_bo_index (MetaCursorSprite *cursor_sprite) get_pending_cursor_sprite_gbm_bo_index (MetaCursorNativeGpuState *cursor_gpu_state)
{ {
MetaCursorNativePrivate *cursor_priv = return (cursor_gpu_state->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
return (cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
} }
static struct gbm_bo * static struct gbm_bo *
get_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite) get_pending_cursor_sprite_gbm_bo (MetaCursorNativeGpuState *cursor_gpu_state)
{ {
MetaCursorNativePrivate *cursor_priv =
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
guint pending_bo; guint pending_bo;
if (!cursor_priv) pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
return NULL; return cursor_gpu_state->bos[pending_bo];
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
return cursor_priv->bos[pending_bo];
} }
static struct gbm_bo * static struct gbm_bo *
get_active_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite) get_active_cursor_sprite_gbm_bo (MetaCursorNativeGpuState *cursor_gpu_state)
{ {
MetaCursorNativePrivate *cursor_priv = return cursor_gpu_state->bos[cursor_gpu_state->active_bo];
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
if (!cursor_priv)
return NULL;
return cursor_priv->bos[cursor_priv->active_bo];
} }
static void static void
set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite, set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
MetaGpuKms *gpu_kms,
struct gbm_bo *bo) struct gbm_bo *bo)
{ {
MetaCursorNativePrivate *cursor_priv; MetaCursorNativePrivate *cursor_priv;
MetaCursorNativeGpuState *cursor_gpu_state;
guint pending_bo; guint pending_bo;
cursor_priv = ensure_cursor_priv (cursor_sprite); cursor_priv = ensure_cursor_priv (cursor_sprite);
cursor_gpu_state = ensure_cursor_gpu_state (cursor_priv, gpu_kms);
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite); pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
cursor_priv->bos[pending_bo] = bo; cursor_gpu_state->bos[pending_bo] = bo;
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_SET; cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_SET;
} }
static void static void
@ -175,19 +204,30 @@ set_crtc_cursor (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite) MetaCursorSprite *cursor_sprite)
{ {
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native); MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
MetaGpuKms *gpu_kms;
int kms_fd;
gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (cursor_sprite) if (cursor_sprite)
{ {
MetaCursorNativePrivate *cursor_priv = MetaCursorNativePrivate *cursor_priv;
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite); MetaCursorNativeGpuState *cursor_gpu_state;
struct gbm_bo *bo; struct gbm_bo *bo;
union gbm_bo_handle handle; union gbm_bo_handle handle;
int hot_x, hot_y; int hot_x, hot_y;
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET) cursor_priv = get_cursor_priv (cursor_sprite);
bo = get_pending_cursor_sprite_gbm_bo (cursor_sprite); cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
if (cursor_gpu_state->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
bo = get_pending_cursor_sprite_gbm_bo (cursor_gpu_state);
else else
bo = get_active_cursor_sprite_gbm_bo (cursor_sprite); bo = get_active_cursor_sprite_gbm_bo (cursor_gpu_state);
if (!priv->hw_state_invalidated && bo == crtc->cursor_renderer_private) if (!priv->hw_state_invalidated && bo == crtc->cursor_renderer_private)
return; return;
@ -197,8 +237,9 @@ set_crtc_cursor (MetaCursorRendererNative *native,
handle = gbm_bo_get_handle (bo); handle = gbm_bo_get_handle (bo);
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y); meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
if (drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32, if (drmModeSetCursor2 (kms_fd, crtc->crtc_id, handle.u32,
priv->cursor_width, priv->cursor_height, cursor_renderer_gpu_data->cursor_width,
cursor_renderer_gpu_data->cursor_height,
hot_x, hot_y) < 0) hot_x, hot_y) < 0)
{ {
if (errno != EACCES) if (errno != EACCES)
@ -207,22 +248,22 @@ set_crtc_cursor (MetaCursorRendererNative *native,
"drawing cursor with OpenGL from now on", "drawing cursor with OpenGL from now on",
strerror (errno)); strerror (errno));
priv->has_hw_cursor = FALSE; priv->has_hw_cursor = FALSE;
priv->hw_cursor_broken = TRUE; cursor_renderer_gpu_data->hw_cursor_broken = TRUE;
} }
} }
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET) if (cursor_gpu_state->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
{ {
cursor_priv->active_bo = cursor_gpu_state->active_bo =
(cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT; (cursor_gpu_state->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_NONE; cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_NONE;
} }
} }
else else
{ {
if (priv->hw_state_invalidated || crtc->cursor_renderer_private != NULL) if (priv->hw_state_invalidated || crtc->cursor_renderer_private != NULL)
{ {
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0); drmModeSetCursor2 (kms_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
crtc->cursor_renderer_private = NULL; crtc->cursor_renderer_private = NULL;
} }
} }
@ -280,17 +321,21 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
&data->in_local_cursor_rect, &data->in_local_cursor_rect,
NULL)) NULL))
{ {
MetaGpuKms *gpu_kms;
int kms_fd;
float crtc_cursor_x, crtc_cursor_y; float crtc_cursor_x, crtc_cursor_y;
set_crtc_cursor (data->in_cursor_renderer_native, set_crtc_cursor (data->in_cursor_renderer_native,
monitor_crtc_mode->output->crtc, monitor_crtc_mode->output->crtc,
data->in_cursor_sprite); data->in_cursor_sprite);
gpu_kms = META_GPU_KMS (meta_monitor_get_gpu (monitor));
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
crtc_cursor_x = (data->in_local_cursor_rect.origin.x - crtc_cursor_x = (data->in_local_cursor_rect.origin.x -
scaled_crtc_rect.origin.x) * scale; scaled_crtc_rect.origin.x) * scale;
crtc_cursor_y = (data->in_local_cursor_rect.origin.y - crtc_cursor_y = (data->in_local_cursor_rect.origin.y -
scaled_crtc_rect.origin.y) * scale; scaled_crtc_rect.origin.y) * scale;
drmModeMoveCursor (priv->drm_fd, drmModeMoveCursor (kms_fd,
monitor_crtc_mode->output->crtc->crtc_id, monitor_crtc_mode->output->crtc->crtc_id,
roundf (crtc_cursor_x), roundf (crtc_cursor_x),
roundf (crtc_cursor_y)); roundf (crtc_cursor_y));
@ -368,18 +413,24 @@ update_hw_cursor (MetaCursorRendererNative *native,
} }
static gboolean static gboolean
has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite) has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
MetaGpuKms *gpu_kms)
{ {
MetaCursorNativePrivate *cursor_priv = MetaCursorNativePrivate *cursor_priv;
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite); MetaCursorNativeGpuState *cursor_gpu_state;
cursor_priv = get_cursor_priv (cursor_sprite);
if (!cursor_priv) if (!cursor_priv)
return FALSE; return FALSE;
switch (cursor_priv->pending_bo_state) cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
if (!cursor_gpu_state)
return FALSE;
switch (cursor_gpu_state->pending_bo_state)
{ {
case META_CURSOR_GBM_BO_STATE_NONE: case META_CURSOR_GBM_BO_STATE_NONE:
return get_active_cursor_sprite_gbm_bo (cursor_sprite) != NULL; return get_active_cursor_sprite_gbm_bo (cursor_gpu_state) != NULL;
case META_CURSOR_GBM_BO_STATE_SET: case META_CURSOR_GBM_BO_STATE_SET:
return TRUE; return TRUE;
case META_CURSOR_GBM_BO_STATE_INVALIDATED: case META_CURSOR_GBM_BO_STATE_INVALIDATED:
@ -405,6 +456,7 @@ cursor_over_transformed_logical_monitor (MetaCursorRenderer *renderer,
ClutterRect cursor_rect; ClutterRect cursor_rect;
cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite); cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
logical_monitors = logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager); meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next) for (l = logical_monitors; l; l = l->next)
@ -492,17 +544,29 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer); MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native); MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
GList *gpus; GList *gpus;
GList *l;
CoglTexture *texture; CoglTexture *texture;
if (priv->hw_cursor_broken)
return FALSE;
if (!cursor_sprite) if (!cursor_sprite)
return FALSE; return FALSE;
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager); gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
if (g_list_length (gpus) != 1) for (l = gpus; l; l = l->next)
return FALSE; {
MetaGpuKms *gpu_kms = l->data;
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
if (!cursor_renderer_gpu_data)
return FALSE;
if (cursor_renderer_gpu_data->hw_cursor_broken)
return FALSE;
if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms))
return FALSE;
}
if (cursor_over_transformed_logical_monitor (renderer, cursor_sprite)) if (cursor_over_transformed_logical_monitor (renderer, cursor_sprite))
return FALSE; return FALSE;
@ -514,9 +578,6 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
if (!can_draw_cursor_unscaled (renderer, cursor_sprite)) if (!can_draw_cursor_unscaled (renderer, cursor_sprite))
return FALSE; return FALSE;
if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite))
return FALSE;
return TRUE; return TRUE;
} }
@ -588,62 +649,94 @@ meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
} }
static void static void
get_hardware_cursor_size (MetaCursorRendererNative *native, cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state)
uint64_t *width, uint64_t *height)
{ {
MetaCursorRendererNativePrivate *priv = int i;
meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width; for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++)
*height = priv->cursor_height; g_clear_pointer (&cursor_gpu_state->bos[i], (GDestroyNotify) gbm_bo_destroy);
g_free (cursor_gpu_state);
}
static MetaCursorNativeGpuState *
get_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
MetaGpuKms *gpu_kms)
{
return g_hash_table_lookup (cursor_priv->gpu_states, gpu_kms);
}
static MetaCursorNativeGpuState *
ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
MetaGpuKms *gpu_kms)
{
MetaCursorNativeGpuState *cursor_gpu_state;
cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
if (cursor_gpu_state)
return cursor_gpu_state;
cursor_gpu_state = g_new0 (MetaCursorNativeGpuState, 1);
g_hash_table_insert (cursor_priv->gpu_states, gpu_kms, cursor_gpu_state);
return cursor_gpu_state;
} }
static void static void
cursor_priv_free (gpointer data) cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
{ {
MetaCursorNativePrivate *cursor_priv = data; g_hash_table_destroy (cursor_priv->gpu_states);
guint i; }
if (!data) static MetaCursorNativePrivate *
return; get_cursor_priv (MetaCursorSprite *cursor_sprite)
{
for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++) return g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
g_clear_pointer (&cursor_priv->bos[i], (GDestroyNotify) gbm_bo_destroy);
g_slice_free (MetaCursorNativePrivate, cursor_priv);
} }
static MetaCursorNativePrivate * static MetaCursorNativePrivate *
ensure_cursor_priv (MetaCursorSprite *cursor_sprite) ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
{ {
MetaCursorNativePrivate *cursor_priv = MetaCursorNativePrivate *cursor_priv;
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
if (!cursor_priv) cursor_priv = get_cursor_priv (cursor_sprite);
{ if (cursor_priv)
cursor_priv = g_slice_new0 (MetaCursorNativePrivate); return cursor_priv;
g_object_set_qdata_full (G_OBJECT (cursor_sprite),
quark_cursor_sprite, cursor_priv = g_new0 (MetaCursorNativePrivate, 1);
cursor_priv, cursor_priv->gpu_states =
cursor_priv_free); g_hash_table_new_full (g_direct_hash,
} g_direct_equal,
NULL,
(GDestroyNotify) cursor_gpu_state_free);
g_object_set_qdata_full (G_OBJECT (cursor_sprite),
quark_cursor_sprite,
cursor_priv,
(GDestroyNotify) cursor_priv_free);
return cursor_priv; return cursor_priv;
} }
static void static void
load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native, load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite, MetaGpuKms *gpu_kms,
uint8_t *pixels, MetaCursorSprite *cursor_sprite,
uint width, uint8_t *pixels,
uint height, uint width,
int rowstride, uint height,
uint32_t gbm_format) int rowstride,
uint32_t gbm_format)
{ {
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native);
uint64_t cursor_width, cursor_height; uint64_t cursor_width, cursor_height;
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
struct gbm_device *gbm_device;
get_hardware_cursor_size (native, &cursor_width, &cursor_height); cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
if (!cursor_renderer_gpu_data)
return;
cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width;
cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height;
if (width > cursor_width || height > cursor_height) if (width > cursor_width || height > cursor_height)
{ {
@ -652,14 +745,15 @@ load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
return; return;
} }
if (gbm_device_is_format_supported (priv->gbm, gbm_format, gbm_device = meta_gbm_device_from_gpu (gpu_kms);
if (gbm_device_is_format_supported (gbm_device, gbm_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{ {
struct gbm_bo *bo; struct gbm_bo *bo;
uint8_t buf[4 * cursor_width * cursor_height]; uint8_t buf[4 * cursor_width * cursor_height];
uint i; uint i;
bo = gbm_bo_create (priv->gbm, cursor_width, cursor_height, bo = gbm_bo_create (gbm_device, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo) if (!bo)
{ {
@ -678,7 +772,7 @@ load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
return; return;
} }
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo); set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
} }
else else
{ {
@ -687,42 +781,50 @@ load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
} }
static void static void
invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite) invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
MetaGpuKms *gpu_kms)
{ {
MetaCursorNativePrivate *cursor_priv = MetaCursorNativePrivate *cursor_priv;
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite); MetaCursorNativeGpuState *cursor_gpu_state;
guint pending_bo; guint pending_bo;
cursor_priv = get_cursor_priv (cursor_sprite);
if (!cursor_priv) if (!cursor_priv)
return; return;
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite); cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
g_clear_pointer (&cursor_priv->bos[pending_bo], if (!cursor_gpu_state)
return;
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
(GDestroyNotify) gbm_bo_destroy); (GDestroyNotify) gbm_bo_destroy);
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED; cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
} }
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND
static void static void
meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer, meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite, MetaGpuKms *gpu_kms,
struct wl_resource *buffer) MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer)
{ {
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer); MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv = MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
meta_cursor_renderer_native_get_instance_private (native);
uint32_t gbm_format; uint32_t gbm_format;
uint64_t cursor_width, cursor_height; uint64_t cursor_width, cursor_height;
CoglTexture *texture; CoglTexture *texture;
uint width, height; uint width, height;
if (!priv->gbm || priv->hw_cursor_broken) cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
return; return;
/* Destroy any previous pending cursor buffer; we'll always either fail (which /* Destroy any previous pending cursor buffer; we'll always either fail (which
* should unset, or succeed, which will set new buffer. * should unset, or succeed, which will set new buffer.
*/ */
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite); invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
width = cogl_texture_get_width (texture); width = cogl_texture_get_width (texture);
@ -759,16 +861,18 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
} }
buffer_data = wl_shm_buffer_get_data (shm_buffer); buffer_data = wl_shm_buffer_get_data (shm_buffer);
load_cursor_sprite_gbm_buffer (native, load_cursor_sprite_gbm_buffer_for_gpu (native,
cursor_sprite, gpu_kms,
buffer_data, cursor_sprite,
width, height, rowstride, buffer_data,
gbm_format); width, height, rowstride,
gbm_format);
wl_shm_buffer_end_access (shm_buffer); wl_shm_buffer_end_access (shm_buffer);
} }
else else
{ {
struct gbm_device *gbm_device;
struct gbm_bo *bo; struct gbm_bo *bo;
/* HW cursors have a predefined size (at least 64x64), which usually is /* HW cursors have a predefined size (at least 64x64), which usually is
@ -777,7 +881,8 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
* access to the data, but it's not possible if the buffer is in GPU * access to the data, but it's not possible if the buffer is in GPU
* memory (and possibly tiled too), so if we don't get the right size, we * memory (and possibly tiled too), so if we don't get the right size, we
* fallback to GL. */ * fallback to GL. */
get_hardware_cursor_size (native, &cursor_width, &cursor_height); cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width;
cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height;
if (width != cursor_width || height != cursor_height) if (width != cursor_width || height != cursor_height)
{ {
@ -785,7 +890,8 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
return; return;
} }
bo = gbm_bo_import (priv->gbm, gbm_device = meta_gbm_device_from_gpu (gpu_kms);
bo = gbm_bo_import (gbm_device,
GBM_BO_IMPORT_WL_BUFFER, GBM_BO_IMPORT_WL_BUFFER,
buffer, buffer,
GBM_BO_USE_CURSOR); GBM_BO_USE_CURSOR);
@ -795,32 +901,83 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *r
return; return;
} }
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo); set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
}
}
static void
meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native);
GList *gpus;
GList *l;
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = l->data;
meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (
renderer,
gpu_kms,
cursor_sprite,
buffer);
} }
} }
#endif #endif
static void
meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
MetaGpuKms *gpu_kms,
MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
return;
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
load_cursor_sprite_gbm_buffer_for_gpu (native,
gpu_kms,
cursor_sprite,
(uint8_t *) xc_image->pixels,
xc_image->width,
xc_image->height,
xc_image->width * 4,
GBM_FORMAT_ARGB8888);
}
static void static void
meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer, meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite, MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image) XcursorImage *xc_image)
{ {
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer); MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv = MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native); meta_cursor_renderer_native_get_instance_private (native);
GList *gpus;
GList *l;
if (!priv->gbm || priv->hw_cursor_broken) gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
return; for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = l->data;
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite); meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (
renderer,
load_cursor_sprite_gbm_buffer (native, gpu_kms,
cursor_sprite, cursor_sprite,
(uint8_t *) xc_image->pixels, xc_image);
xc_image->width, }
xc_image->height,
xc_image->width * 4,
GBM_FORMAT_ARGB8888);
} }
static void static void
@ -839,6 +996,8 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
meta_cursor_renderer_native_realize_cursor_from_xcursor; meta_cursor_renderer_native_realize_cursor_from_xcursor;
quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native"); quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
quark_cursor_renderer_native_gpu_data =
g_quark_from_static_string ("-meta-cursor-renderer-native-gpu-data");
} }
static void static void
@ -866,32 +1025,36 @@ init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
MetaCursorRendererNativePrivate *priv = MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native); meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
GList *gpus; GList *gpus;
MetaGpuKms *gpu_kms; GList *l;
uint64_t width, height;
struct gbm_device *gbm_device;
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager); gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
if (g_list_length (gpus) != 1) for (l = gpus; l; l = l->next)
return;
gpu_kms = META_GPU_KMS (gpus->data);
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
if (!gbm_device)
return;
priv->gbm = gbm_device;
priv->drm_fd = meta_gpu_kms_get_fd (gpu_kms);
if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{ {
priv->cursor_width = width; MetaGpuKms *gpu_kms = l->data;
priv->cursor_height = height; MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
} int kms_fd;
else struct gbm_device *gbm_device;
{ uint64_t width, height;
priv->cursor_width = 64;
priv->cursor_height = 64; gbm_device = meta_gbm_device_from_gpu (gpu_kms);
if (!gbm_device)
continue;
cursor_renderer_gpu_data =
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (drmGetCap (kms_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (kms_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
cursor_renderer_gpu_data->cursor_width = width;
cursor_renderer_gpu_data->cursor_height = height;
}
else
{
cursor_renderer_gpu_data->cursor_width = 64;
cursor_renderer_gpu_data->cursor_height = 64;
}
} }
} }