Compare commits

...

7 Commits

Author SHA1 Message Date
4d6f99c95d backend/native: Use high priority contexts for secondary GPUs
Ensure the context requests EGL_CONTEXT_PRIORITY_HIGH_IMG, and
that we use cogl_egl_create_context() to ensure that is honored.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
9e54e404ee backends: Drop rt-scheduler configuration key
This is no longer an experimental feature. Even if we wanted to,
GSettings spawns threads, which we want to avoid until we drop
capabilities.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
6ec6ea7d3c core: Drop all capabilities on initialization
Add an optional dependency on libcap-ng, if the library is detected
drop all capabilities by default, in order to allow packagers/users
to do "setcap CAP_SYS_NICE=+ep `which gnome-shell`" and let it set
higher sched/egl priorities without preserving the capability forever.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
d8c4d78f4a core: Set up EGL context creation thread before dropping capabilities
We do intend this thread to preserve the necessary capabilities to
create high priority EGL contexts. Set this thread up before we drop
these.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
b7a662bfdd core: Set SCHED_RR by default on Wayland sessions
This still may fail if the executable is missing the right capability.
This can no longer depend on a setting as we want this to happen
before capabilities are dropped (and before other threads are spawned).

The necessary bits (eg. "setcap CAP_SYS_NICE=+ep `which gnome-shell`")
are still left up to users/distributors.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
9d61e6e56f core: Move unix signal handler later in the process
This does spawn a thread, so better to leave for late(r) initialization.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
231d9e3c31 cogl: Defer EGLContext creation to a separate thread
This is rather pointless and complex at the moment, but will pay
off as we can then spawn this thread early enough that it keeps
capabilities to create high priority contexts.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/923
2019-11-13 15:12:12 +01:00
14 changed files with 290 additions and 44 deletions

View File

@ -16,7 +16,7 @@ RUN dnf -y update && dnf -y upgrade && \
dnf builddep -y mutter && \
# Until Fedora catches up with new build-deps
dnf install -y 'pkgconfig(graphene-gobject-1.0)' 'pkgconfig(sysprof-capture-3)' && \
dnf install -y 'pkgconfig(graphene-gobject-1.0)' 'pkgconfig(sysprof-capture-3)' 'pkgconfig(libcap-ng)' && \
# For running unit tests
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 '*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center && \

View File

