Add KMS cursor manager

This new manager object intends to take over management of the cursor
plane from the native cursor renderer. It's API is intended to be used
from the main thread, except for the _in_input() function, but mainly
operates in the KMS context, i.e. the KMS thread.

It makes use of an "update filter" that is called before each
MetaKmsUpdate is turned into a atomic KMS commit or a set of legacy
drmMode*() API calls. When the cursor position has been invalidated,
it'll assign the cursor plane in the filter callback, using an as up to
date as possible pointer position as the source for the cursor plane
position.

Cursor updates from the input thread schedules updates for the affected
CRTCs which will cause the filter to be run, potentially for cursor-only
commits.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
Jonas Ådahl 2022-12-21 18:54:17 +01:00
parent 5a798989c4
commit 6d873036e0
5 changed files with 931 additions and 0 deletions

View File

@ -0,0 +1,853 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#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;
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)
{
float crtc_x, crtc_y;
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;
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_state_impl->layout.size.width *
crtc_state_impl->scale) &&
cursor_rect.origin.y < (crtc_state_impl->layout.size.height *
crtc_state_impl->scale))
{
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;
MetaRectangle dst_rect;
MetaKmsAssignPlaneFlag assign_plane_flags =
META_KMS_ASSIGN_PLANE_FLAG_NONE;
if (crtc_state_impl->pending_buffer != crtc_state_impl->buffer)
{
assign_plane_flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED;
*old_buffer = g_steal_pointer (&crtc_state_impl->pending_buffer);
crtc_state_impl->pending_buffer = g_object_ref (buffer);
}
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 = (MetaRectangle) {
.x = round (cursor_rect.origin.x),
.y = round (cursor_rect.origin.y),
.width = round (cursor_rect.size.width),
.height = round (cursor_rect.size.height),
};
meta_kms_update_assign_plane (update,
crtc, cursor_plane,
buffer,
src_rect, dst_rect,
assign_plane_flags);
}
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;
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);
}
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;
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->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,
const graphene_point_t *hotspot)
{
UpdateSpriteData *data;
data = g_new0 (UpdateSpriteData, 1);
data->crtc = crtc;
data->buffer = buffer ? g_object_ref (buffer) : NULL;
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);
}

View File

@ -0,0 +1,62 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_CURSOR_MANAGER_H
#define META_KMS_CURSOR_MANAGER_H
#include <glib-object.h>
#include <graphene.h>
#include "backends/native/meta-backend-native-types.h"
#include "backends/native/meta-kms-types.h"
#include "core/util-private.h"
typedef struct _MetaKmsCrtcLayout
{
MetaKmsCrtc *crtc;
graphene_rect_t layout;
float scale;
} MetaKmsCrtcLayout;
typedef void (* MetaKmsCursorQueryInImpl) (float *x,
float *y,
gpointer user_data);
#define META_TYPE_KMS_CURSOR_MANAGER (meta_kms_cursor_manager_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsCursorManager, meta_kms_cursor_manager,
META, KMS_CURSOR_MANAGER, GObject)
MetaKmsCursorManager * meta_kms_cursor_manager_new (MetaKms *kms);
void meta_kms_cursor_manager_set_query_func (MetaKmsCursorManager *cursor_manager,
MetaKmsCursorQueryInImpl func,
gpointer user_data);
void meta_kms_cursor_manager_position_changed_in_input_impl (MetaKmsCursorManager *cursor_manager,
const graphene_point_t *position);
void meta_kms_cursor_manager_update_sprite (MetaKmsCursorManager *cursor_manager,
MetaKmsCrtc *crtc,
MetaDrmBuffer *buffer,
const graphene_point_t *hotspot);
void meta_kms_cursor_manager_update_crtc_layout (MetaKmsCursorManager *cursor_manager,
GArray *layouts);
#endif /* META_KMS_CURSOR_MANAGER_H */

View File

@ -43,6 +43,8 @@ typedef enum _MetaKmsPageFlipListenerFlag MetaKmsPageFlipListenerFlag;
typedef struct _MetaKmsImpl MetaKmsImpl; typedef struct _MetaKmsImpl MetaKmsImpl;
typedef struct _MetaKmsImplDevice MetaKmsImplDevice; typedef struct _MetaKmsImplDevice MetaKmsImplDevice;
typedef struct _MetaKmsCursorManager MetaKmsCursorManager;
/* 16:16 fixed point */ /* 16:16 fixed point */
typedef int32_t MetaFixed16; typedef int32_t MetaFixed16;

View File

@ -23,6 +23,7 @@
#include "backends/native/meta-kms-private.h" #include "backends/native/meta-kms-private.h"
#include "backends/native/meta-backend-native.h" #include "backends/native/meta-backend-native.h"
#include "backends/native/meta-kms-cursor-manager.h"
#include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl.h" #include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-update-private.h" #include "backends/native/meta-kms-update-private.h"
@ -154,6 +155,8 @@ struct _MetaKms
guint callback_source_id; guint callback_source_id;
int kernel_thread_inhibit_count; int kernel_thread_inhibit_count;
MetaKmsCursorManager *cursor_manager;
}; };
G_DEFINE_TYPE (MetaKms, meta_kms, META_TYPE_THREAD) G_DEFINE_TYPE (MetaKms, meta_kms, META_TYPE_THREAD)
@ -434,6 +437,8 @@ on_prepare_shutdown (MetaBackend *backend,
{ {
meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL); meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL);
meta_thread_flush_callbacks (META_THREAD (kms)); meta_thread_flush_callbacks (META_THREAD (kms));
g_clear_object (&kms->cursor_manager);
} }
MetaKms * MetaKms *
@ -508,6 +513,7 @@ meta_kms_constructed (GObject *object)
static void static void
meta_kms_init (MetaKms *kms) meta_kms_init (MetaKms *kms)
{ {
kms->cursor_manager = meta_kms_cursor_manager_new (kms);
} }
static void static void
@ -557,3 +563,9 @@ meta_kms_uninhibit_kernel_thread (MetaKms *kms)
if (kms->kernel_thread_inhibit_count == 0) if (kms->kernel_thread_inhibit_count == 0)
meta_thread_reset_thread_type (META_THREAD (kms), META_THREAD_TYPE_KERNEL); meta_thread_reset_thread_type (META_THREAD (kms), META_THREAD_TYPE_KERNEL);
} }
MetaKmsCursorManager *
meta_kms_get_cursor_manager (MetaKms *kms)
{
return kms->cursor_manager;
}

View File

@ -784,6 +784,8 @@ if have_native_backend
'backends/native/meta-kms-crtc-private.h', 'backends/native/meta-kms-crtc-private.h',
'backends/native/meta-kms-crtc.c', 'backends/native/meta-kms-crtc.c',
'backends/native/meta-kms-crtc.h', 'backends/native/meta-kms-crtc.h',
'backends/native/meta-kms-cursor-manager.c',
'backends/native/meta-kms-cursor-manager.h',
'backends/native/meta-kms-device-private.h', 'backends/native/meta-kms-device-private.h',
'backends/native/meta-kms-device.c', 'backends/native/meta-kms-device.c',
'backends/native/meta-kms-device.h', 'backends/native/meta-kms-device.h',