mutter/src/backends/native/meta-kms-cursor-manager.c
Bilal Elmoussaoui 3d693e8309 mutter: Completely replace MetaRectangle with MtkRectangle
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>
2023-08-30 16:46:14 +02:00

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);
}