@ -79,6 +79,15 @@ G_BEGIN_DECLS
EGLDisplay
cogl_egl_context_get_egl_display (CoglContext *context);
gboolean cogl_egl_init_thread (void);
EGLContext
cogl_egl_create_context (EGLDisplay display,
EGLConfig config,
EGLContext shared_context,
const EGLint *attrib_list,
GError **error);
G_END_DECLS
/* The gobject introspection scanner seems to parse public headers in

View File

@ -110,6 +110,21 @@ static const CoglFeatureData winsys_feature_data[] =
#include "winsys/cogl-winsys-egl-feature-functions.h"
};
static GMainContext *egl_thread_context = NULL;
typedef struct _CreateEGLContextData
{
EGLDisplay display;
EGLConfig config;
EGLContext shared_context;
const EGLint *attrib_list;
EGLContext context;
GError *error;
GMutex mutex;
GCond cond;
gboolean finished;
} CreateEGLContextData;
static GCallback
_cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer,
const char *name,
@ -386,16 +401,14 @@ try_create_context (CoglDisplay *display,
attribs[i++] = EGL_NONE;
egl_display->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
attribs);
egl_display->egl_context = cogl_egl_create_context (edpy,
config,
EGL_NO_CONTEXT,
attribs,
error);
if (egl_display->egl_context == EGL_NO_CONTEXT)
{
error_message = "Unable to create a suitable EGL context";
goto fail;
}
goto err;
if (egl_renderer->private_features &
COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY)
@ -965,3 +978,206 @@ cogl_egl_context_get_egl_display (CoglContext *context)
return egl_renderer->edpy;
}
static gpointer
init_egl_context_thread (gpointer data)
{
GMainContext *main_context = data;
GMainLoop *main_loop = g_main_loop_new (main_context, FALSE);
g_main_loop_run (main_loop);
return NULL;
}
gboolean
cogl_egl_init_thread (void)
{
g_autoptr (GMainContext) main_context = NULL;
g_autoptr (GThread) thread = NULL;
g_autoptr (GError) error = NULL;
if (egl_thread_context != NULL)
return TRUE;
main_context = g_main_context_new ();
thread = g_thread_try_new ("EGL context generator thread",
init_egl_context_thread,
main_context, &error);
if (!thread)
{
g_warning ("Failed to create EGL Context generator thread: %s",
error->message);
return FALSE;
}
egl_thread_context = g_steal_pointer (&main_context);
return TRUE;
}
static CreateEGLContextData *
create_egl_context_data_new (EGLDisplay display,
EGLConfig config,
EGLContext shared_context,
const EGLint *attrib_list)
{
CreateEGLContextData *data;
data = g_new0 (CreateEGLContextData, 1);
data->display = display;
data->config = config;
data->shared_context = shared_context;
data->attrib_list = attrib_list;
data->context = EGL_NO_CONTEXT;
g_mutex_init (&data->mutex);
g_cond_init (&data->cond);
return data;
}
static const char *
get_egl_error_str (EGLint error_number)
{
switch (error_number)
{
case EGL_SUCCESS:
return "The last function succeeded without error.";
break;
case EGL_NOT_INITIALIZED:
return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
break;
case EGL_BAD_ACCESS:
return "EGL cannot access a requested resource (for example a context is bound in another thread).";
break;
case EGL_BAD_ALLOC:
return "EGL failed to allocate resources for the requested operation.";
break;
case EGL_BAD_ATTRIBUTE:
return "An unrecognized attribute or attribute value was passed in the attribute list.";
break;
case EGL_BAD_CONTEXT:
return "An EGLContext argument does not name a valid EGL rendering context.";
break;
case EGL_BAD_CONFIG:
return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
break;
case EGL_BAD_CURRENT_SURFACE:
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.";
break;
case EGL_BAD_DISPLAY:
return "An EGLDisplay argument does not name a valid EGL display connection.";
break;
case EGL_BAD_SURFACE:
return "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.";
break;
case EGL_BAD_MATCH:
return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).";
break;
case EGL_BAD_PARAMETER:
return "One or more argument values are invalid.";
break;
case EGL_BAD_NATIVE_PIXMAP:
return "A NativePixmapType argument does not refer to a valid native pixmap.";
break;
case EGL_BAD_NATIVE_WINDOW:
return "A NativeWindowType argument does not refer to a valid native window.";
break;
case EGL_CONTEXT_LOST:
return "A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering. ";
break;
case EGL_BAD_STREAM_KHR:
return "An EGLStreamKHR argument does not name a valid EGL stream.";
break;
case EGL_BAD_STATE_KHR:
return "An EGLStreamKHR argument is not in a valid state";
break;
case EGL_BAD_DEVICE_EXT:
return "An EGLDeviceEXT argument does not name a valid EGL device.";
break;
case EGL_BAD_OUTPUT_LAYER_EXT:
return "An EGLOutputLayerEXT argument does not name a valid EGL output layer.";
default:
return "Unknown error";
break;
}
}
static void
set_egl_error (GError **error)
{
EGLint error_number;
const char *error_str;
if (!error)
return;
error_number = eglGetError ();
error_str = get_egl_error_str (error_number);
g_set_error_literal (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_CONTEXT,
error_str);
}
/* Executed in the EGL context generator thread */
static gboolean
create_context_in_thread (gpointer user_data)
{
CreateEGLContextData *data = user_data;
g_mutex_lock (&data->mutex);
data->context = eglCreateContext (data->display,
data->config,
data->shared_context,
data->attrib_list);
if (data->context == EGL_NO_CONTEXT)
set_egl_error (&data->error);
data->finished = TRUE;
g_cond_signal (&data->cond);
g_mutex_unlock (&data->mutex);
return G_SOURCE_REMOVE;
}
EGLContext
cogl_egl_create_context (EGLDisplay display,
EGLConfig config,
EGLContext shared_context,
const EGLint *attrib_list,
GError **error)
{
CreateEGLContextData *data;
EGLContext context;
GSource *source;
if (!cogl_egl_init_thread ())
{
g_set_error_literal (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_CONTEXT,
"EGL thread initialization failed");
return EGL_NO_CONTEXT;
}
data = create_egl_context_data_new (display, config,
shared_context, attrib_list);
g_mutex_lock (&data->mutex);
source = g_idle_source_new ();
g_source_set_callback (source, create_context_in_thread,
data, NULL);
g_source_attach (source, egl_thread_context);
g_source_unref (source);
while (!data->finished)
g_cond_wait (&data->cond, &data->mutex);
context = data->context;
if (data->error)
g_propagate_error (error, data->error);
g_mutex_unlock (&data->mutex);
g_free (data);
return context;
}

