mirror of
https://github.com/brl/mutter.git
synced 2025-05-17 04:24:55 +00:00

In profilers with a timeline or flame graph views it is a very common scenario that a span name must be displayed in an area too short to fit it. In this case, profilers may implement automatic shortening to show the most important part of the span name in the available area. This makes it easier to tell what's going on without having to zoom all the way in. The current trace span names in Mutter don't really follow any system and cannot really be shortened automatically. The Tracy profiler shortens with C++ in mind. Consider an example C++ name: SomeNamespace::SomeClass::some_method(args) The method name is the most important part, and the arguments with the class name will be cut if necessary in the order of importance. This logic makes sence for other languages too, like Rust. I can see it being implemented in other profilers like Sysprof, since it's generally useful. Hence, this commit adjusts our trace names to look like C++ and arrange the parts of the name in the respective order of importance. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3402>
1336 lines
48 KiB
C
1336 lines
48 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* Copyright (C) 2014 Red Hat
|
|
* Copyright 2020 DisplayLink (UK) Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Written by:
|
|
* Jasper St. Pierre <jstpierre@mecheye.net>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "backends/native/meta-cursor-renderer-native.h"
|
|
|
|
#include <string.h>
|
|
#include <gbm.h>
|
|
#include <xf86drm.h>
|
|
#include <errno.h>
|
|
|
|
#include "backends/meta-backend-private.h"
|
|
#include "backends/meta-cursor-sprite-xcursor.h"
|
|
#include "backends/meta-logical-monitor.h"
|
|
#include "backends/meta-monitor.h"
|
|
#include "backends/meta-monitor-manager-private.h"
|
|
#include "backends/meta-output.h"
|
|
#include "backends/native/meta-backend-native-private.h"
|
|
#include "backends/native/meta-crtc-kms.h"
|
|
#include "backends/native/meta-device-pool.h"
|
|
#include "backends/native/meta-drm-buffer-dumb.h"
|
|
#include "backends/native/meta-drm-buffer-gbm.h"
|
|
#include "backends/native/meta-input-thread.h"
|
|
#include "backends/native/meta-frame-native.h"
|
|
#include "backends/native/meta-kms-cursor-manager.h"
|
|
#include "backends/native/meta-kms-device.h"
|
|
#include "backends/native/meta-kms-plane.h"
|
|
#include "backends/native/meta-kms-update.h"
|
|
#include "backends/native/meta-kms.h"
|
|
#include "backends/native/meta-renderer-native.h"
|
|
#include "backends/native/meta-seat-native.h"
|
|
#include "core/boxes-private.h"
|
|
#include "meta/boxes.h"
|
|
#include "meta/meta-backend.h"
|
|
#include "meta/util.h"
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
#include "wayland/meta-cursor-sprite-wayland.h"
|
|
#include "wayland/meta-wayland-buffer.h"
|
|
#endif
|
|
|
|
static GQuark quark_cursor_sprite = 0;
|
|
|
|
typedef struct _CursorStageView
|
|
{
|
|
gboolean needs_emit_painted;
|
|
gboolean has_hw_cursor;
|
|
|
|
gboolean is_hw_cursor_valid;
|
|
} CursorStageView;
|
|
|
|
struct _MetaCursorRendererNative
|
|
{
|
|
MetaCursorRenderer parent;
|
|
};
|
|
|
|
struct _MetaCursorRendererNativePrivate
|
|
{
|
|
MetaBackend *backend;
|
|
|
|
MetaCursorSprite *current_cursor;
|
|
gulong texture_changed_handler_id;
|
|
|
|
guint animation_timeout_id;
|
|
|
|
gulong pointer_position_changed_in_impl_handler_id;
|
|
gboolean input_disconnected;
|
|
GMutex input_mutex;
|
|
GCond input_cond;
|
|
};
|
|
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
|
|
|
|
typedef struct _MetaCursorRendererNativeGpuData
|
|
{
|
|
gboolean hw_cursor_broken;
|
|
|
|
uint64_t cursor_width;
|
|
uint64_t cursor_height;
|
|
} MetaCursorRendererNativeGpuData;
|
|
|
|
typedef struct _MetaCursorNativePrivate
|
|
{
|
|
GHashTable *gpu_states;
|
|
|
|
struct {
|
|
gboolean can_preprocess;
|
|
float current_relative_scale;
|
|
MetaMonitorTransform current_relative_transform;
|
|
} preprocess_state;
|
|
} MetaCursorNativePrivate;
|
|
|
|
static GQuark quark_cursor_renderer_native_gpu_data = 0;
|
|
static GQuark quark_cursor_stage_view = 0;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
|
|
|
|
static gboolean
|
|
realize_cursor_sprite_for_crtc (MetaCursorRenderer *renderer,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSprite *cursor_sprite);
|
|
|
|
static void
|
|
invalidate_cursor_gpu_state (MetaCursorRenderer *cursor_renderer,
|
|
MetaCursorSprite *cursor_sprite);
|
|
|
|
static CursorStageView *
|
|
get_cursor_stage_view (MetaStageView *view)
|
|
{
|
|
return g_object_get_qdata (G_OBJECT (view),
|
|
quark_cursor_stage_view);
|
|
}
|
|
|
|
static CursorStageView *
|
|
ensure_cursor_stage_view (MetaStageView *view)
|
|
{
|
|
CursorStageView *cursor_stage_view;
|
|
|
|
cursor_stage_view = get_cursor_stage_view (view);
|
|
if (!cursor_stage_view)
|
|
{
|
|
cursor_stage_view = g_new0 (CursorStageView, 1);
|
|
cursor_stage_view->is_hw_cursor_valid = FALSE;
|
|
g_object_set_qdata_full (G_OBJECT (view),
|
|
quark_cursor_stage_view,
|
|
cursor_stage_view,
|
|
g_free);
|
|
}
|
|
|
|
return cursor_stage_view;
|
|
}
|
|
|
|
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
|
|
meta_cursor_renderer_native_finalize (GObject *object)
|
|
{
|
|
MetaCursorRendererNative *renderer = META_CURSOR_RENDERER_NATIVE (object);
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (renderer);
|
|
|
|
g_clear_signal_handler (&priv->texture_changed_handler_id,
|
|
priv->current_cursor);
|
|
g_clear_object (&priv->current_cursor);
|
|
g_clear_handle_id (&priv->animation_timeout_id, g_source_remove);
|
|
|
|
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
|
}
|
|
|
|
static float
|
|
calculate_cursor_crtc_sprite_scale (MetaBackend *backend,
|
|
MetaCursorSprite *cursor_sprite,
|
|
MetaLogicalMonitor *logical_monitor)
|
|
{
|
|
if (meta_backend_is_stage_views_scaled (backend))
|
|
{
|
|
return (meta_logical_monitor_get_scale (logical_monitor) *
|
|
meta_cursor_sprite_get_texture_scale (cursor_sprite));
|
|
}
|
|
else
|
|
{
|
|
return meta_cursor_sprite_get_texture_scale (cursor_sprite);
|
|
}
|
|
}
|
|
|
|
static void
|
|
disable_hw_cursor_for_gpu (MetaGpuKms *gpu_kms,
|
|
const GError *error)
|
|
{
|
|
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data =
|
|
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
|
|
|
|
g_warning ("Failed to set hardware cursor (%s), "
|
|
"using OpenGL from now on",
|
|
error->message);
|
|
cursor_renderer_gpu_data->hw_cursor_broken = TRUE;
|
|
}
|
|
|
|
void
|
|
meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_renderer_native,
|
|
MetaRendererView *view,
|
|
ClutterFrame *frame)
|
|
{
|
|
MetaCursorRenderer *cursor_renderer =
|
|
META_CURSOR_RENDERER (cursor_renderer_native);
|
|
CursorStageView *cursor_stage_view;
|
|
MetaCursorSprite *cursor_sprite;
|
|
|
|
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
|
|
if (!cursor_sprite)
|
|
return;
|
|
|
|
cursor_stage_view = get_cursor_stage_view (META_STAGE_VIEW (view));
|
|
if (cursor_stage_view &&
|
|
cursor_stage_view->needs_emit_painted)
|
|
{
|
|
meta_cursor_renderer_emit_painted (cursor_renderer,
|
|
cursor_sprite,
|
|
CLUTTER_STAGE_VIEW (view));
|
|
cursor_stage_view->needs_emit_painted = FALSE;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
|
|
{
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
|
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
|
|
|
|
priv->animation_timeout_id = 0;
|
|
meta_cursor_sprite_tick_frame (cursor_sprite);
|
|
meta_cursor_renderer_force_update (renderer);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
maybe_schedule_cursor_sprite_animation_frame (MetaCursorRendererNative *native,
|
|
MetaCursorSprite *cursor_sprite,
|
|
gboolean cursor_changed)
|
|
{
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
guint delay;
|
|
|
|
if (!cursor_changed && priv->animation_timeout_id)
|
|
return;
|
|
|
|
g_clear_handle_id (&priv->animation_timeout_id, g_source_remove);
|
|
|
|
if (cursor_sprite && meta_cursor_sprite_is_animated (cursor_sprite))
|
|
{
|
|
delay = meta_cursor_sprite_get_current_frame_time (cursor_sprite);
|
|
|
|
if (delay == 0)
|
|
return;
|
|
|
|
priv->animation_timeout_id =
|
|
g_timeout_add (delay,
|
|
(GSourceFunc) meta_cursor_renderer_native_update_animation,
|
|
native);
|
|
g_source_set_name_by_id (priv->animation_timeout_id,
|
|
"[mutter] meta_cursor_renderer_native_update_animation");
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite,
|
|
MetaCursorRenderer *cursor_renderer)
|
|
{
|
|
invalidate_cursor_gpu_state (cursor_renderer, cursor_sprite);
|
|
}
|
|
|
|
static gboolean
|
|
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *cursor_renderer,
|
|
MetaCursorSprite *cursor_sprite)
|
|
{
|
|
MetaCursorRendererNative *native =
|
|
META_CURSOR_RENDERER_NATIVE (cursor_renderer);
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaBackend *backend = priv->backend;
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (priv->backend);
|
|
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
gboolean cursor_changed;
|
|
GList *views;
|
|
GList *l;
|
|
|
|
COGL_TRACE_BEGIN_SCOPED (MetaCursorRendererNative,
|
|
"Meta::CursorRendererNative::update_cursor()");
|
|
|
|
cursor_changed = priv->current_cursor != cursor_sprite;
|
|
|
|
views = meta_renderer_get_views (renderer);
|
|
g_list_foreach (views, (GFunc) ensure_cursor_stage_view, NULL);
|
|
|
|
for (l = views; l; l = l->next)
|
|
{
|
|
MetaStageView *view = l->data;
|
|
MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
|
|
MetaCrtc *crtc = meta_renderer_view_get_crtc (renderer_view);
|
|
MetaCrtcNative *crtc_native = META_CRTC_NATIVE (crtc);
|
|
CursorStageView *cursor_stage_view = NULL;
|
|
gboolean has_hw_cursor = FALSE;
|
|
|
|
cursor_stage_view = get_cursor_stage_view (view);
|
|
g_assert (cursor_stage_view);
|
|
|
|
if (!META_IS_CRTC_KMS (crtc) ||
|
|
!meta_crtc_native_is_hw_cursor_supported (crtc_native))
|
|
{
|
|
if (cursor_stage_view->has_hw_cursor)
|
|
{
|
|
meta_stage_view_uninhibit_cursor_overlay (view);
|
|
cursor_stage_view->has_hw_cursor = FALSE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (cursor_sprite && !meta_backend_is_hw_cursors_inhibited (backend))
|
|
{
|
|
meta_cursor_sprite_realize_texture (cursor_sprite);
|
|
|
|
if (cursor_changed ||
|
|
!cursor_stage_view->is_hw_cursor_valid)
|
|
{
|
|
has_hw_cursor = realize_cursor_sprite_for_crtc (cursor_renderer,
|
|
META_CRTC_KMS (crtc),
|
|
cursor_sprite);
|
|
|
|
cursor_stage_view->is_hw_cursor_valid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
has_hw_cursor =
|
|
cursor_stage_view->is_hw_cursor_valid &&
|
|
cursor_stage_view->has_hw_cursor;
|
|
}
|
|
|
|
if (has_hw_cursor)
|
|
cursor_stage_view->needs_emit_painted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
cursor_stage_view->is_hw_cursor_valid = FALSE;
|
|
has_hw_cursor = FALSE;
|
|
}
|
|
|
|
if (cursor_stage_view->has_hw_cursor != has_hw_cursor)
|
|
{
|
|
if (has_hw_cursor)
|
|
meta_stage_view_inhibit_cursor_overlay (view);
|
|
else
|
|
meta_stage_view_uninhibit_cursor_overlay (view);
|
|
|
|
cursor_stage_view->has_hw_cursor = has_hw_cursor;
|
|
|
|
if (!has_hw_cursor)
|
|
{
|
|
MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
|
|
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
|
|
|
|
meta_kms_cursor_manager_update_sprite (kms_cursor_manager,
|
|
kms_crtc,
|
|
NULL,
|
|
META_MONITOR_TRANSFORM_NORMAL,
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cursor_changed)
|
|
{
|
|
if (priv->current_cursor)
|
|
{
|
|
g_clear_signal_handler (&priv->texture_changed_handler_id,
|
|
priv->current_cursor);
|
|
}
|
|
|
|
g_set_object (&priv->current_cursor, cursor_sprite);
|
|
|
|
if (priv->current_cursor)
|
|
{
|
|
priv->texture_changed_handler_id =
|
|
g_signal_connect (cursor_sprite, "texture-changed",
|
|
G_CALLBACK (on_cursor_sprite_texture_changed),
|
|
cursor_renderer);
|
|
}
|
|
}
|
|
|
|
maybe_schedule_cursor_sprite_animation_frame (native, cursor_sprite,
|
|
cursor_changed);
|
|
|
|
return cursor_sprite && meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
|
}
|
|
|
|
static void
|
|
invalidate_cursor_gpu_state (MetaCursorRenderer *cursor_renderer,
|
|
MetaCursorSprite *cursor_sprite)
|
|
{
|
|
MetaCursorRendererNative *native =
|
|
META_CURSOR_RENDERER_NATIVE (cursor_renderer);
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaRenderer *renderer = meta_backend_get_renderer (priv->backend);
|
|
GList *views;
|
|
GList *l;
|
|
|
|
views = meta_renderer_get_views (renderer);
|
|
for (l = views; l; l = l->next)
|
|
{
|
|
MetaStageView *view = l->data;
|
|
CursorStageView *cursor_stage_view;
|
|
|
|
cursor_stage_view = get_cursor_stage_view (view);
|
|
cursor_stage_view->is_hw_cursor_valid = FALSE;
|
|
}
|
|
}
|
|
|
|
static MetaDrmBuffer *
|
|
create_cursor_drm_buffer_gbm (MetaGpuKms *gpu_kms,
|
|
MetaDeviceFile *device_file,
|
|
struct gbm_device *gbm_device,
|
|
uint8_t *pixels,
|
|
int width,
|
|
int height,
|
|
int stride,
|
|
int cursor_width,
|
|
int cursor_height,
|
|
uint32_t format,
|
|
GError **error)
|
|
{
|
|
struct gbm_bo *bo;
|
|
uint8_t buf[4 * cursor_width * cursor_height];
|
|
int i;
|
|
MetaDrmBufferFlags flags;
|
|
MetaDrmBufferGbm *buffer_gbm;
|
|
|
|
if (!gbm_device_is_format_supported (gbm_device, format,
|
|
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Buffer format not supported");
|
|
return NULL;
|
|
}
|
|
|
|
bo = gbm_bo_create (gbm_device, cursor_width, cursor_height,
|
|
format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
|
if (!bo)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Failed to allocate gbm_bo: %s", g_strerror (errno));
|
|
return NULL;
|
|
}
|
|
|
|
memset (buf, 0, sizeof (buf));
|
|
for (i = 0; i < height; i++)
|
|
memcpy (buf + i * 4 * cursor_width, pixels + i * stride, width * 4);
|
|
if (gbm_bo_write (bo, buf, cursor_width * cursor_height * 4) != 0)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Failed write to gbm_bo: %s", g_strerror (errno));
|
|
gbm_bo_destroy (bo);
|
|
return NULL;
|
|
}
|
|
|
|
flags = META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS;
|
|
buffer_gbm = meta_drm_buffer_gbm_new_take (device_file, bo, flags, error);
|
|
if (!buffer_gbm)
|
|
{
|
|
gbm_bo_destroy (bo);
|
|
return NULL;
|
|
}
|
|
|
|
return META_DRM_BUFFER (buffer_gbm);
|
|
}
|
|
|
|
static MetaDrmBuffer *
|
|
create_cursor_drm_buffer_dumb (MetaGpuKms *gpu_kms,
|
|
MetaDeviceFile *device_file,
|
|
uint8_t *pixels,
|
|
int width,
|
|
int height,
|
|
int stride,
|
|
int cursor_width,
|
|
int cursor_height,
|
|
uint32_t format,
|
|
GError **error)
|
|
{
|
|
MetaDrmBufferDumb *buffer_dumb;
|
|
int i;
|
|
uint8_t *data;
|
|
|
|
buffer_dumb = meta_drm_buffer_dumb_new (device_file,
|
|
cursor_width, cursor_height,
|
|
format,
|
|
error);
|
|
if (!buffer_dumb)
|
|
return NULL;
|
|
|
|
data = meta_drm_buffer_dumb_get_data (buffer_dumb);
|
|
|
|
memset (data, 0, cursor_width * cursor_height * 4);
|
|
for (i = 0; i < height; i++)
|
|
memcpy (data + i * 4 * cursor_width, pixels + i * stride, width * 4);
|
|
|
|
return META_DRM_BUFFER (buffer_dumb);
|
|
}
|
|
|
|
static MetaDrmBuffer *
|
|
create_cursor_drm_buffer (MetaGpuKms *gpu_kms,
|
|
MetaDeviceFile *device_file,
|
|
uint8_t *pixels,
|
|
int width,
|
|
int height,
|
|
int stride,
|
|
int cursor_width,
|
|
int cursor_height,
|
|
uint32_t format,
|
|
GError **error)
|
|
{
|
|
struct gbm_device *gbm_device;
|
|
|
|
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
|
|
if (gbm_device)
|
|
{
|
|
return create_cursor_drm_buffer_gbm (gpu_kms, device_file, gbm_device,
|
|
pixels,
|
|
width, height, stride,
|
|
cursor_width, cursor_height,
|
|
format,
|
|
error);
|
|
}
|
|
else
|
|
{
|
|
return create_cursor_drm_buffer_dumb (gpu_kms, device_file,
|
|
pixels,
|
|
width, height, stride,
|
|
cursor_width, cursor_height,
|
|
format,
|
|
error);
|
|
}
|
|
}
|
|
|
|
static void
|
|
calculate_crtc_cursor_hotspot (MetaCursorSprite *cursor_sprite,
|
|
float scale,
|
|
MetaMonitorTransform transform,
|
|
graphene_point_t *hotspot)
|
|
{
|
|
int hot_x, hot_y;
|
|
int width, height;
|
|
|
|
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
|
|
width = meta_cursor_sprite_get_width (cursor_sprite);
|
|
height = meta_cursor_sprite_get_height (cursor_sprite);
|
|
meta_monitor_transform_transform_point (transform,
|
|
&width, &height,
|
|
&hot_x, &hot_y);
|
|
*hotspot = GRAPHENE_POINT_INIT (hot_x * scale, hot_y * scale);
|
|
}
|
|
|
|
static gboolean
|
|
load_cursor_sprite_gbm_buffer_for_crtc (MetaCursorRendererNative *native,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSprite *cursor_sprite,
|
|
uint8_t *pixels,
|
|
uint width,
|
|
uint height,
|
|
int rowstride,
|
|
float scale,
|
|
MetaMonitorTransform transform,
|
|
uint32_t gbm_format)
|
|
{
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (priv->backend);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
MetaDevicePool *device_pool =
|
|
meta_backend_native_get_device_pool (backend_native);
|
|
MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
|
MetaKmsCrtc *kms_crtc;
|
|
uint64_t cursor_width, cursor_height;
|
|
g_autoptr (MetaDrmBuffer) buffer = NULL;
|
|
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
|
g_autoptr (MetaDeviceFile) device_file = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
graphene_point_t hotspot;
|
|
|
|
cursor_renderer_gpu_data =
|
|
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
|
|
if (!cursor_renderer_gpu_data)
|
|
return FALSE;
|
|
|
|
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)
|
|
{
|
|
meta_warning ("Invalid theme cursor size (must be at most %ux%u)",
|
|
(unsigned int)cursor_width, (unsigned int)cursor_height);
|
|
return FALSE;
|
|
}
|
|
|
|
device_file = meta_device_pool_open (device_pool,
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
META_DEVICE_FILE_FLAG_TAKE_CONTROL,
|
|
&error);
|
|
if (!device_file)
|
|
{
|
|
g_warning ("Failed to open '%s' for updating the cursor: %s",
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
error->message);
|
|
disable_hw_cursor_for_gpu (gpu_kms, error);
|
|
return FALSE;
|
|
}
|
|
|
|
buffer = create_cursor_drm_buffer (gpu_kms, device_file,
|
|
pixels,
|
|
width, height, rowstride,
|
|
cursor_width,
|
|
cursor_height,
|
|
gbm_format,
|
|
&error);
|
|
if (!buffer)
|
|
{
|
|
g_warning ("Realizing HW cursor failed: %s", error->message);
|
|
disable_hw_cursor_for_gpu (gpu_kms, error);
|
|
return FALSE;
|
|
}
|
|
|
|
calculate_crtc_cursor_hotspot (cursor_sprite, scale, transform, &hotspot);
|
|
|
|
kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
|
|
meta_kms_cursor_manager_update_sprite (kms_cursor_manager,
|
|
kms_crtc,
|
|
buffer,
|
|
transform,
|
|
&hotspot);
|
|
return TRUE;
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
scale_and_transform_cursor_sprite_cpu (uint8_t *pixels,
|
|
cairo_format_t pixel_format,
|
|
int width,
|
|
int height,
|
|
int rowstride,
|
|
float scale,
|
|
MetaMonitorTransform transform)
|
|
{
|
|
cairo_t *cr;
|
|
cairo_surface_t *source_surface;
|
|
cairo_surface_t *target_surface;
|
|
int image_width;
|
|
int image_height;
|
|
|
|
image_width = ceilf (width * scale);
|
|
image_height = ceilf (height * scale);
|
|
|
|
target_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
image_width,
|
|
image_height);
|
|
|
|
cr = cairo_create (target_surface);
|
|
if (transform != META_MONITOR_TRANSFORM_NORMAL)
|
|
{
|
|
cairo_translate (cr, 0.5 * image_width, 0.5 * image_height);
|
|
switch (transform)
|
|
{
|
|
case META_MONITOR_TRANSFORM_90:
|
|
cairo_rotate (cr, M_PI * 1.5);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_180:
|
|
cairo_rotate (cr, M_PI);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_270:
|
|
cairo_rotate (cr, M_PI * 0.5);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_FLIPPED:
|
|
cairo_scale (cr, -1, 1);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_FLIPPED_90:
|
|
cairo_scale (cr, -1, 1);
|
|
cairo_rotate (cr, M_PI * 0.5);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_FLIPPED_180:
|
|
cairo_scale (cr, -1, 1);
|
|
cairo_rotate (cr, M_PI);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_FLIPPED_270:
|
|
cairo_scale (cr, -1, 1);
|
|
cairo_rotate (cr, M_PI * 1.5);
|
|
break;
|
|
case META_MONITOR_TRANSFORM_NORMAL:
|
|
g_assert_not_reached ();
|
|
}
|
|
cairo_translate (cr, -0.5 * image_width, -0.5 * image_height);
|
|
}
|
|
cairo_scale (cr, scale, scale);
|
|
|
|
source_surface = cairo_image_surface_create_for_data (pixels,
|
|
pixel_format,
|
|
width,
|
|
height,
|
|
rowstride);
|
|
|
|
cairo_set_source_surface (cr, source_surface, 0, 0);
|
|
cairo_paint (cr);
|
|
cairo_destroy (cr);
|
|
cairo_surface_destroy (source_surface);
|
|
|
|
return target_surface;
|
|
}
|
|
|
|
static cairo_format_t
|
|
gbm_format_to_cairo_format (uint32_t gbm_format)
|
|
{
|
|
switch (gbm_format)
|
|
{
|
|
case GBM_FORMAT_XRGB8888:
|
|
return CAIRO_FORMAT_RGB24;
|
|
default:
|
|
g_warn_if_reached ();
|
|
G_GNUC_FALLTHROUGH;
|
|
case GBM_FORMAT_ARGB8888:
|
|
return CAIRO_FORMAT_ARGB32;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
load_scaled_and_transformed_cursor_sprite (MetaCursorRendererNative *native,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSprite *cursor_sprite,
|
|
float relative_scale,
|
|
MetaMonitorTransform relative_transform,
|
|
uint8_t *data,
|
|
int width,
|
|
int height,
|
|
int rowstride,
|
|
uint32_t gbm_format)
|
|
{
|
|
gboolean retval = FALSE;
|
|
|
|
if (!G_APPROX_VALUE (relative_scale, 1.f, FLT_EPSILON) ||
|
|
relative_transform != META_MONITOR_TRANSFORM_NORMAL ||
|
|
gbm_format != GBM_FORMAT_ARGB8888)
|
|
{
|
|
cairo_surface_t *surface;
|
|
cairo_format_t cairo_format;
|
|
|
|
cairo_format = gbm_format_to_cairo_format (gbm_format);
|
|
surface = scale_and_transform_cursor_sprite_cpu (data,
|
|
cairo_format,
|
|
width,
|
|
height,
|
|
rowstride,
|
|
relative_scale,
|
|
relative_transform);
|
|
|
|
retval =
|
|
load_cursor_sprite_gbm_buffer_for_crtc (native,
|
|
crtc_kms,
|
|
cursor_sprite,
|
|
cairo_image_surface_get_data (surface),
|
|
cairo_image_surface_get_width (surface),
|
|
cairo_image_surface_get_width (surface),
|
|
cairo_image_surface_get_stride (surface),
|
|
relative_scale,
|
|
relative_transform,
|
|
GBM_FORMAT_ARGB8888);
|
|
|
|
cairo_surface_destroy (surface);
|
|
}
|
|
else
|
|
{
|
|
retval = load_cursor_sprite_gbm_buffer_for_crtc (native,
|
|
crtc_kms,
|
|
cursor_sprite,
|
|
data,
|
|
width,
|
|
height,
|
|
rowstride,
|
|
relative_scale,
|
|
relative_transform,
|
|
gbm_format);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
static gboolean
|
|
realize_cursor_sprite_from_wl_buffer_for_crtc (MetaCursorRenderer *renderer,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSpriteWayland *sprite_wayland)
|
|
{
|
|
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_wayland);
|
|
MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
|
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
|
uint64_t cursor_width, cursor_height;
|
|
CoglTexture *texture;
|
|
uint width, height;
|
|
MetaWaylandBuffer *buffer;
|
|
struct wl_resource *buffer_resource;
|
|
struct wl_shm_buffer *shm_buffer;
|
|
|
|
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 FALSE;
|
|
|
|
buffer = meta_cursor_sprite_wayland_get_buffer (sprite_wayland);
|
|
if (!buffer)
|
|
return FALSE;
|
|
|
|
buffer_resource = meta_wayland_buffer_get_resource (buffer);
|
|
if (!buffer_resource)
|
|
return FALSE;
|
|
|
|
shm_buffer = wl_shm_buffer_get (buffer_resource);
|
|
if (shm_buffer)
|
|
{
|
|
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
|
|
uint8_t *buffer_data;
|
|
float relative_scale;
|
|
MetaMonitorTransform relative_transform;
|
|
uint32_t gbm_format;
|
|
|
|
MetaCrtc *crtc = META_CRTC (crtc_kms);
|
|
MetaLogicalMonitor *logical_monitor;
|
|
MetaMonitor *monitor;
|
|
MetaMonitorTransform logical_transform;
|
|
gboolean retval;
|
|
|
|
monitor = meta_output_get_monitor (meta_crtc_get_outputs (crtc)->data);
|
|
logical_monitor = meta_monitor_get_logical_monitor (monitor);
|
|
|
|
relative_scale = calculate_cursor_crtc_sprite_scale (priv->backend,
|
|
cursor_sprite,
|
|
logical_monitor);
|
|
|
|
logical_transform = meta_logical_monitor_get_transform (logical_monitor);
|
|
relative_transform = meta_monitor_transform_transform (
|
|
meta_monitor_transform_invert (
|
|
meta_cursor_sprite_get_texture_transform (cursor_sprite)),
|
|
meta_monitor_logical_to_crtc_transform (monitor, logical_transform));
|
|
|
|
wl_shm_buffer_begin_access (shm_buffer);
|
|
buffer_data = wl_shm_buffer_get_data (shm_buffer);
|
|
|
|
width = wl_shm_buffer_get_width (shm_buffer);
|
|
height = wl_shm_buffer_get_height (shm_buffer);
|
|
|
|
switch (wl_shm_buffer_get_format (shm_buffer))
|
|
{
|
|
case WL_SHM_FORMAT_ARGB8888:
|
|
gbm_format = GBM_FORMAT_ARGB8888;
|
|
break;
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
gbm_format = GBM_FORMAT_XRGB8888;
|
|
break;
|
|
default:
|
|
g_warn_if_reached ();
|
|
gbm_format = GBM_FORMAT_ARGB8888;
|
|
}
|
|
|
|
retval = load_scaled_and_transformed_cursor_sprite (native,
|
|
crtc_kms,
|
|
cursor_sprite,
|
|
relative_scale,
|
|
relative_transform,
|
|
buffer_data,
|
|
width,
|
|
height,
|
|
rowstride,
|
|
gbm_format);
|
|
|
|
wl_shm_buffer_end_access (shm_buffer);
|
|
|
|
return retval;
|
|
}
|
|
else
|
|
{
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (priv->backend);
|
|
MetaDevicePool *device_pool =
|
|
meta_backend_native_get_device_pool (backend_native);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
|
|
int hot_x, hot_y;
|
|
g_autoptr (MetaDeviceFile) device_file = NULL;
|
|
struct gbm_device *gbm_device;
|
|
struct gbm_bo *bo;
|
|
g_autoptr (GError) error = NULL;
|
|
MetaDrmBufferFlags flags;
|
|
MetaDrmBufferGbm *buffer_gbm;
|
|
|
|
device_file = meta_device_pool_open (device_pool,
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
META_DEVICE_FILE_FLAG_TAKE_CONTROL,
|
|
&error);
|
|
if (!device_file)
|
|
{
|
|
g_warning ("Failed to open '%s' for updating the cursor: %s",
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
/* HW cursors have a predefined size (at least 64x64), which usually is
|
|
* bigger than cursor theme size, so themed cursors must be padded with
|
|
* transparent pixels to fill the overlay. This is trivial if we have CPU
|
|
* 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
|
|
* fallback to GL. */
|
|
cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width;
|
|
cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height;
|
|
|
|
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
|
width = cogl_texture_get_width (texture);
|
|
height = cogl_texture_get_height (texture);
|
|
|
|
if (width != cursor_width || height != cursor_height)
|
|
{
|
|
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors");
|
|
return FALSE;
|
|
}
|
|
|
|
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
|
|
if (!gbm_device)
|
|
return FALSE;
|
|
|
|
bo = gbm_bo_import (gbm_device,
|
|
GBM_BO_IMPORT_WL_BUFFER,
|
|
buffer,
|
|
GBM_BO_USE_CURSOR);
|
|
if (!bo)
|
|
{
|
|
meta_warning ("Importing HW cursor from wl_buffer failed");
|
|
return FALSE;
|
|
}
|
|
|
|
flags = META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS;
|
|
buffer_gbm = meta_drm_buffer_gbm_new_take (device_file, bo, flags,
|
|
&error);
|
|
if (!buffer_gbm)
|
|
{
|
|
meta_warning ("Failed to create DRM buffer wrapper: %s",
|
|
error->message);
|
|
gbm_bo_destroy (bo);
|
|
return FALSE;
|
|
}
|
|
|
|
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
|
|
kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
|
|
meta_kms_cursor_manager_update_sprite (kms_cursor_manager,
|
|
kms_crtc,
|
|
META_DRM_BUFFER (buffer_gbm),
|
|
META_MONITOR_TRANSFORM_NORMAL,
|
|
&GRAPHENE_POINT_INIT (hot_x, hot_y));
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif /* HAVE_WAYLAND */
|
|
|
|
static gboolean
|
|
realize_cursor_sprite_from_xcursor_for_crtc (MetaCursorRenderer *renderer,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSpriteXcursor *sprite_xcursor)
|
|
{
|
|
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (native);
|
|
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
|
|
MetaCrtc *crtc = META_CRTC (crtc_kms);
|
|
MetaLogicalMonitor *logical_monitor;
|
|
MetaMonitor *monitor;
|
|
MetaMonitorTransform logical_transform;
|
|
XcursorImage *xc_image;
|
|
float relative_scale;
|
|
MetaMonitorTransform relative_transform;
|
|
|
|
monitor = meta_output_get_monitor (meta_crtc_get_outputs (crtc)->data);
|
|
logical_monitor = meta_monitor_get_logical_monitor (monitor);
|
|
|
|
relative_scale = calculate_cursor_crtc_sprite_scale (priv->backend,
|
|
cursor_sprite,
|
|
logical_monitor);
|
|
|
|
logical_transform = meta_logical_monitor_get_transform (logical_monitor);
|
|
relative_transform = meta_monitor_transform_transform (
|
|
meta_monitor_transform_invert (
|
|
meta_cursor_sprite_get_texture_transform (cursor_sprite)),
|
|
meta_monitor_logical_to_crtc_transform (monitor, logical_transform));
|
|
|
|
xc_image = meta_cursor_sprite_xcursor_get_current_image (sprite_xcursor);
|
|
|
|
return load_scaled_and_transformed_cursor_sprite (native,
|
|
crtc_kms,
|
|
cursor_sprite,
|
|
relative_scale,
|
|
relative_transform,
|
|
(uint8_t *) xc_image->pixels,
|
|
xc_image->width,
|
|
xc_image->height,
|
|
xc_image->width * 4,
|
|
GBM_FORMAT_ARGB8888);
|
|
}
|
|
|
|
static gboolean
|
|
realize_cursor_sprite_for_crtc (MetaCursorRenderer *renderer,
|
|
MetaCrtcKms *crtc_kms,
|
|
MetaCursorSprite *cursor_sprite)
|
|
{
|
|
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
|
|
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
|
|
|
|
meta_topic (META_DEBUG_KMS,
|
|
"Realizing HW cursor for cursor sprite for CRTC %u (%s)",
|
|
meta_kms_crtc_get_id (kms_crtc),
|
|
meta_kms_device_get_path (kms_device));
|
|
|
|
COGL_TRACE_BEGIN_SCOPED (CursorRendererNativeRealize,
|
|
"Meta::CursorRendererNative::realize_cursor_sprite_for_crtc()");
|
|
if (META_IS_CURSOR_SPRITE_XCURSOR (cursor_sprite))
|
|
{
|
|
MetaCursorSpriteXcursor *sprite_xcursor =
|
|
META_CURSOR_SPRITE_XCURSOR (cursor_sprite);
|
|
|
|
return realize_cursor_sprite_from_xcursor_for_crtc (renderer,
|
|
crtc_kms,
|
|
sprite_xcursor);
|
|
}
|
|
#ifdef HAVE_WAYLAND
|
|
else if (META_IS_CURSOR_SPRITE_WAYLAND (cursor_sprite))
|
|
{
|
|
MetaCursorSpriteWayland *sprite_wayland =
|
|
META_CURSOR_SPRITE_WAYLAND (cursor_sprite);
|
|
|
|
return realize_cursor_sprite_from_wl_buffer_for_crtc (renderer,
|
|
crtc_kms,
|
|
sprite_wayland);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
|
|
{
|
|
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = meta_cursor_renderer_native_finalize;
|
|
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
|
|
|
|
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");
|
|
quark_cursor_stage_view =
|
|
g_quark_from_static_string ("-meta-cursor-stage-view-native");
|
|
}
|
|
|
|
static void
|
|
on_monitors_changed (MetaMonitorManager *monitors,
|
|
MetaCursorRendererNative *native)
|
|
{
|
|
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
|
|
|
meta_cursor_renderer_force_update (renderer);
|
|
}
|
|
|
|
static void
|
|
init_hw_cursor_support_for_gpu (MetaGpuKms *gpu_kms)
|
|
{
|
|
MetaKmsDevice *kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
|
|
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
|
uint64_t width, height;
|
|
|
|
cursor_renderer_gpu_data =
|
|
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
|
|
|
|
if (!meta_kms_device_get_cursor_size (kms_device, &width, &height))
|
|
{
|
|
width = 64;
|
|
height = 64;
|
|
}
|
|
|
|
cursor_renderer_gpu_data->cursor_width = width;
|
|
cursor_renderer_gpu_data->cursor_height = height;
|
|
}
|
|
|
|
static void
|
|
on_gpu_added_for_cursor (MetaBackend *backend,
|
|
MetaGpuKms *gpu_kms)
|
|
{
|
|
init_hw_cursor_support_for_gpu (gpu_kms);
|
|
}
|
|
|
|
typedef struct _CursorKmsImplState
|
|
{
|
|
graphene_point_t sprite_hotspot;
|
|
graphene_rect_t sprite_rect;
|
|
} CursorKmsImplState;
|
|
|
|
static void
|
|
on_pointer_position_changed_in_input_impl (MetaSeatImpl *seat_impl,
|
|
const graphene_point_t *position,
|
|
MetaBackend *backend)
|
|
{
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
|
|
meta_kms_cursor_manager_position_changed_in_input_impl (kms_cursor_manager,
|
|
position);
|
|
}
|
|
|
|
static gboolean
|
|
connect_seat_signals_in_input_impl (gpointer user_data)
|
|
{
|
|
GTask *task = G_TASK (user_data);
|
|
MetaCursorRendererNative *cursor_renderer_native =
|
|
META_CURSOR_RENDERER_NATIVE (g_task_get_task_data (task));
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
|
MetaBackend *backend = priv->backend;
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
|
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
ClutterInputDevice *device;
|
|
graphene_point_t position;
|
|
|
|
priv->pointer_position_changed_in_impl_handler_id =
|
|
g_signal_connect (seat_impl, "pointer-position-changed-in-impl",
|
|
G_CALLBACK (on_pointer_position_changed_in_input_impl),
|
|
backend);
|
|
|
|
|
|
device = meta_seat_impl_get_pointer (seat_impl);
|
|
meta_seat_impl_query_state (seat_impl, device, NULL, &position, NULL);
|
|
meta_kms_cursor_manager_position_changed_in_input_impl (kms_cursor_manager,
|
|
&position);
|
|
|
|
g_task_return_boolean (task, TRUE);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static gboolean
|
|
disconnect_seat_signals_in_input_impl (gpointer user_data)
|
|
{
|
|
GTask *task = G_TASK (user_data);
|
|
MetaCursorRendererNative *cursor_renderer_native =
|
|
META_CURSOR_RENDERER_NATIVE (g_task_get_task_data (task));
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
|
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
|
|
|
|
g_clear_signal_handler (&priv->pointer_position_changed_in_impl_handler_id,
|
|
seat_impl);
|
|
g_task_return_boolean (task, TRUE);
|
|
|
|
g_mutex_lock (&priv->input_mutex);
|
|
priv->input_disconnected = TRUE;
|
|
g_cond_signal (&priv->input_cond);
|
|
g_mutex_unlock (&priv->input_mutex);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
query_cursor_position_in_kms_impl (float *x,
|
|
float *y,
|
|
gpointer user_data)
|
|
{
|
|
ClutterSeat *seat = user_data;
|
|
ClutterInputDevice *device;
|
|
graphene_point_t position;
|
|
|
|
device = clutter_seat_get_pointer (seat);
|
|
clutter_seat_query_state (seat, device, NULL, &position, NULL);
|
|
*x = position.x;
|
|
*y = position.y;
|
|
}
|
|
|
|
static void
|
|
init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
|
|
{
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
|
MetaBackend *backend = priv->backend;
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
MetaKmsCursorManager *kms_cursor_manager = meta_kms_get_cursor_manager (kms);
|
|
ClutterSeat *seat;
|
|
MetaSeatNative *seat_native;
|
|
GList *gpus;
|
|
GList *l;
|
|
|
|
gpus = meta_backend_get_gpus (priv->backend);
|
|
for (l = gpus; l; l = l->next)
|
|
{
|
|
MetaGpuKms *gpu_kms = l->data;
|
|
|
|
init_hw_cursor_support_for_gpu (gpu_kms);
|
|
}
|
|
|
|
seat = meta_backend_get_default_seat (priv->backend);
|
|
seat_native = META_SEAT_NATIVE (seat);
|
|
meta_seat_native_run_impl_task (seat_native,
|
|
connect_seat_signals_in_input_impl,
|
|
cursor_renderer_native, NULL);
|
|
|
|
meta_kms_cursor_manager_set_query_func (kms_cursor_manager,
|
|
query_cursor_position_in_kms_impl,
|
|
seat);
|
|
}
|
|
|
|
static void
|
|
on_started (MetaContext *context,
|
|
MetaCursorRendererNative *cursor_renderer_native)
|
|
{
|
|
if (g_strcmp0 (getenv ("MUTTER_DEBUG_DISABLE_HW_CURSORS"), "1"))
|
|
init_hw_cursor_support (cursor_renderer_native);
|
|
else
|
|
g_message ("Disabling hardware cursors because MUTTER_DEBUG_DISABLE_HW_CURSORS is set");
|
|
}
|
|
|
|
static void
|
|
on_prepare_shutdown (MetaContext *context,
|
|
MetaCursorRendererNative *cursor_renderer_native)
|
|
{
|
|
MetaCursorRendererNativePrivate *priv =
|
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
|
ClutterSeat *seat;
|
|
MetaSeatNative *seat_native;
|
|
|
|
g_mutex_init (&priv->input_mutex);
|
|
g_cond_init (&priv->input_cond);
|
|
priv->input_disconnected = FALSE;
|
|
|
|
seat = meta_backend_get_default_seat (priv->backend);
|
|
seat_native = META_SEAT_NATIVE (seat);
|
|
meta_seat_native_run_impl_task (seat_native,
|
|
disconnect_seat_signals_in_input_impl,
|
|
cursor_renderer_native, NULL);
|
|
|
|
g_mutex_lock (&priv->input_mutex);
|
|
while (!priv->input_disconnected)
|
|
g_cond_wait (&priv->input_cond, &priv->input_mutex);
|
|
g_mutex_unlock (&priv->input_mutex);
|
|
|
|
g_mutex_clear (&priv->input_mutex);
|
|
g_cond_clear (&priv->input_cond);
|
|
}
|
|
|
|
MetaCursorRendererNative *
|
|
meta_cursor_renderer_native_new (MetaBackend *backend,
|
|
ClutterInputDevice *device)
|
|
{
|
|
MetaMonitorManager *monitor_manager =
|
|
meta_backend_get_monitor_manager (backend);
|
|
MetaCursorRendererNative *cursor_renderer_native;
|
|
MetaCursorRendererNativePrivate *priv;
|
|
MetaSeatNative *seat =
|
|
META_SEAT_NATIVE (meta_backend_get_default_seat (backend));
|
|
|
|
g_assert (seat);
|
|
|
|
cursor_renderer_native = g_object_new (META_TYPE_CURSOR_RENDERER_NATIVE,
|
|
"backend", backend,
|
|
"device", device,
|
|
NULL);
|
|
priv =
|
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
|
|
|
g_signal_connect_object (monitor_manager, "monitors-changed-internal",
|
|
G_CALLBACK (on_monitors_changed),
|
|
cursor_renderer_native, 0);
|
|
g_signal_connect (backend, "gpu-added",
|
|
G_CALLBACK (on_gpu_added_for_cursor), NULL);
|
|
g_signal_connect (meta_backend_get_context (backend),
|
|
"started",
|
|
G_CALLBACK (on_started),
|
|
cursor_renderer_native);
|
|
g_signal_connect (meta_backend_get_context (backend),
|
|
"prepare-shutdown",
|
|
G_CALLBACK (on_prepare_shutdown),
|
|
cursor_renderer_native);
|
|
|
|
priv->backend = backend;
|
|
|
|
return cursor_renderer_native;
|
|
}
|
|
|
|
static void
|
|
meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
|
|
{
|
|
}
|