diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index 83b217274..5e58bb549 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -755,6 +755,7 @@ process_page_flip_listener (MetaKmsImplDevice *impl_device, meta_kms_page_flip_data_add_listener (page_flip_data, listener->vtable, listener->flags, + listener->main_context, listener_user_data, listener_destroy_notify); diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index 8f44df454..291e9e7bf 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -1091,6 +1091,7 @@ generate_page_flip_datas (MetaKmsImplDevice *impl_device, meta_kms_page_flip_data_add_listener (page_flip_data, listener->vtable, listener->flags, + listener->main_context, user_data, destroy_notify); @@ -1113,6 +1114,7 @@ generate_page_flip_datas (MetaKmsImplDevice *impl_device, meta_kms_page_flip_data_add_listener (page_flip_data, other_listener->vtable, other_listener->flags, + other_listener->main_context, other_user_data, other_destroy_notify); listeners = g_list_delete_link (listeners, l); diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 5ae4104c4..68f6f4172 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -1064,6 +1064,7 @@ meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device, MetaKms *kms = meta_kms_device_get_kms (priv->device); meta_kms_queue_callback (kms, + NULL, emit_resources_changed_callback, GUINT_TO_POINTER (changes), NULL); } diff --git a/src/backends/native/meta-kms-page-flip-private.h b/src/backends/native/meta-kms-page-flip-private.h index 93ed2d30d..f1079014b 100644 --- a/src/backends/native/meta-kms-page-flip-private.h +++ b/src/backends/native/meta-kms-page-flip-private.h @@ -38,6 +38,7 @@ void meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data); void meta_kms_page_flip_data_add_listener (MetaKmsPageFlipData *page_flip_data, const MetaKmsPageFlipListenerVtable *vtable, MetaKmsPageFlipListenerFlag flags, + GMainContext *main_context, gpointer user_data, GDestroyNotify destroy_notify); diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c index c3faf8271..022e65dde 100644 --- a/src/backends/native/meta-kms-page-flip.c +++ b/src/backends/native/meta-kms-page-flip.c @@ -30,8 +30,11 @@ typedef struct _MetaKmsPageFlipClosure { const MetaKmsPageFlipListenerVtable *vtable; MetaKmsPageFlipListenerFlag flags; + GMainContext *main_context; gpointer user_data; GDestroyNotify destroy_notify; + + MetaKmsPageFlipData *page_flip_data; } MetaKmsPageFlipClosure; struct _MetaKmsPageFlipData @@ -55,6 +58,7 @@ struct _MetaKmsPageFlipData static MetaKmsPageFlipClosure * meta_kms_page_flip_closure_new (const MetaKmsPageFlipListenerVtable *vtable, MetaKmsPageFlipListenerFlag flags, + GMainContext *main_context, gpointer user_data, GDestroyNotify destroy_notify) { @@ -64,6 +68,7 @@ meta_kms_page_flip_closure_new (const MetaKmsPageFlipListenerVtable *vtable, *closure = (MetaKmsPageFlipClosure) { .vtable = vtable, .flags = flags, + .main_context = main_context, .user_data = user_data, .destroy_notify = destroy_notify, }; @@ -74,10 +79,20 @@ meta_kms_page_flip_closure_new (const MetaKmsPageFlipListenerVtable *vtable, static void meta_kms_page_flip_closure_free (MetaKmsPageFlipClosure *closure) { + g_clear_pointer (&closure->page_flip_data, meta_kms_page_flip_data_unref); g_clear_pointer (&closure->user_data, closure->destroy_notify); g_free (closure); } +static void +meta_kms_page_closure_set_data (MetaKmsPageFlipClosure *closure, + MetaKmsPageFlipData *page_flip_data) +{ + g_return_if_fail (!closure->page_flip_data); + + closure->page_flip_data = meta_kms_page_flip_data_ref (page_flip_data); +} + MetaKmsPageFlipData * meta_kms_page_flip_data_new (MetaKmsImplDevice *impl_device, MetaKmsCrtc *crtc) @@ -118,12 +133,14 @@ void meta_kms_page_flip_data_add_listener (MetaKmsPageFlipData *page_flip_data, const MetaKmsPageFlipListenerVtable *vtable, MetaKmsPageFlipListenerFlag flags, + GMainContext *main_context, gpointer user_data, GDestroyNotify destroy_notify) { MetaKmsPageFlipClosure *closure; closure = meta_kms_page_flip_closure_new (vtable, flags, + main_context, user_data, destroy_notify); page_flip_data->closures = g_list_append (page_flip_data->closures, closure); @@ -142,31 +159,26 @@ meta_kms_page_flip_data_get_crtc (MetaKmsPageFlipData *page_flip_data) } static void -meta_kms_page_flip_data_flipped (MetaThread *thread, - gpointer user_data) +invoke_page_flip_closure_flipped (MetaThread *thread, + gpointer user_data) { - MetaKmsPageFlipData *page_flip_data = user_data; - GList *l; + MetaKmsPageFlipClosure *closure = user_data; + MetaKmsPageFlipData *page_flip_data = closure->page_flip_data; meta_assert_not_in_kms_impl (META_KMS (thread)); - for (l = page_flip_data->closures; l; l = l->next) + if (page_flip_data->is_symbolic) { - MetaKmsPageFlipClosure *closure = l->data; - - if (page_flip_data->is_symbolic) - { - closure->vtable->ready (page_flip_data->crtc, - closure->user_data); - } - else - { - closure->vtable->flipped (page_flip_data->crtc, - page_flip_data->sequence, - page_flip_data->sec, - page_flip_data->usec, - closure->user_data); - } + closure->vtable->ready (page_flip_data->crtc, + closure->user_data); + } + else + { + closure->vtable->flipped (page_flip_data->crtc, + page_flip_data->sequence, + page_flip_data->sec, + page_flip_data->usec, + closure->user_data); } } @@ -209,63 +221,78 @@ void meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data) { MetaKms *kms = meta_kms_from_impl_device (page_flip_data->impl_device); + g_autoptr (GList) closures = NULL; + GList *l; meta_assert_in_kms_impl (kms); - meta_kms_queue_callback (kms, - meta_kms_page_flip_data_flipped, - page_flip_data, - (GDestroyNotify) meta_kms_page_flip_data_unref); -} - -static void -meta_kms_page_flip_data_mode_set_fallback (MetaThread *thread, - gpointer user_data) -{ - MetaKmsPageFlipData *page_flip_data = user_data; - GList *l; - - meta_assert_not_in_kms_impl (META_KMS (thread)); - - for (l = page_flip_data->closures; l; l = l->next) + closures = g_steal_pointer (&page_flip_data->closures); + for (l = closures; l; l = l->next) { MetaKmsPageFlipClosure *closure = l->data; - closure->vtable->mode_set_fallback (page_flip_data->crtc, - closure->user_data); + meta_kms_page_closure_set_data (closure, page_flip_data); + meta_kms_queue_callback (kms, + closure->main_context, + invoke_page_flip_closure_flipped, + closure, + (GDestroyNotify) meta_kms_page_flip_closure_free); + } + + meta_kms_page_flip_data_unref (page_flip_data); +} + +static void +invoke_page_flip_closure_mode_set_fallback (MetaThread *thread, + gpointer user_data) +{ + MetaKmsPageFlipClosure *closure = user_data; + MetaKmsPageFlipData *page_flip_data = closure->page_flip_data; + + meta_assert_not_in_kms_impl (META_KMS (thread)); + + closure->vtable->mode_set_fallback (page_flip_data->crtc, + closure->user_data); } void meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data) { MetaKms *kms = meta_kms_from_impl_device (page_flip_data->impl_device); + g_autoptr (GList) closures = NULL; + GList *l; meta_assert_in_kms_impl (kms); - meta_kms_queue_callback (kms, - meta_kms_page_flip_data_mode_set_fallback, - page_flip_data, - (GDestroyNotify) meta_kms_page_flip_data_unref); -} - -static void -meta_kms_page_flip_data_discard (MetaThread *thread, - gpointer user_data) -{ - MetaKmsPageFlipData *page_flip_data = user_data; - GList *l; - - meta_assert_not_in_kms_impl (META_KMS (thread)); - - for (l = page_flip_data->closures; l; l = l->next) + closures = g_steal_pointer (&page_flip_data->closures); + for (l = closures; l; l = l->next) { MetaKmsPageFlipClosure *closure = l->data; - closure->vtable->discarded (page_flip_data->crtc, - closure->user_data, - page_flip_data->error); + meta_kms_page_closure_set_data (closure, page_flip_data); + meta_kms_queue_callback (kms, + closure->main_context, + invoke_page_flip_closure_mode_set_fallback, + closure, + (GDestroyNotify) meta_kms_page_flip_closure_free); } + + meta_kms_page_flip_data_unref (page_flip_data); +} + +static void +invoke_page_flip_closure_discarded (MetaThread *thread, + gpointer user_data) +{ + MetaKmsPageFlipClosure *closure = user_data; + MetaKmsPageFlipData *page_flip_data = closure->page_flip_data; + + meta_assert_not_in_kms_impl (META_KMS (thread)); + + closure->vtable->discarded (page_flip_data->crtc, + closure->user_data, + page_flip_data->error); } void @@ -282,14 +309,27 @@ meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data, const GError *error) { MetaKms *kms = meta_kms_from_impl_device (page_flip_data->impl_device); + g_autoptr (GList) closures = NULL; + GList *l; meta_assert_in_kms_impl (kms); if (error) meta_kms_page_flip_data_take_error (page_flip_data, g_error_copy (error)); - meta_kms_queue_callback (kms, - meta_kms_page_flip_data_discard, - page_flip_data, - (GDestroyNotify) meta_kms_page_flip_data_unref); + closures = g_steal_pointer (&page_flip_data->closures); + for (l = closures; l; l = l->next) + { + MetaKmsPageFlipClosure *closure = l->data; + + meta_kms_page_closure_set_data (closure, page_flip_data); + + meta_kms_queue_callback (kms, + closure->main_context, + invoke_page_flip_closure_discarded, + closure, + (GDestroyNotify) meta_kms_page_flip_closure_free); + } + + meta_kms_page_flip_data_unref (page_flip_data); } diff --git a/src/backends/native/meta-kms-private.h b/src/backends/native/meta-kms-private.h index a9fb92b5b..6aa36d3f7 100644 --- a/src/backends/native/meta-kms-private.h +++ b/src/backends/native/meta-kms-private.h @@ -31,6 +31,7 @@ typedef void (* MetaKmsCallback) (MetaKms *kms, gpointer user_data); void meta_kms_queue_callback (MetaKms *kms, + GMainContext *main_context, MetaThreadCallback callback, gpointer user_data, GDestroyNotify user_data_destroy); diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index ab4ad1395..962117a92 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -121,6 +121,7 @@ typedef struct _MetaKmsPageFlipListener MetaKmsCrtc *crtc; const MetaKmsPageFlipListenerVtable *vtable; MetaKmsPageFlipListenerFlag flags; + GMainContext *main_context; gpointer user_data; GDestroyNotify destroy_notify; } MetaKmsPageFlipListener; diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index ceb298a80..d7588124e 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -193,14 +193,35 @@ meta_kms_mode_set_free (MetaKmsModeSet *mode_set) g_free (mode_set); } +static gboolean +noop_callback (gpointer user_data) +{ + return G_SOURCE_REMOVE; +} + static void meta_kms_page_flip_listener_unref (MetaKmsPageFlipListener *listener) { if (!g_atomic_ref_count_dec (&listener->ref_count)) return; - g_clear_pointer (&listener->user_data, listener->destroy_notify); - g_free (listener); + if (listener->main_context == g_main_context_get_thread_default ()) + { + g_clear_pointer (&listener->user_data, listener->destroy_notify); + g_free (listener); + } + else + { + GSource *source; + + source = g_idle_source_new (); + g_source_set_callback (source, noop_callback, + g_steal_pointer (&listener->user_data), + g_steal_pointer (&listener->destroy_notify)); + g_source_attach (source, listener->main_context); + g_source_unref (source); + g_free (listener); + } } static gboolean @@ -497,6 +518,7 @@ meta_kms_update_add_page_flip_listener (MetaKmsUpdate *upd MetaKmsCrtc *crtc, const MetaKmsPageFlipListenerVtable *vtable, MetaKmsPageFlipListenerFlag flags, + GMainContext *main_context, gpointer user_data, GDestroyNotify destroy_notify) { @@ -510,6 +532,7 @@ meta_kms_update_add_page_flip_listener (MetaKmsUpdate *upd .crtc = crtc, .vtable = vtable, .flags = flags, + .main_context = main_context, .user_data = user_data, .destroy_notify = destroy_notify, }; diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index 26da6ca27..8024a3f33 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -168,6 +168,7 @@ void meta_kms_update_add_page_flip_listener (MetaKmsUpdate MetaKmsCrtc *crtc, const MetaKmsPageFlipListenerVtable *vtable, MetaKmsPageFlipListenerFlag flags, + GMainContext *main_context, gpointer user_data, GDestroyNotify destroy_notify); diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 80b50e7b5..158e34aaa 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -170,6 +170,7 @@ meta_kms_queue_result_callback (MetaKms *kms, MetaKmsResultListener *listener) { meta_kms_queue_callback (kms, + NULL, invoke_result_listener, listener, (GDestroyNotify) meta_kms_result_listener_free); @@ -219,6 +220,7 @@ meta_kms_notify_modes_set (MetaKms *kms) void meta_kms_queue_callback (MetaKms *kms, + GMainContext *main_context, MetaThreadCallback callback, gpointer user_data, GDestroyNotify user_data_destroy) @@ -226,7 +228,7 @@ meta_kms_queue_callback (MetaKms *kms, MetaThread *thread = META_THREAD (kms); meta_thread_queue_callback (thread, - NULL, + main_context, callback, user_data, user_data_destroy); diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index bcb791bc4..850fadf6d 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -474,6 +474,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, kms_crtc, &page_flip_listener_vtable, flags, + NULL, g_object_ref (view), g_object_unref); } @@ -1548,6 +1549,7 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, kms_crtc, &page_flip_listener_vtable, META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, + NULL, g_object_ref (onscreen_native->view), g_object_unref); add_onscreen_frame_info (crtc); diff --git a/src/tests/native-kms-updates.c b/src/tests/native-kms-updates.c index 92916aa3c..0d6b7a568 100644 --- a/src/tests/native-kms-updates.c +++ b/src/tests/native-kms-updates.c @@ -351,6 +351,7 @@ meta_test_kms_update_page_flip (void) meta_kms_update_add_page_flip_listener (update, crtc, &page_flip_listener_vtable, META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, + NULL, &data, page_flip_data_destroy); @@ -375,6 +376,7 @@ meta_test_kms_update_page_flip (void) meta_kms_update_add_page_flip_listener (update, crtc, &page_flip_listener_vtable, META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, + NULL, &data, page_flip_data_destroy); @@ -594,6 +596,132 @@ meta_test_kms_update_merge (void) meta_kms_update_free (update1); } +typedef struct _ThreadData +{ + GMutex init_mutex; + GMainContext *main_context; + GMainLoop *main_thread_loop; + GThread *thread; +} ThreadData; + +static gpointer +off_thread_page_flip_thread_func (gpointer user_data) +{ + ThreadData *data = user_data; + MetaKmsDevice *device; + MetaKms *kms; + MetaKmsUpdate *update; + MetaKmsCrtc *crtc; + MetaKmsConnector *connector; + MetaKmsMode *mode; + g_autoptr (MetaDrmBuffer) primary_buffer1 = NULL; + g_autoptr (MetaDrmBuffer) primary_buffer2 = NULL; + MetaKmsPlane *primary_plane; + PageFlipData page_flip_data = {}; + MetaKmsFeedback *feedback; + + g_mutex_lock (&data->init_mutex); + g_mutex_unlock (&data->init_mutex); + + device = meta_get_test_kms_device (test_context); + kms = meta_kms_device_get_kms (device); + crtc = meta_get_test_kms_crtc (device); + connector = meta_get_test_kms_connector (device); + mode = meta_kms_connector_get_preferred_mode (connector); + + meta_thread_register_callback_context (META_THREAD (kms), + data->main_context); + + update = meta_kms_update_new (device); + + meta_kms_update_mode_set (update, crtc, + g_list_append (NULL, connector), + mode); + + primary_buffer1 = meta_create_test_mode_dumb_buffer (device, mode); + + primary_plane = meta_kms_device_get_primary_plane_for (device, crtc); + meta_kms_update_assign_plane (update, + crtc, + primary_plane, + primary_buffer1, + meta_get_mode_fixed_rect_16 (mode), + meta_get_mode_rect (mode), + META_KMS_ASSIGN_PLANE_FLAG_NONE); + + page_flip_data.loop = g_main_loop_new (data->main_context, FALSE); + page_flip_data.thread = g_thread_self (); + meta_kms_update_add_page_flip_listener (update, crtc, + &page_flip_listener_vtable, + META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, + data->main_context, + &page_flip_data, + page_flip_data_destroy); + + feedback = + meta_kms_device_process_update_sync (device, update, + META_KMS_UPDATE_FLAG_NONE); + meta_kms_feedback_unref (feedback); + + g_main_loop_run (page_flip_data.loop); + g_assert_cmpint (page_flip_data.state, ==, DESTROYED); + + page_flip_data.state = INIT; + update = meta_kms_update_new (device); + primary_buffer2 = meta_create_test_mode_dumb_buffer (device, mode); + meta_kms_update_assign_plane (update, + crtc, + primary_plane, + primary_buffer2, + meta_get_mode_fixed_rect_16 (mode), + meta_get_mode_rect (mode), + META_KMS_ASSIGN_PLANE_FLAG_NONE); + meta_kms_update_add_page_flip_listener (update, crtc, + &page_flip_listener_vtable, + META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, + data->main_context, + &page_flip_data, + page_flip_data_destroy); + + feedback = + meta_kms_device_process_update_sync (device, update, + META_KMS_UPDATE_FLAG_NONE); + meta_kms_feedback_unref (feedback); + + g_main_loop_run (page_flip_data.loop); + g_assert_cmpint (page_flip_data.state, ==, DESTROYED); + + g_main_loop_unref (page_flip_data.loop); + + g_main_loop_quit (data->main_thread_loop); + + meta_thread_unregister_callback_context (META_THREAD (kms), + data->main_context); + + return GINT_TO_POINTER (TRUE); +} + +static void +meta_test_kms_update_off_thread_page_flip (void) +{ + ThreadData data = {}; + + g_mutex_init (&data.init_mutex); + g_mutex_lock (&data.init_mutex); + data.main_context = g_main_context_new (); + data.main_thread_loop = g_main_loop_new (NULL, FALSE); + data.thread = g_thread_new ("Off-thread page flip test", + off_thread_page_flip_thread_func, + &data); + g_mutex_unlock (&data.init_mutex); + + g_main_loop_run (data.main_thread_loop); + g_assert_cmpint (GPOINTER_TO_INT (g_thread_join (data.thread)), ==, TRUE); + g_main_loop_unref (data.main_thread_loop); + g_main_context_unref (data.main_context); + g_mutex_clear (&data.init_mutex); +} + static void init_tests (void) { @@ -609,6 +737,8 @@ init_tests (void) meta_test_kms_update_page_flip); g_test_add_func ("/backends/native/kms/update/merge", meta_test_kms_update_merge); + g_test_add_func ("/backends/native/kms/update/off-thread-page-flip", + meta_test_kms_update_off_thread_page_flip); } int