3d693e8309
There are still various helpers that might be worth to move to mtk as well Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3128>
876 lines
27 KiB
C
876 lines
27 KiB
C
/*
|
|
* Copyright (C) 2021 Red Hat
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "backends/native/meta-kms-cursor-manager.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#include "backends/native/meta-kms-crtc.h"
|
|
#include "backends/native/meta-kms-impl.h"
|
|
#include "backends/native/meta-kms-device-private.h"
|
|
#include "backends/native/meta-kms-update-private.h"
|
|
#include "backends/native/meta-thread.h"
|
|
|
|
typedef struct _MetaKmsCursorManagerImpl
|
|
{
|
|
MetaKmsImpl *impl;
|
|
GPtrArray *crtc_states;
|
|
|
|
MetaKmsCursorQueryInImpl cursor_query_in_impl_func;
|
|
gpointer cursor_query_in_impl_func_user_data;
|
|
|
|
MetaKmsUpdateFilter *update_filter;
|
|
} MetaKmsCursorManagerImpl;
|
|
|
|
typedef struct _CrtcStateImpl
|
|
{
|
|
gatomicrefcount ref_count;
|
|
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl;
|
|
|
|
MetaKmsCrtc *crtc;
|
|
graphene_rect_t layout;
|
|
float scale;
|
|
MetaMonitorTransform transform;
|
|
MetaDrmBuffer *buffer;
|
|
graphene_point_t hotspot;
|
|
|
|
gboolean cursor_invalidated;
|
|
gboolean force_update;
|
|
gboolean has_cursor;
|
|
|
|
graphene_point_t pending_hotspot;
|
|
MetaDrmBuffer *pending_buffer;
|
|
MetaDrmBuffer *active_buffer;
|
|
MetaDrmBuffer *presenting_buffer;
|
|
} CrtcStateImpl;
|
|
|
|
struct _MetaKmsCursorManager
|
|
{
|
|
GObject parent;
|
|
|
|
MetaKms *kms;
|
|
};
|
|
|
|
G_DEFINE_TYPE (MetaKmsCursorManager, meta_kms_cursor_manager,
|
|
G_TYPE_OBJECT)
|
|
|
|
static GQuark quark_cursor_manager_impl;
|
|
|
|
static CrtcStateImpl *
|
|
find_crtc_state (MetaKmsCursorManagerImpl *cursor_manager_impl,
|
|
MetaKmsCrtc *crtc)
|
|
{
|
|
int i;
|
|
|
|
if (!cursor_manager_impl->crtc_states)
|
|
return NULL;
|
|
|
|
for (i = 0; i < cursor_manager_impl->crtc_states->len; i++)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl =
|
|
g_ptr_array_index (cursor_manager_impl->crtc_states, i);
|
|
|
|
if (crtc_state_impl->crtc == crtc)
|
|
return crtc_state_impl;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static CrtcStateImpl *
|
|
crtc_state_impl_new (MetaKmsCursorManagerImpl *cursor_manager_impl,
|
|
MetaKmsCrtc *crtc,
|
|
graphene_rect_t layout,
|
|
float scale,
|
|
MetaDrmBuffer *buffer)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl;
|
|
|
|
crtc_state_impl = g_new0 (CrtcStateImpl, 1);
|
|
g_atomic_ref_count_init (&crtc_state_impl->ref_count);
|
|
crtc_state_impl->cursor_manager_impl = cursor_manager_impl;
|
|
crtc_state_impl->crtc = crtc;
|
|
crtc_state_impl->layout = layout;
|
|
crtc_state_impl->scale = scale;
|
|
crtc_state_impl->buffer = buffer;
|
|
|
|
return crtc_state_impl;
|
|
}
|
|
|
|
static CrtcStateImpl *
|
|
crtc_state_impl_ref (CrtcStateImpl *crtc_state_impl)
|
|
{
|
|
g_atomic_ref_count_inc (&crtc_state_impl->ref_count);
|
|
return crtc_state_impl;
|
|
}
|
|
|
|
static void
|
|
crtc_state_impl_unref (CrtcStateImpl *crtc_state_impl)
|
|
{
|
|
if (g_atomic_ref_count_dec (&crtc_state_impl->ref_count))
|
|
{
|
|
g_warn_if_fail (!crtc_state_impl->buffer);
|
|
g_warn_if_fail (!crtc_state_impl->pending_buffer);
|
|
g_warn_if_fail (!crtc_state_impl->active_buffer);
|
|
g_warn_if_fail (!crtc_state_impl->presenting_buffer);
|
|
g_free (crtc_state_impl);
|
|
}
|
|
}
|
|
|
|
static void
|
|
crtc_state_impl_swap_buffer (CrtcStateImpl *crtc_state_impl,
|
|
MetaDrmBuffer **from_buffer_ref,
|
|
MetaDrmBuffer **to_buffer_ref)
|
|
{
|
|
MetaDrmBuffer *buffer_to_release;
|
|
|
|
if (*from_buffer_ref == *to_buffer_ref)
|
|
{
|
|
buffer_to_release = g_steal_pointer (from_buffer_ref);
|
|
}
|
|
else
|
|
{
|
|
buffer_to_release = g_steal_pointer (to_buffer_ref);
|
|
*to_buffer_ref = g_steal_pointer (from_buffer_ref);
|
|
}
|
|
|
|
if (buffer_to_release)
|
|
{
|
|
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc_state_impl->crtc);
|
|
MetaKms *kms = meta_kms_device_get_kms (device);
|
|
|
|
meta_thread_queue_callback (META_THREAD (kms),
|
|
NULL, NULL,
|
|
buffer_to_release,
|
|
g_object_unref);
|
|
}
|
|
}
|
|
|
|
static void
|
|
crtc_state_impl_notify_presented (CrtcStateImpl *crtc_state_impl)
|
|
{
|
|
crtc_state_impl_swap_buffer (crtc_state_impl,
|
|
&crtc_state_impl->active_buffer,
|
|
&crtc_state_impl->presenting_buffer);
|
|
}
|
|
|
|
static void
|
|
cursor_page_flip_feedback_flipped (MetaKmsCrtc *crtc,
|
|
unsigned int sequence,
|
|
unsigned int tv_sec,
|
|
unsigned int tv_usec,
|
|
gpointer user_data)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl = user_data;
|
|
|
|
crtc_state_impl_notify_presented (crtc_state_impl);
|
|
}
|
|
|
|
static void
|
|
cursor_page_flip_feedback_ready (MetaKmsCrtc *crtc,
|
|
gpointer user_data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
cursor_page_flip_feedback_mode_set_fallback (MetaKmsCrtc *crtc,
|
|
gpointer user_data)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl = user_data;
|
|
|
|
crtc_state_impl_notify_presented (crtc_state_impl);
|
|
}
|
|
|
|
static void
|
|
cursor_page_flip_feedback_discarded (MetaKmsCrtc *crtc,
|
|
gpointer user_data,
|
|
const GError *error)
|
|
{
|
|
}
|
|
|
|
static const MetaKmsPageFlipListenerVtable cursor_page_flip_listener_vtable = {
|
|
.flipped = cursor_page_flip_feedback_flipped,
|
|
.ready = cursor_page_flip_feedback_ready,
|
|
.mode_set_fallback = cursor_page_flip_feedback_mode_set_fallback,
|
|
.discarded = cursor_page_flip_feedback_discarded,
|
|
};
|
|
|
|
static void
|
|
cursor_result_feedback (const MetaKmsFeedback *feedback,
|
|
gpointer user_data)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl = user_data;
|
|
|
|
switch (meta_kms_feedback_get_result (feedback))
|
|
{
|
|
case META_KMS_FEEDBACK_PASSED:
|
|
break;
|
|
case META_KMS_FEEDBACK_FAILED:
|
|
return;
|
|
}
|
|
|
|
crtc_state_impl->cursor_invalidated = FALSE;
|
|
|
|
crtc_state_impl_swap_buffer (crtc_state_impl,
|
|
&crtc_state_impl->pending_buffer,
|
|
&crtc_state_impl->active_buffer);
|
|
}
|
|
|
|
static const MetaKmsResultListenerVtable cursor_result_listener_vtable = {
|
|
.feedback = cursor_result_feedback,
|
|
};
|
|
|
|
static gboolean
|
|
get_current_cursor_position (MetaKmsCursorManagerImpl *cursor_manager_impl,
|
|
float *x,
|
|
float *y)
|
|
{
|
|
gpointer user_data;
|
|
|
|
if (!cursor_manager_impl->cursor_query_in_impl_func)
|
|
return FALSE;
|
|
|
|
user_data = cursor_manager_impl->cursor_query_in_impl_func_user_data;
|
|
cursor_manager_impl->cursor_query_in_impl_func (x, y, user_data);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
calculate_cursor_rect (CrtcStateImpl *crtc_state_impl,
|
|
MetaDrmBuffer *buffer,
|
|
const graphene_point_t *hotspot,
|
|
float x,
|
|
float y,
|
|
graphene_rect_t *out_cursor_rect)
|
|
{
|
|
int crtc_x, crtc_y, crtc_width, crtc_height;
|
|
int buffer_width, buffer_height;
|
|
graphene_rect_t cursor_rect;
|
|
|
|
crtc_x = (x - crtc_state_impl->layout.origin.x) * crtc_state_impl->scale;
|
|
crtc_y = (y - crtc_state_impl->layout.origin.y) * crtc_state_impl->scale;
|
|
crtc_width = roundf (crtc_state_impl->layout.size.width *
|
|
crtc_state_impl->scale);
|
|
crtc_height = roundf (crtc_state_impl->layout.size.height *
|
|
crtc_state_impl->scale);
|
|
|
|
meta_monitor_transform_transform_point (crtc_state_impl->transform,
|
|
&crtc_width, &crtc_height,
|
|
&crtc_x, &crtc_y);
|
|
|
|
buffer_width = meta_drm_buffer_get_width (buffer);
|
|
buffer_height = meta_drm_buffer_get_height (buffer);
|
|
|
|
cursor_rect = (graphene_rect_t) {
|
|
.origin = {
|
|
.x = crtc_x - hotspot->x,
|
|
.y = crtc_y - hotspot->y,
|
|
},
|
|
.size = {
|
|
.width = buffer_width,
|
|
.height = buffer_height,
|
|
},
|
|
};
|
|
if (cursor_rect.origin.x + cursor_rect.size.width > 0.0 &&
|
|
cursor_rect.origin.y + cursor_rect.size.height > 0.0 &&
|
|
cursor_rect.origin.x < crtc_width &&
|
|
cursor_rect.origin.y < crtc_height)
|
|
{
|
|
if (out_cursor_rect)
|
|
*out_cursor_rect = cursor_rect;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static MetaKmsUpdate *
|
|
maybe_update_cursor_plane (MetaKmsCursorManagerImpl *cursor_manager_impl,
|
|
MetaKmsCrtc *crtc,
|
|
MetaKmsUpdate *update,
|
|
MetaDrmBuffer **old_buffer)
|
|
{
|
|
MetaKmsImpl *impl = cursor_manager_impl->impl;
|
|
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
|
|
MetaKmsDevice *device;
|
|
CrtcStateImpl *crtc_state_impl;
|
|
float x, y;
|
|
MetaDrmBuffer *buffer;
|
|
const graphene_point_t *hotspot;
|
|
gboolean should_have_cursor;
|
|
gboolean did_have_cursor;
|
|
graphene_rect_t cursor_rect;
|
|
MetaKmsPlane *cursor_plane;
|
|
|
|
g_assert (old_buffer && !*old_buffer);
|
|
|
|
if (!get_current_cursor_position (cursor_manager_impl, &x, &y))
|
|
return update;
|
|
|
|
crtc_state_impl = find_crtc_state (cursor_manager_impl, crtc);
|
|
g_return_val_if_fail (crtc_state_impl, update);
|
|
|
|
if (!crtc_state_impl->cursor_invalidated)
|
|
return update;
|
|
|
|
device = meta_kms_crtc_get_device (crtc_state_impl->crtc);
|
|
buffer = crtc_state_impl->buffer;
|
|
hotspot = &crtc_state_impl->hotspot;
|
|
|
|
if (buffer)
|
|
{
|
|
should_have_cursor = calculate_cursor_rect (crtc_state_impl,
|
|
buffer,
|
|
hotspot,
|
|
x, y,
|
|
&cursor_rect);
|
|
}
|
|
else
|
|
{
|
|
should_have_cursor = FALSE;
|
|
}
|
|
|
|
did_have_cursor = crtc_state_impl->has_cursor;
|
|
crtc_state_impl->has_cursor = should_have_cursor;
|
|
|
|
if (!should_have_cursor && !did_have_cursor)
|
|
return update;
|
|
|
|
if (!update)
|
|
{
|
|
MetaKmsImplDevice *impl_device =
|
|
meta_kms_device_get_impl_device (device);
|
|
|
|
update = meta_kms_update_new (device);
|
|
meta_kms_update_realize (update, impl_device);
|
|
}
|
|
|
|
cursor_plane = meta_kms_device_get_cursor_plane_for (device, crtc);
|
|
|
|
if (should_have_cursor)
|
|
{
|
|
int width, height;
|
|
MetaFixed16Rectangle src_rect;
|
|
MtkRectangle dst_rect;
|
|
MetaKmsAssignPlaneFlag assign_plane_flags =
|
|
META_KMS_ASSIGN_PLANE_FLAG_NONE;
|
|
MetaKmsPlaneAssignment *plane_assignment;
|
|
|
|
if (crtc_state_impl->pending_buffer != crtc_state_impl->buffer)
|
|
{
|
|
*old_buffer = g_steal_pointer (&crtc_state_impl->pending_buffer);
|
|
crtc_state_impl->pending_buffer = g_object_ref (buffer);
|
|
}
|
|
else
|
|
{
|
|
assign_plane_flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED;
|
|
}
|
|
|
|
width = meta_drm_buffer_get_width (buffer);
|
|
height = meta_drm_buffer_get_height (buffer);
|
|
|
|
src_rect = (MetaFixed16Rectangle) {
|
|
.x = meta_fixed_16_from_int (0),
|
|
.y = meta_fixed_16_from_int (0),
|
|
.width = meta_fixed_16_from_int (width),
|
|
.height = meta_fixed_16_from_int (height),
|
|
};
|
|
dst_rect = (MtkRectangle) {
|
|
.x = round (cursor_rect.origin.x),
|
|
.y = round (cursor_rect.origin.y),
|
|
.width = round (cursor_rect.size.width),
|
|
.height = round (cursor_rect.size.height),
|
|
};
|
|
|
|
plane_assignment = meta_kms_update_assign_plane (update,
|
|
crtc, cursor_plane,
|
|
buffer,
|
|
src_rect, dst_rect,
|
|
assign_plane_flags);
|
|
meta_kms_plane_assignment_set_cursor_hotspot (plane_assignment,
|
|
(int) roundf (hotspot->x),
|
|
(int) roundf (hotspot->y));
|
|
}
|
|
else
|
|
{
|
|
*old_buffer = g_steal_pointer (&crtc_state_impl->pending_buffer);
|
|
meta_kms_update_unassign_plane (update, crtc, cursor_plane);
|
|
}
|
|
|
|
meta_kms_update_add_page_flip_listener (update,
|
|
crtc,
|
|
&cursor_page_flip_listener_vtable,
|
|
META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
|
|
meta_thread_impl_get_main_context (thread_impl),
|
|
crtc_state_impl_ref (crtc_state_impl),
|
|
(GDestroyNotify) crtc_state_impl_unref);
|
|
meta_kms_update_add_result_listener (update,
|
|
&cursor_result_listener_vtable,
|
|
meta_thread_impl_get_main_context (thread_impl),
|
|
crtc_state_impl_ref (crtc_state_impl),
|
|
(GDestroyNotify) crtc_state_impl_unref);
|
|
|
|
return update;
|
|
}
|
|
|
|
static void
|
|
free_old_buffers (gpointer retval,
|
|
const GError *error,
|
|
gpointer user_data)
|
|
{
|
|
GList *old_buffers = retval;
|
|
|
|
g_list_free_full (old_buffers, g_object_unref);
|
|
}
|
|
|
|
static MetaKmsUpdate *
|
|
update_filter_cb (MetaKmsImpl *impl,
|
|
MetaKmsCrtc *crtc,
|
|
MetaKmsUpdate *update,
|
|
MetaKmsUpdateFlag flags,
|
|
gpointer user_data)
|
|
{
|
|
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl = user_data;
|
|
|
|
if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY)
|
|
return update;
|
|
|
|
if (flags & META_KMS_UPDATE_FLAG_MODE_SET)
|
|
{
|
|
GPtrArray *crtc_states = cursor_manager_impl->crtc_states;
|
|
GList *old_buffers = NULL;
|
|
int i;
|
|
|
|
g_return_val_if_fail (crtc_states, update);
|
|
|
|
for (i = 0; i < crtc_states->len; i++)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl = g_ptr_array_index (crtc_states, i);
|
|
MetaKmsCrtc *crtc = crtc_state_impl->crtc;
|
|
MetaDrmBuffer *old_buffer = NULL;
|
|
|
|
if (meta_kms_crtc_get_device (crtc) !=
|
|
meta_kms_update_get_device (update))
|
|
continue;
|
|
|
|
update = maybe_update_cursor_plane (cursor_manager_impl,
|
|
crtc, update, &old_buffer);
|
|
if (old_buffer)
|
|
old_buffers = g_list_prepend (old_buffers, old_buffer);
|
|
}
|
|
|
|
if (old_buffers)
|
|
{
|
|
meta_thread_queue_callback (meta_thread_impl_get_thread (thread_impl),
|
|
g_main_context_default (),
|
|
NULL,
|
|
old_buffers,
|
|
(GDestroyNotify) free_old_buffers);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MetaDrmBuffer *old_buffer = NULL;
|
|
|
|
update = maybe_update_cursor_plane (cursor_manager_impl,
|
|
crtc, update, &old_buffer);
|
|
|
|
if (old_buffer)
|
|
{
|
|
meta_thread_queue_callback (meta_thread_impl_get_thread (thread_impl),
|
|
g_main_context_default (),
|
|
NULL,
|
|
old_buffer, g_object_unref);
|
|
}
|
|
}
|
|
|
|
return update;
|
|
}
|
|
|
|
static void
|
|
meta_kms_cursor_manager_impl_free (MetaKmsCursorManagerImpl *cursor_manager_impl)
|
|
{
|
|
g_warn_if_fail (!cursor_manager_impl->crtc_states);
|
|
|
|
g_free (cursor_manager_impl);
|
|
}
|
|
|
|
static MetaKmsCursorManagerImpl *
|
|
ensure_cursor_manager_impl (MetaKmsImpl *impl)
|
|
{
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl;
|
|
|
|
cursor_manager_impl = g_object_get_qdata (G_OBJECT (impl),
|
|
quark_cursor_manager_impl);
|
|
if (!cursor_manager_impl)
|
|
{
|
|
cursor_manager_impl = g_new0 (MetaKmsCursorManagerImpl, 1);
|
|
cursor_manager_impl->impl = impl;
|
|
|
|
g_object_set_qdata (G_OBJECT (impl),
|
|
quark_cursor_manager_impl,
|
|
cursor_manager_impl);
|
|
|
|
cursor_manager_impl->update_filter =
|
|
meta_kms_impl_add_update_filter (impl, update_filter_cb,
|
|
cursor_manager_impl);
|
|
}
|
|
return cursor_manager_impl;
|
|
}
|
|
|
|
static gpointer
|
|
finalize_in_impl (MetaThreadImpl *thread_impl,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
MetaKmsImpl *impl = META_KMS_IMPL (thread_impl);
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl;
|
|
|
|
cursor_manager_impl = g_object_steal_qdata (G_OBJECT (impl),
|
|
quark_cursor_manager_impl);
|
|
if (cursor_manager_impl)
|
|
{
|
|
GPtrArray *crtc_states;
|
|
|
|
meta_kms_impl_remove_update_filter (impl,
|
|
cursor_manager_impl->update_filter);
|
|
crtc_states = g_steal_pointer (&cursor_manager_impl->crtc_states);
|
|
meta_kms_cursor_manager_impl_free (cursor_manager_impl);
|
|
return crtc_states;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_kms_cursor_manager_finalize (GObject *object)
|
|
{
|
|
MetaKmsCursorManager *cursor_manager = META_KMS_CURSOR_MANAGER (object);
|
|
GPtrArray *crtc_states;
|
|
|
|
crtc_states =
|
|
meta_thread_run_impl_task_sync (META_THREAD (cursor_manager->kms),
|
|
finalize_in_impl, NULL, NULL);
|
|
g_clear_pointer (&crtc_states, g_ptr_array_unref);
|
|
|
|
G_OBJECT_CLASS (meta_kms_cursor_manager_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
meta_kms_cursor_manager_class_init (MetaKmsCursorManagerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = meta_kms_cursor_manager_finalize;
|
|
|
|
quark_cursor_manager_impl =
|
|
g_quark_from_static_string ("-meta-kms-cursor-manager-quark");
|
|
}
|
|
|
|
static void
|
|
meta_kms_cursor_manager_init (MetaKmsCursorManager *cursor_manager)
|
|
{
|
|
}
|
|
|
|
MetaKmsCursorManager *
|
|
meta_kms_cursor_manager_new (MetaKms *kms)
|
|
{
|
|
MetaKmsCursorManager *cursor_manager;
|
|
|
|
cursor_manager = g_object_new (META_TYPE_KMS_CURSOR_MANAGER, NULL);
|
|
cursor_manager->kms = kms;
|
|
|
|
return cursor_manager;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
MetaKmsCursorQueryInImpl func;
|
|
gpointer user_data;
|
|
} SetQueryFuncData;
|
|
|
|
static gpointer
|
|
set_query_func_in_impl (MetaThreadImpl *thread_impl,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
SetQueryFuncData *data = user_data;
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl =
|
|
ensure_cursor_manager_impl (META_KMS_IMPL (thread_impl));
|
|
|
|
cursor_manager_impl->cursor_query_in_impl_func = data->func;
|
|
cursor_manager_impl->cursor_query_in_impl_func_user_data = data->user_data;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
meta_kms_cursor_manager_set_query_func (MetaKmsCursorManager *cursor_manager,
|
|
MetaKmsCursorQueryInImpl func,
|
|
gpointer user_data)
|
|
{
|
|
SetQueryFuncData *data;
|
|
|
|
data = g_new0 (SetQueryFuncData, 1);
|
|
data->func = func;
|
|
data->user_data = user_data;
|
|
|
|
meta_thread_post_impl_task (META_THREAD (cursor_manager->kms),
|
|
set_query_func_in_impl,
|
|
data, g_free,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gpointer
|
|
position_changed_in_impl (MetaThreadImpl *thread_impl,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl =
|
|
ensure_cursor_manager_impl (META_KMS_IMPL (thread_impl));
|
|
const graphene_point_t *position = user_data;
|
|
GPtrArray *crtc_states;
|
|
int i;
|
|
|
|
crtc_states = cursor_manager_impl->crtc_states;
|
|
g_return_val_if_fail (crtc_states, NULL);
|
|
|
|
for (i = 0; i < crtc_states->len; i++)
|
|
{
|
|
CrtcStateImpl *crtc_state_impl = g_ptr_array_index (crtc_states, i);
|
|
MetaDrmBuffer *buffer;
|
|
const graphene_point_t *hotspot;
|
|
gboolean did_have_cursor;
|
|
gboolean should_have_cursor;
|
|
|
|
buffer = crtc_state_impl->buffer;
|
|
hotspot = &crtc_state_impl->hotspot;
|
|
|
|
if (buffer)
|
|
{
|
|
should_have_cursor = calculate_cursor_rect (crtc_state_impl,
|
|
buffer,
|
|
hotspot,
|
|
position->x,
|
|
position->y,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
should_have_cursor = FALSE;
|
|
}
|
|
|
|
did_have_cursor = crtc_state_impl->has_cursor;
|
|
|
|
if (did_have_cursor != should_have_cursor ||
|
|
should_have_cursor)
|
|
{
|
|
MetaKmsCrtc *crtc = crtc_state_impl->crtc;
|
|
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
|
|
MetaKmsImplDevice *impl_device =
|
|
meta_kms_device_get_impl_device (device);
|
|
|
|
crtc_state_impl->cursor_invalidated = TRUE;
|
|
|
|
meta_kms_impl_device_schedule_process (impl_device,
|
|
crtc_state_impl->crtc);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static graphene_point_t *
|
|
copy_point (const graphene_point_t *point)
|
|
{
|
|
return graphene_point_init_from_point (graphene_point_alloc (), point);
|
|
}
|
|
|
|
void
|
|
meta_kms_cursor_manager_position_changed_in_input_impl (MetaKmsCursorManager *cursor_manager,
|
|
const graphene_point_t *position)
|
|
{
|
|
meta_thread_post_impl_task (META_THREAD (cursor_manager->kms),
|
|
position_changed_in_impl,
|
|
copy_point (position),
|
|
(GDestroyNotify) graphene_point_free,
|
|
NULL, NULL);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
MetaKmsCrtc *crtc;
|
|
MetaDrmBuffer *buffer;
|
|
MetaMonitorTransform transform;
|
|
graphene_point_t hotspot;
|
|
} UpdateSpriteData;
|
|
|
|
static gpointer
|
|
update_sprite_in_impl (MetaThreadImpl *thread_impl,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl =
|
|
ensure_cursor_manager_impl (META_KMS_IMPL (thread_impl));
|
|
UpdateSpriteData *data = user_data;
|
|
MetaKmsCrtc *crtc = data->crtc;
|
|
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
|
|
MetaKmsImplDevice *impl_device =
|
|
meta_kms_device_get_impl_device (device);
|
|
CrtcStateImpl *crtc_state_impl;
|
|
MetaDrmBuffer *old_buffer;
|
|
|
|
crtc_state_impl = find_crtc_state (cursor_manager_impl, crtc);
|
|
g_return_val_if_fail (crtc_state_impl, NULL);
|
|
|
|
old_buffer = g_steal_pointer (&crtc_state_impl->buffer);
|
|
crtc_state_impl->buffer = g_steal_pointer (&data->buffer);
|
|
crtc_state_impl->transform = data->transform;
|
|
crtc_state_impl->hotspot = data->hotspot;
|
|
crtc_state_impl->cursor_invalidated = TRUE;
|
|
|
|
meta_kms_impl_device_schedule_process (impl_device,
|
|
crtc_state_impl->crtc);
|
|
|
|
if (old_buffer)
|
|
{
|
|
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
|
|
|
meta_thread_queue_callback (thread,
|
|
NULL, NULL,
|
|
old_buffer, g_object_unref);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
meta_kms_cursor_manager_update_sprite (MetaKmsCursorManager *cursor_manager,
|
|
MetaKmsCrtc *crtc,
|
|
MetaDrmBuffer *buffer,
|
|
MetaMonitorTransform transform,
|
|
const graphene_point_t *hotspot)
|
|
{
|
|
UpdateSpriteData *data;
|
|
|
|
data = g_new0 (UpdateSpriteData, 1);
|
|
data->crtc = crtc;
|
|
data->buffer = buffer ? g_object_ref (buffer) : NULL;
|
|
data->transform = transform;
|
|
if (hotspot)
|
|
data->hotspot = *hotspot;
|
|
|
|
meta_thread_post_impl_task (META_THREAD (cursor_manager->kms),
|
|
update_sprite_in_impl,
|
|
data, g_free,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
crtc_state_impl_clear_in_main (CrtcStateImpl *crtc_state_impl)
|
|
{
|
|
g_clear_object (&crtc_state_impl->buffer);
|
|
g_clear_object (&crtc_state_impl->pending_buffer);
|
|
g_clear_object (&crtc_state_impl->active_buffer);
|
|
g_clear_object (&crtc_state_impl->presenting_buffer);
|
|
crtc_state_impl_unref (crtc_state_impl);
|
|
}
|
|
|
|
static void
|
|
clear_crtc_states_in_impl (MetaThreadImpl *thread_impl,
|
|
GPtrArray *crtc_states)
|
|
{
|
|
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
|
|
|
meta_thread_queue_callback (thread,
|
|
NULL, NULL,
|
|
crtc_states,
|
|
(GDestroyNotify) g_ptr_array_unref);
|
|
}
|
|
|
|
static gpointer
|
|
update_viewports_in_impl (MetaThreadImpl *thread_impl,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
MetaKmsCursorManagerImpl *cursor_manager_impl =
|
|
ensure_cursor_manager_impl (META_KMS_IMPL (thread_impl));
|
|
GArray *layouts = user_data;
|
|
GPtrArray *crtc_states;
|
|
int i;
|
|
|
|
crtc_states =
|
|
g_ptr_array_new_full (layouts->len,
|
|
(GDestroyNotify) crtc_state_impl_clear_in_main);
|
|
|
|
for (i = 0; i < layouts->len; i++)
|
|
{
|
|
MetaKmsCrtcLayout *crtc_layout =
|
|
&g_array_index (layouts, MetaKmsCrtcLayout, i);
|
|
CrtcStateImpl *crtc_state_impl;
|
|
CrtcStateImpl *old_crtc_state;
|
|
|
|
old_crtc_state = find_crtc_state (cursor_manager_impl, crtc_layout->crtc);
|
|
if (old_crtc_state)
|
|
{
|
|
crtc_state_impl =
|
|
crtc_state_impl_new (cursor_manager_impl,
|
|
crtc_layout->crtc,
|
|
crtc_layout->layout,
|
|
crtc_layout->scale,
|
|
g_steal_pointer (&old_crtc_state->buffer));
|
|
}
|
|
else
|
|
{
|
|
crtc_state_impl =
|
|
crtc_state_impl_new (cursor_manager_impl,
|
|
crtc_layout->crtc,
|
|
crtc_layout->layout,
|
|
crtc_layout->scale,
|
|
NULL);
|
|
}
|
|
|
|
crtc_state_impl->cursor_invalidated = TRUE;
|
|
g_ptr_array_add (crtc_states, crtc_state_impl);
|
|
}
|
|
|
|
if (cursor_manager_impl->crtc_states)
|
|
clear_crtc_states_in_impl (thread_impl, cursor_manager_impl->crtc_states);
|
|
cursor_manager_impl->crtc_states = crtc_states;
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
meta_kms_cursor_manager_update_crtc_layout (MetaKmsCursorManager *cursor_manager,
|
|
GArray *layouts)
|
|
{
|
|
meta_thread_post_impl_task (META_THREAD (cursor_manager->kms),
|
|
update_viewports_in_impl,
|
|
g_array_ref (layouts),
|
|
(GDestroyNotify) g_array_unref,
|
|
NULL, NULL);
|
|
}
|