View File

@ -67,3 +67,6 @@
/* Either <sys/random.h> or <linux/random.h> */
#mesondefine HAVE_SYS_RANDOM
#mesondefine HAVE_LINUX_RANDOM
/* Defined if libcap-ng is available */
#mesondefine HAVE_LIBCAPNG

View File

@ -120,10 +120,6 @@
framebuffers instead of window content,
to manage HiDPI monitors. Does not
require a restart.
• “rt-scheduler” — makes mutter request a low priority
real-time scheduling. The executable
or user must have CAP_SYS_NICE.
Requires a restart.
• “autostart-xwayland” — initializes Xwayland lazily if there are
X11 clients. Requires restart.
</description>

View File

@ -36,6 +36,7 @@ libstartup_notification_req = '>= 0.7'
libcanberra_req = '>= 0.26'
libwacom_req = '>= 0.13'
atk_req = '>= 2.5.3'
libcapng_req = '>= 0.7.9'
# optional version requirements
udev_req = '>= 228'
@ -127,6 +128,7 @@ xau_dep = dependency('xau')
ice_dep = dependency('ice')
atk_dep = dependency('atk', version: atk_req)
libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
libcapng_dep = dependency('libcap-ng', required: get_option('libcapng'))
# For now always require X11 support
have_x11 = true
@ -258,6 +260,7 @@ have_core_tests = false
have_cogl_tests = false
have_clutter_tests = false
have_installed_tests = false
have_libcapng = libcapng_dep.found()
if have_tests
have_core_tests = get_option('core_tests')
@ -364,6 +367,7 @@ cdata.set('HAVE_SM', have_sm)
cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
cdata.set('HAVE_INTROSPECTION', have_introspection)
cdata.set('HAVE_PROFILER', have_profiler)
cdata.set('HAVE_LIBCAPNG', have_libcapng)
xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base')
cdata.set_quoted('XKB_BASE', xkb_base)
@ -445,6 +449,7 @@ output = [
' Startup notification..... ' + have_startup_notification.to_string(),
' Introspection............ ' + have_introspection.to_string(),
' Profiler................. ' + have_profiler.to_string(),
' libcap-ng................ ' + have_libcapng.to_string(),
'',
' Tests:',
'',

View File

@ -152,3 +152,9 @@ option('xwayland_grab_default_access_rules',
value: 'gnome-boxes,remote-viewer,virt-viewer,virt-manager,vinagre,vncviewer,Xephyr',
description: 'Comma delimited list of applications ressources or class allowed to issue X11 grabs in Xwayland'
)
option('libcapng',
type: 'feature',
value: 'auto',
description: 'Enable libcap-ng support'
)

View File

@ -35,6 +35,7 @@
#include "backends/meta-backend-private.h"
#include "backends/meta-egl.h"
#include "backends/meta-egl-ext.h"
#include "cogl/cogl-egl.h"
#include "meta/util.h"
struct _MetaEgl
@ -506,16 +507,9 @@ meta_egl_create_context (MetaEgl *egl,
const EGLint *attrib_list,
GError **error)
{
EGLContext context;
context = eglCreateContext (display, config, share_context, attrib_list);
if (context == EGL_NO_CONTEXT)
{
set_egl_error (error);
return EGL_NO_CONTEXT;
}
return context;
return cogl_egl_create_context (display, config,
share_context, attrib_list,
error);
}
gboolean

View File

@ -33,8 +33,7 @@ typedef enum _MetaExperimentalFeature
META_EXPERIMENTAL_FEATURE_NONE = 0,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0),
META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS = (1 << 1),
META_EXPERIMENTAL_FEATURE_RT_SCHEDULER = (1 << 2),
META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND = (1 << 3),
META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND = (1 << 2),
} MetaExperimentalFeature;
#define META_TYPE_SETTINGS (meta_settings_get_type ())

