diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 48915814a..32fc315d1 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -152,6 +152,8 @@ struct _MetaKms GList *pending_callbacks; guint callback_source_id; + + int kernel_thread_inhibit_count; }; G_DEFINE_TYPE (MetaKms, meta_kms, META_TYPE_THREAD) @@ -441,7 +443,7 @@ meta_kms_new (MetaBackend *backend, MetaUdev *udev = meta_backend_native_get_udev (backend_native); MetaKms *kms; const char *thread_type_string; - MetaThreadType thread_type = META_THREAD_TYPE_USER; + MetaThreadType thread_type = META_THREAD_TYPE_KERNEL; thread_type_string = g_getenv ("MUTTER_DEBUG_KMS_THREAD_TYPE"); if (thread_type_string) @@ -532,3 +534,23 @@ meta_kms_emit_resources_changed (MetaKms *kms, { g_signal_emit (kms, signals[RESOURCES_CHANGED], 0, changes); } + +void +meta_kms_inhibit_kernel_thread (MetaKms *kms) +{ + kms->kernel_thread_inhibit_count++; + + if (kms->kernel_thread_inhibit_count == 1) + meta_thread_reset_thread_type (META_THREAD (kms), META_THREAD_TYPE_USER); +} + +void +meta_kms_uninhibit_kernel_thread (MetaKms *kms) +{ + g_return_if_fail (kms->kernel_thread_inhibit_count > 0); + + kms->kernel_thread_inhibit_count--; + + if (kms->kernel_thread_inhibit_count == 0) + meta_thread_reset_thread_type (META_THREAD (kms), META_THREAD_TYPE_KERNEL); +} diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index a0e8b2bb8..be7b68d6c 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -56,4 +56,10 @@ MetaKms * meta_kms_new (MetaBackend *backend, MetaKmsFlags flags, GError **error); +META_EXPORT_TEST +void meta_kms_inhibit_kernel_thread (MetaKms *kms); + +META_EXPORT_TEST +void meta_kms_uninhibit_kernel_thread (MetaKms *kms); + #endif /* META_KMS_H */ diff --git a/src/backends/native/meta-render-device-egl-stream.c b/src/backends/native/meta-render-device-egl-stream.c index fa287a66d..dbfd491a5 100644 --- a/src/backends/native/meta-render-device-egl-stream.c +++ b/src/backends/native/meta-render-device-egl-stream.c @@ -23,11 +23,15 @@ #include "backends/native/meta-render-device-egl-stream.h" #include "backends/meta-backend-private.h" +#include "backends/native/meta-backend-native.h" +#include "backends/native/meta-kms.h" struct _MetaRenderDeviceEglStream { MetaRenderDevice parent; + gboolean inhibited_kms_kernel_thread; + EGLDeviceEXT egl_device; }; @@ -169,6 +173,7 @@ meta_render_device_egl_stream_initable_init (GInitable *initable, MetaRenderDeviceEglStream *render_device_egl_stream = META_RENDER_DEVICE_EGL_STREAM (initable); MetaBackend *backend = meta_render_device_get_backend (render_device); + MetaKms *kms; EGLDeviceEXT egl_device; EGLDisplay egl_display; g_autofree const char **missing_extensions = NULL; @@ -198,6 +203,10 @@ meta_render_device_egl_stream_initable_init (GInitable *initable, return FALSE; } + kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); + meta_kms_inhibit_kernel_thread (kms); + render_device_egl_stream->inhibited_kms_kernel_thread = TRUE; + return TRUE; } @@ -259,11 +268,32 @@ meta_render_device_egl_stream_create_egl_display (MetaRenderDevice *render_devi return egl_display; } +static void +meta_render_device_egl_stream_finalize (GObject *object) +{ + MetaRenderDevice *render_device = META_RENDER_DEVICE (object); + MetaRenderDeviceEglStream *render_device_egl_stream = + META_RENDER_DEVICE_EGL_STREAM (render_device); + + if (render_device_egl_stream->inhibited_kms_kernel_thread) + { + MetaBackend *backend = meta_render_device_get_backend (render_device); + MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); + + meta_kms_uninhibit_kernel_thread (kms); + } + + G_OBJECT_CLASS (meta_render_device_egl_stream_parent_class)->finalize (object); +} + static void meta_render_device_egl_stream_class_init (MetaRenderDeviceEglStreamClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaRenderDeviceClass *render_device_class = META_RENDER_DEVICE_CLASS (klass); + object_class->finalize = meta_render_device_egl_stream_finalize; + render_device_class->create_egl_display = meta_render_device_egl_stream_create_egl_display; } diff --git a/src/tests/meson.build b/src/tests/meson.build index 2377d2831..01bd0fbce 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -448,6 +448,16 @@ if have_native_tests ], 'variants': [['', test_env_variables + kms_thread_user_variables]], }, + { + 'name': 'kms', + 'suite': 'backends/native/kms', + 'sources': [ + #'meta-kms-test-utils.c', + #'meta-kms-test-utils.h', + 'native-kms.c', + ], + 'variants': [['', test_env_variables ]], + }, { 'name': 'kms-render', 'suite': 'backends/native/kms', diff --git a/src/tests/native-kms.c b/src/tests/native-kms.c new file mode 100644 index 000000000..263d9831f --- /dev/null +++ b/src/tests/native-kms.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 Red Hat Inc. + * + * 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-backend-native.h" +#include "backends/native/meta-kms.h" +#include "meta-test/meta-context-test.h" +//#include "tests/meta-kms-test-utils.h" + +static MetaContext *test_context; + +static gpointer +assert_not_thread (MetaThreadImpl *thread_impl, + gpointer user_data, + GError **error) +{ + GThread **thread_to_check = user_data; + + g_assert (g_steal_pointer (thread_to_check) != g_thread_self ()); + + return NULL; +} + +static gpointer +assert_thread (MetaThreadImpl *thread_impl, + gpointer user_data, + GError **error) +{ + GThread **thread_to_check = user_data; + + g_assert (g_steal_pointer (thread_to_check) == g_thread_self ()); + + return NULL; +} + +static void +meta_test_kms_inhibit_kernel_thread (void) +{ + MetaBackend *backend = meta_context_get_backend (test_context); + MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); + MetaThread *thread = META_THREAD (kms); + GThread *main_thread; + GThread *test_thread; + + main_thread = g_thread_self (); + + test_thread = main_thread; + meta_thread_post_impl_task (thread, assert_not_thread, &test_thread, NULL, + NULL, NULL); + + meta_kms_inhibit_kernel_thread (kms); + g_assert_null (test_thread); + + test_thread = main_thread; + meta_thread_post_impl_task (thread, assert_thread, &test_thread, NULL, + NULL, NULL); + + meta_kms_uninhibit_kernel_thread (kms); + g_assert_null (test_thread); + + test_thread = main_thread; + meta_thread_post_impl_task (thread, assert_not_thread, &test_thread, NULL, + NULL, NULL); + + while (test_thread) + g_main_context_iteration (NULL, TRUE); +} + +static void +init_tests (void) +{ + g_test_add_func ("/backends/native/kms/inhibit-kernel-thread", + meta_test_kms_inhibit_kernel_thread); +} + +int +main (int argc, + char **argv) +{ + g_autoptr (MetaContext) context = NULL; + g_autoptr (GError) error = NULL; + + context = test_context = + meta_create_test_context (META_CONTEXT_TEST_TYPE_VKMS, + META_CONTEXT_TEST_FLAG_NO_X11); + g_assert (meta_context_configure (context, &argc, &argv, NULL)); + + init_tests (); + + return meta_context_test_run_tests (META_CONTEXT_TEST (context), + META_TEST_RUN_FLAG_CAN_SKIP); +}