kms: Use a kernel thread by default

Also add an API to inhibit the kernel thread from being used, and make
MetaRenderDeviceEglStream inhibit the kernel thread from being used if
it's active.

The reason for this is that the MetaRenderDeviceEGlStream is used when
using EGLStreams instead of KMS for page flipping. This means the actual
page flipping happens as a side effect of using EGL/OpenGL, which can't
easily be done off thread.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
Jonas Ådahl 2022-06-15 23:49:15 +02:00
parent 788ad43e17
commit 276ebbf5ee
5 changed files with 179 additions and 1 deletions

View File

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

View File

@ -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 */

View File

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

View File

@ -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',

110
src/tests/native-kms.c Normal file
View File

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