View File

@ -264,8 +264,6 @@ experimental_features_handler (GVariant *features_variant,
features |= META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER;
else if (g_str_equal (feature, "kms-modifiers"))
features |= META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS;
else if (g_str_equal (feature, "rt-scheduler"))
features |= META_EXPERIMENTAL_FEATURE_RT_SCHEDULER;
else if (g_str_equal (feature, "autostart-xwayland"))
features |= META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND;
else

View File

@ -341,7 +341,6 @@ static void
meta_backend_native_post_init (MetaBackend *backend)
{
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
MetaSettings *settings = meta_backend_get_settings (backend);
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
@ -349,20 +348,6 @@ meta_backend_native_post_init (MetaBackend *backend)
NULL, NULL);
meta_device_manager_native_set_relative_motion_filter (manager, relative_motion_filter,
meta_backend_get_monitor_manager (backend));
if (meta_settings_is_experimental_feature_enabled (settings,
META_EXPERIMENTAL_FEATURE_RT_SCHEDULER))
{
int retval;
struct sched_param sp = {
.sched_priority = sched_get_priority_min (SCHED_RR)
};
retval = sched_setscheduler (0, SCHED_RR | SCHED_RESET_ON_FORK, &sp);
if (retval != 0)
g_warning ("Failed to set RT scheduler: %m");
}
}
static MetaMonitorManager *

View File

@ -3509,6 +3509,7 @@ create_secondary_egl_context (MetaEgl *egl,
{
EGLint attributes[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
EGL_NONE
};

View File

@ -66,6 +66,10 @@
#include <girepository.h>
#endif
#ifdef HAVE_LIBCAPNG
#include <cap-ng.h>
#endif
#if defined(HAVE_NATIVE_BACKEND) && defined(HAVE_WAYLAND)
#include <systemd/sd-login.h>
#endif /* HAVE_WAYLAND && HAVE_NATIVE_BACKEND */
@ -522,6 +526,22 @@ meta_override_compositor_configuration (MetaCompositorType compositor_type,
_backend_gtype_override = backend_gtype;
}
#ifdef HAVE_NATIVE_BACKEND
static void
meta_set_scheduler (void)
{
int retval;
struct sched_param sp = {
.sched_priority = sched_get_priority_min (SCHED_RR)
};
retval = sched_setscheduler (0, SCHED_RR | SCHED_RESET_ON_FORK, &sp);
if (retval != 0)
g_warning ("Failed to set RT scheduler: %m");
}
#endif /* HAVE_NATIVE_BACKEND */
/**
* meta_init: (skip)
*
@ -553,8 +573,6 @@ meta_init (void)
g_strerror (errno));
#endif
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
if (g_getenv ("MUTTER_VERBOSE"))
meta_set_verbose (TRUE);
if (g_getenv ("MUTTER_DEBUG"))
@ -575,6 +593,21 @@ meta_init (void)
meta_set_is_wayland_compositor (TRUE);
#endif
#ifdef HAVE_NATIVE_BACKEND
if (backend_gtype == META_TYPE_BACKEND_NATIVE)
{
meta_set_scheduler ();
cogl_egl_init_thread ();
}
#endif
#ifdef HAVE_LIBCAPNG
capng_clear (CAPNG_SELECT_BOTH);
capng_apply (CAPNG_SELECT_BOTH);
#endif
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
if (g_get_home_dir ())
if (chdir (g_get_home_dir ()) < 0)
meta_warning ("Could not change to home directory %s.\n",

View File

@ -18,6 +18,7 @@ mutter_pkg_deps = [
glib_dep,
gsettings_desktop_schemas_dep,
gtk3_dep,
libcapng_dep,
pango_dep,
]