From 42d614f6fadfc432f4a3f83bcb72b39c5150cd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 5 Mar 2020 21:35:57 +0100 Subject: [PATCH 01/38] backend-native: Add non-functional 'headless' mode Make it possible to pass --headless as a command line argument in order to turn the native backend "headless". This currently doesn't do anything, but the intention is that it should not use logind nor KMS, and work completely headless with only virtual outputs. Part-of: --- src/backends/meta-backend-private.h | 5 +- src/backends/meta-backend.c | 10 +++- src/backends/native/meta-backend-native.c | 43 ++++++++++++++++ src/core/main.c | 63 ++++++++++++++++++++--- 4 files changed, 110 insertions(+), 11 deletions(-) diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 80df654bc67..3926a3c63ae 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -104,7 +104,10 @@ struct _MetaBackendClass MetaPointerConstraint *constraint); }; -void meta_init_backend (GType backend_gtype); +void meta_init_backend (GType backend_gtype, + unsigned int n_properties, + const char *names[], + const GValue *values); void meta_release_backend (void); #ifdef HAVE_WAYLAND diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 9e525957e0e..6b2780eebd9 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -1458,14 +1458,20 @@ meta_backend_get_clutter_backend (MetaBackend *backend) } void -meta_init_backend (GType backend_gtype) +meta_init_backend (GType backend_gtype, + unsigned int n_properties, + const char *names[], + const GValue *values) { MetaBackend *backend; GError *error = NULL; /* meta_backend_init() above install the backend globally so * so meta_get_backend() works even during initialization. */ - backend = g_object_new (backend_gtype, NULL); + backend = META_BACKEND (g_object_new_with_properties (backend_gtype, + n_properties, + names, + values)); if (!g_initable_init (G_INITABLE (backend), NULL, &error)) { g_warning ("Failed to create backend: %s", error->message); diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index bf270c3ffaf..8a83f0bc84d 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -65,6 +65,17 @@ #include "backends/meta-screen-cast.h" #endif +enum +{ + PROP_0, + + PROP_HEADLESS, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + struct _MetaBackendNative { MetaBackend parent; @@ -73,6 +84,8 @@ struct _MetaBackendNative MetaUdev *udev; MetaKms *kms; + gboolean is_headless; + gulong udev_device_added_handler_id; }; @@ -520,6 +533,25 @@ meta_backend_native_initable_init (GInitable *initable, return initable_parent_iface->init (initable, cancellable, error); } +static void +meta_backend_native_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaBackendNative *backend_native = META_BACKEND_NATIVE (object); + + switch (prop_id) + { + case PROP_HEADLESS: + backend_native->is_headless = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void initable_iface_init (GInitableIface *initable_iface) { @@ -534,6 +566,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) MetaBackendClass *backend_class = META_BACKEND_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->set_property = meta_backend_native_set_property; object_class->dispose = meta_backend_native_dispose; backend_class->create_clutter_backend = meta_backend_native_create_clutter_backend; @@ -554,6 +587,16 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->update_screen_size = meta_backend_native_update_screen_size; backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint; + + obj_props[PROP_HEADLESS] = + g_param_spec_boolean ("headless", + "headless", + "Headless", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); } static void diff --git a/src/core/main.c b/src/core/main.c index 4bcfd7a5de1..f908fd217fc 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -208,6 +208,7 @@ static char *opt_wayland_display; #endif #ifdef HAVE_NATIVE_BACKEND static gboolean opt_display_server; +static gboolean opt_headless; #endif static gboolean opt_x11; @@ -279,6 +280,11 @@ static GOptionEntry meta_options[] = { &opt_display_server, N_("Run as a full display server, rather than nested") }, + { + "headless", 0, 0, G_OPTION_ARG_NONE, + &opt_headless, + N_("Run as a headless display server") + }, #endif { "x11", 0, 0, G_OPTION_ARG_NONE, @@ -468,14 +474,21 @@ check_for_wayland_session_type (void) * Wayland compositor, then the X11 Compositing Manager backend is used. */ static void -calculate_compositor_configuration (MetaCompositorType *compositor_type, - GType *backend_gtype) +calculate_compositor_configuration (MetaCompositorType *compositor_type, + GType *backend_gtype, + unsigned int *n_properties, + const char **prop_names[], + GValue *prop_values[]) { #ifdef HAVE_WAYLAND - gboolean run_as_wayland_compositor = opt_wayland && !opt_x11; + gboolean run_as_wayland_compositor = ((opt_wayland || + opt_display_server || + opt_headless) && + !opt_x11); #ifdef HAVE_NATIVE_BACKEND - if ((opt_wayland || opt_nested || opt_display_server) && opt_x11) + if ((opt_wayland || opt_nested || opt_display_server || opt_headless) && + opt_x11) #else if ((opt_wayland || opt_nested) && opt_x11) #endif @@ -485,7 +498,7 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, } #ifdef HAVE_NATIVE_BACKEND - if (opt_nested && opt_display_server) + if (opt_nested && (opt_display_server || opt_headless)) { meta_warning ("Can't run both as nested and as a display server"); meta_exit (META_EXIT_ERROR); @@ -507,6 +520,10 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, #endif /* HAVE_WAYLAND */ *compositor_type = META_COMPOSITOR_TYPE_X11; + *n_properties = 0; + *prop_names = NULL; + *prop_values = NULL; + #ifdef HAVE_WAYLAND if (opt_nested) { @@ -516,9 +533,25 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, #endif /* HAVE_WAYLAND */ #ifdef HAVE_NATIVE_BACKEND - if (opt_display_server) + if (opt_display_server || opt_headless) { *backend_gtype = META_TYPE_BACKEND_NATIVE; + if (opt_headless) + { + static const char *headless_prop_names[] = { + "headless", + }; + static GValue headless_prop_values[] = { + G_VALUE_INIT, + }; + + g_value_init (&headless_prop_values[0], G_TYPE_BOOLEAN); + g_value_set_boolean (&headless_prop_values[0], TRUE); + + *n_properties = G_N_ELEMENTS (headless_prop_values); + *prop_names = headless_prop_names; + *prop_values = headless_prop_values; + } return; } @@ -572,6 +605,10 @@ meta_init (void) const char *debug_env; MetaCompositorType compositor_type; GType backend_gtype; + unsigned int n_properties; + const char **prop_names; + GValue *prop_values; + int i; #ifdef HAVE_SYS_PRCTL prctl (PR_SET_DUMPABLE, 1); @@ -610,10 +647,17 @@ meta_init (void) { compositor_type = _compositor_type_override; backend_gtype = _backend_gtype_override; + n_properties = 0; + prop_names = NULL; + prop_values = NULL; } else { - calculate_compositor_configuration (&compositor_type, &backend_gtype); + calculate_compositor_configuration (&compositor_type, + &backend_gtype, + &n_properties, + &prop_names, + &prop_values); } #ifdef HAVE_WAYLAND @@ -644,7 +688,10 @@ meta_init (void) if (!meta_is_wayland_compositor ()) meta_select_display (opt_display_name); - meta_init_backend (backend_gtype); + meta_init_backend (backend_gtype, n_properties, prop_names, prop_values); + + for (i = 0; i < n_properties; i++) + g_value_reset (&prop_values[i]); meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); -- GitLab From 3091cd89dc6378e1d25dc2896e2f93258078f0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 17 Dec 2020 22:12:41 +0100 Subject: [PATCH 02/38] native: Rename MetaMonitorManagerKms to MetaMonitorManagerNative We'll sooner or later start managing not only KMS backend monitors, but virtual / remote ones too. Part-of: --- src/backends/native/meta-backend-native.c | 16 +- src/backends/native/meta-crtc-kms.c | 10 +- ...er-kms.c => meta-monitor-manager-native.c} | 196 ++++++++++-------- ...er-kms.h => meta-monitor-manager-native.h} | 20 +- src/backends/native/meta-renderer-native.h | 2 +- src/meson.build | 4 +- 6 files changed, 132 insertions(+), 116 deletions(-) rename src/backends/native/{meta-monitor-manager-kms.c => meta-monitor-manager-native.c} (70%) rename src/backends/native/{meta-monitor-manager-kms.h => meta-monitor-manager-native.h} (66%) diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 8a83f0bc84d..ebd8570d07e 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -53,7 +53,7 @@ #include "backends/native/meta-kms.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-launcher.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #include "backends/native/meta-renderer-native.h" #include "backends/native/meta-seat-native.h" #include "backends/native/meta-stage-native.h" @@ -214,7 +214,7 @@ meta_backend_native_create_monitor_manager (MetaBackend *backend, { MetaMonitorManager *manager; - manager = g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error, + manager = g_initable_new (META_TYPE_MONITOR_MANAGER_NATIVE, NULL, error, "backend", backend, NULL); if (!manager) @@ -638,8 +638,8 @@ meta_backend_native_pause (MetaBackendNative *native) MetaBackend *backend = META_BACKEND (native); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); @@ -653,7 +653,7 @@ meta_backend_native_pause (MetaBackendNative *native) disconnect_udev_device_added_handler (native); - meta_monitor_manager_kms_pause (monitor_manager_kms); + meta_monitor_manager_native_pause (monitor_manager_native); } void meta_backend_native_resume (MetaBackendNative *native) @@ -662,8 +662,8 @@ void meta_backend_native_resume (MetaBackendNative *native) ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); MetaIdleMonitor *idle_monitor; ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = @@ -674,7 +674,7 @@ void meta_backend_native_resume (MetaBackendNative *native) COGL_TRACE_BEGIN_SCOPED (MetaBackendNativeResume, "Backend (resume)"); - meta_monitor_manager_kms_resume (monitor_manager_kms); + meta_monitor_manager_native_resume (monitor_manager_native); meta_kms_resume (native->kms); connect_udev_device_added_handler (native); diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index e1272f88c94..02b4999bf38 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -34,7 +34,7 @@ #include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-update.h" #include "backends/native/meta-kms.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1) @@ -187,8 +187,8 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, MetaBackend *backend = meta_gpu_get_backend (gpu); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); MetaKms *kms = meta_kms_device_get_kms (kms_device); MetaKmsUpdate *kms_update; MetaKmsCrtcGamma *gamma; @@ -196,8 +196,8 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, if (crtc_kms->is_gamma_valid) return; - gamma = meta_monitor_manager_kms_get_cached_crtc_gamma (monitor_manager_kms, - crtc_kms); + gamma = meta_monitor_manager_native_get_cached_crtc_gamma (monitor_manager_native, + crtc_kms); if (!gamma) return; diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-native.c similarity index 70% rename from src/backends/native/meta-monitor-manager-kms.c rename to src/backends/native/meta-monitor-manager-native.c index 6b952035ad8..9ba58992268 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -23,11 +23,11 @@ */ /** - * SECTION:meta-monitor-manager-kms - * @title: MetaMonitorManagerKms + * SECTION:meta-monitor-manager-native + * @title: MetaMonitorManagerNative * @short_description: A subclass of #MetaMonitorManager using Linux DRM * - * #MetaMonitorManagerKms is a subclass of #MetaMonitorManager which + * #MetaMonitorManagerNative is a subclass of #MetaMonitorManager which * implements its functionality "natively": it uses the appropriate * functions of the Linux DRM kernel module and using a udev client. * @@ -36,7 +36,7 @@ #include "config.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #include #include @@ -63,7 +63,7 @@ #include "meta/main.h" #include "meta/meta-x11-errors.h" -struct _MetaMonitorManagerKms +struct _MetaMonitorManagerNative { MetaMonitorManager parent_instance; @@ -72,7 +72,7 @@ struct _MetaMonitorManagerKms GHashTable *crtc_gamma_cache; }; -struct _MetaMonitorManagerKmsClass +struct _MetaMonitorManagerNativeClass { MetaMonitorManagerClass parent_class; }; @@ -80,23 +80,23 @@ struct _MetaMonitorManagerKmsClass static void initable_iface_init (GInitableIface *initable_iface); -G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerKms, meta_monitor_manager_kms, +G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerNative, meta_monitor_manager_native, META_TYPE_MONITOR_MANAGER, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) static GBytes * -meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager, - MetaOutput *output) +meta_monitor_manager_native_read_edid (MetaMonitorManager *manager, + MetaOutput *output) { return meta_output_kms_read_edid (META_OUTPUT_KMS (output)); } static void -meta_monitor_manager_kms_read_current_state (MetaMonitorManager *manager) +meta_monitor_manager_native_read_current_state (MetaMonitorManager *manager) { MetaMonitorManagerClass *parent_class = - META_MONITOR_MANAGER_CLASS (meta_monitor_manager_kms_parent_class); + META_MONITOR_MANAGER_CLASS (meta_monitor_manager_native_parent_class); MetaPowerSave power_save_mode; power_save_mode = meta_monitor_manager_get_power_save_mode (manager); @@ -129,8 +129,8 @@ meta_power_save_to_dpms_state (MetaPowerSave power_save) } static void -meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, - MetaPowerSave mode) +meta_monitor_manager_native_set_power_save_mode (MetaMonitorManager *manager, + MetaPowerSave mode) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); @@ -174,7 +174,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, } static void -meta_monitor_manager_kms_ensure_initial_config (MetaMonitorManager *manager) +meta_monitor_manager_native_ensure_initial_config (MetaMonitorManager *manager) { MetaMonitorsConfig *config; @@ -286,10 +286,10 @@ update_screen_size (MetaMonitorManager *manager, } static gboolean -meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - MetaMonitorsConfigMethod method, - GError **error) +meta_monitor_manager_native_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_assignments; GPtrArray *output_assignments; @@ -339,12 +339,12 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager } static void -meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager, - MetaCrtc *crtc, - gsize *size, - unsigned short **red, - unsigned short **green, - unsigned short **blue) +meta_monitor_manager_native_get_crtc_gamma (MetaMonitorManager *manager, + MetaCrtc *crtc, + gsize *size, + unsigned short **red, + unsigned short **green, + unsigned short **blue) { MetaKmsCrtc *kms_crtc; const MetaKmsCrtcState *crtc_state; @@ -422,32 +422,33 @@ generate_gamma_ramp_string (size_t size, } MetaKmsCrtcGamma * -meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms, - MetaCrtcKms *crtc_kms) +meta_monitor_manager_native_get_cached_crtc_gamma (MetaMonitorManagerNative *manager_native, + MetaCrtcKms *crtc_kms) { uint64_t crtc_id; crtc_id = meta_crtc_get_id (META_CRTC (crtc_kms)); - return g_hash_table_lookup (manager_kms->crtc_gamma_cache, + return g_hash_table_lookup (manager_native->crtc_gamma_cache, GUINT_TO_POINTER (crtc_id)); } static void -meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, - MetaCrtc *crtc, - gsize size, - unsigned short *red, - unsigned short *green, - unsigned short *blue) +meta_monitor_manager_native_set_crtc_gamma (MetaMonitorManager *manager, + MetaCrtc *crtc, + gsize size, + unsigned short *red, + unsigned short *green, + unsigned short *blue) { - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (manager); MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); g_autofree char *gamma_ramp_string = NULL; MetaBackend *backend = meta_monitor_manager_get_backend (manager); ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); - g_hash_table_replace (manager_kms->crtc_gamma_cache, + g_hash_table_replace (manager_native->crtc_gamma_cache, GUINT_TO_POINTER (meta_crtc_get_id (crtc)), meta_kms_crtc_gamma_new (kms_crtc, size, red, green, blue)); @@ -474,63 +475,63 @@ on_kms_resources_changed (MetaKms *kms, } static void -meta_monitor_manager_kms_connect_hotplug_handler (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_connect_hotplug_handler (MetaMonitorManagerNative *manager_native) { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); - manager_kms->kms_resources_changed_handler_id = + manager_native->kms_resources_changed_handler_id = g_signal_connect (kms, "resources-changed", G_CALLBACK (on_kms_resources_changed), manager); } static void -meta_monitor_manager_kms_disconnect_hotplug_handler (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_disconnect_hotplug_handler (MetaMonitorManagerNative *manager_native) { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); - g_clear_signal_handler (&manager_kms->kms_resources_changed_handler_id, kms); + g_clear_signal_handler (&manager_native->kms_resources_changed_handler_id, kms); } void -meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_pause (MetaMonitorManagerNative *manager_native) { - meta_monitor_manager_kms_disconnect_hotplug_handler (manager_kms); + meta_monitor_manager_native_disconnect_hotplug_handler (manager_native); } void -meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_resume (MetaMonitorManagerNative *manager_native) { - meta_monitor_manager_kms_connect_hotplug_handler (manager_kms); + meta_monitor_manager_native_connect_hotplug_handler (manager_native); } static gboolean -meta_monitor_manager_kms_is_transform_handled (MetaMonitorManager *manager, - MetaCrtc *crtc, - MetaMonitorTransform transform) +meta_monitor_manager_native_is_transform_handled (MetaMonitorManager *manager, + MetaCrtc *crtc, + MetaMonitorTransform transform) { return meta_crtc_kms_is_transform_handled (META_CRTC_KMS (crtc), transform); } static float -meta_monitor_manager_kms_calculate_monitor_mode_scale (MetaMonitorManager *manager, - MetaMonitor *monitor, - MetaMonitorMode *monitor_mode) +meta_monitor_manager_native_calculate_monitor_mode_scale (MetaMonitorManager *manager, + MetaMonitor *monitor, + MetaMonitorMode *monitor_mode) { return meta_monitor_calculate_mode_scale (monitor, monitor_mode); } static float * -meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager *manager, - MetaLogicalMonitorLayoutMode layout_mode, - MetaMonitor *monitor, - MetaMonitorMode *monitor_mode, - int *n_supported_scales) +meta_monitor_manager_native_calculate_supported_scales (MetaMonitorManager *manager, + MetaLogicalMonitorLayoutMode layout_mode, + MetaMonitor *monitor, + MetaMonitorMode *monitor_mode, + int *n_supported_scales) { MetaMonitorScalesConstraint constraints = META_MONITOR_SCALES_CONSTRAINT_NONE; @@ -550,7 +551,7 @@ meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager } static MetaMonitorManagerCapability -meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager) +meta_monitor_manager_native_get_capabilities (MetaMonitorManager *manager) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaSettings *settings = meta_backend_get_settings (backend); @@ -566,15 +567,15 @@ meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager) } static gboolean -meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager, - int *max_width, - int *max_height) +meta_monitor_manager_native_get_max_screen_size (MetaMonitorManager *manager, + int *max_width, + int *max_height) { return FALSE; } static MetaLogicalMonitorLayoutMode -meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager) +meta_monitor_manager_native_get_default_layout_mode (MetaMonitorManager *manager) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaSettings *settings = meta_backend_get_settings (backend); @@ -588,28 +589,30 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager) } static void -meta_monitor_manager_kms_dispose (GObject *object) +meta_monitor_manager_native_dispose (GObject *object) { - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object); + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (object); - g_clear_pointer (&manager_kms->crtc_gamma_cache, + g_clear_pointer (&manager_native->crtc_gamma_cache, g_hash_table_unref); - G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object); + G_OBJECT_CLASS (meta_monitor_manager_native_parent_class)->dispose (object); } static gboolean -meta_monitor_manager_kms_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +meta_monitor_manager_native_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) { - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (initable); - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (initable); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); gboolean can_have_outputs; GList *l; - meta_monitor_manager_kms_connect_hotplug_handler (manager_kms); + meta_monitor_manager_native_connect_hotplug_handler (manager_native); can_have_outputs = FALSE; for (l = meta_backend_get_gpus (backend); l; l = l->next) @@ -629,7 +632,7 @@ meta_monitor_manager_kms_initable_init (GInitable *initable, return FALSE; } - manager_kms->crtc_gamma_cache = + manager_native->crtc_gamma_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) meta_kms_crtc_gamma_free); @@ -640,33 +643,46 @@ meta_monitor_manager_kms_initable_init (GInitable *initable, static void initable_iface_init (GInitableIface *initable_iface) { - initable_iface->init = meta_monitor_manager_kms_initable_init; + initable_iface->init = meta_monitor_manager_native_initable_init; } static void -meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_init (MetaMonitorManagerNative *manager_native) { } static void -meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass) +meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); - object_class->dispose = meta_monitor_manager_kms_dispose; - - manager_class->read_edid = meta_monitor_manager_kms_read_edid; - manager_class->read_current_state = meta_monitor_manager_kms_read_current_state; - manager_class->ensure_initial_config = meta_monitor_manager_kms_ensure_initial_config; - manager_class->apply_monitors_config = meta_monitor_manager_kms_apply_monitors_config; - manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode; - manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma; - manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma; - manager_class->is_transform_handled = meta_monitor_manager_kms_is_transform_handled; - manager_class->calculate_monitor_mode_scale = meta_monitor_manager_kms_calculate_monitor_mode_scale; - manager_class->calculate_supported_scales = meta_monitor_manager_kms_calculate_supported_scales; - manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities; - manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size; - manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode; + object_class->dispose = meta_monitor_manager_native_dispose; + + manager_class->read_edid = + meta_monitor_manager_native_read_edid; + manager_class->read_current_state = + meta_monitor_manager_native_read_current_state; + manager_class->ensure_initial_config = + meta_monitor_manager_native_ensure_initial_config; + manager_class->apply_monitors_config = + meta_monitor_manager_native_apply_monitors_config; + manager_class->set_power_save_mode = + meta_monitor_manager_native_set_power_save_mode; + manager_class->get_crtc_gamma = + meta_monitor_manager_native_get_crtc_gamma; + manager_class->set_crtc_gamma = + meta_monitor_manager_native_set_crtc_gamma; + manager_class->is_transform_handled = + meta_monitor_manager_native_is_transform_handled; + manager_class->calculate_monitor_mode_scale = + meta_monitor_manager_native_calculate_monitor_mode_scale; + manager_class->calculate_supported_scales = + meta_monitor_manager_native_calculate_supported_scales; + manager_class->get_capabilities = + meta_monitor_manager_native_get_capabilities; + manager_class->get_max_screen_size = + meta_monitor_manager_native_get_max_screen_size; + manager_class->get_default_layout_mode = + meta_monitor_manager_native_get_default_layout_mode; } diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-native.h similarity index 66% rename from src/backends/native/meta-monitor-manager-kms.h rename to src/backends/native/meta-monitor-manager-native.h index 3222d5a47f9..60f899734ad 100644 --- a/src/backends/native/meta-monitor-manager-kms.h +++ b/src/backends/native/meta-monitor-manager-native.h @@ -20,8 +20,8 @@ * along with this program; if not, see . */ -#ifndef META_MONITOR_MANAGER_KMS_H -#define META_MONITOR_MANAGER_KMS_H +#ifndef META_MONITOR_MANAGER_NATIVE_H +#define META_MONITOR_MANAGER_NATIVE_H #include #include @@ -32,18 +32,18 @@ typedef struct _MetaGpuKms MetaGpuKms; -#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ()) -G_DECLARE_FINAL_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, - META, MONITOR_MANAGER_KMS, +#define META_TYPE_MONITOR_MANAGER_NATIVE (meta_monitor_manager_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaMonitorManagerNative, meta_monitor_manager_native, + META, MONITOR_MANAGER_NATIVE, MetaMonitorManager) -void meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms); +void meta_monitor_manager_native_pause (MetaMonitorManagerNative *manager_native); -void meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms); +void meta_monitor_manager_native_resume (MetaMonitorManagerNative *manager_native); uint64_t meta_power_save_to_dpms_state (MetaPowerSave power_save); -MetaKmsCrtcGamma * meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms, - MetaCrtcKms *crtc_kms); +MetaKmsCrtcGamma * meta_monitor_manager_native_get_cached_crtc_gamma (MetaMonitorManagerNative *manager_native, + MetaCrtcKms *crtc_kms); -#endif /* META_MONITOR_MANAGER_KMS_H */ +#endif /* META_MONITOR_MANAGER_NATIVE_H */ diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 661736e7cbd..dd19eb01446 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -31,7 +31,7 @@ #include "backends/meta-renderer.h" #include "backends/native/meta-gpu-kms.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #define META_TYPE_RENDERER_NATIVE (meta_renderer_native_get_type ()) G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native, diff --git a/src/meson.build b/src/meson.build index 7ed0bfca0a2..30a08532596 100644 --- a/src/meson.build +++ b/src/meson.build @@ -670,8 +670,8 @@ if have_native_backend 'backends/native/meta-keymap-native.h', 'backends/native/meta-launcher.c', 'backends/native/meta-launcher.h', - 'backends/native/meta-monitor-manager-kms.c', - 'backends/native/meta-monitor-manager-kms.h', + 'backends/native/meta-monitor-manager-native.c', + 'backends/native/meta-monitor-manager-native.h', 'backends/native/meta-output-kms.c', 'backends/native/meta-output-kms.h', 'backends/native/meta-kms-connector-private.h', -- GitLab From fd4ea67b27aed07fcab1f498fbcd879dc1876834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 17 Dec 2020 22:31:28 +0100 Subject: [PATCH 03/38] native: Add abstract MetaOutputNative object MetaOutputKms is made to inherit from this, but it doesn't do anything special yet. Part-of: --- src/backends/native/meta-output-kms.c | 4 +-- src/backends/native/meta-output-kms.h | 3 +- src/backends/native/meta-output-native.c | 35 ++++++++++++++++++++++++ src/backends/native/meta-output-native.h | 35 ++++++++++++++++++++++++ src/meson.build | 2 ++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/backends/native/meta-output-native.c create mode 100644 src/backends/native/meta-output-native.h diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index d9055bb3ffe..b976c116dac 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -41,12 +41,12 @@ struct _MetaOutputKms { - MetaOutput parent; + MetaOutputNative parent; MetaKmsConnector *kms_connector; }; -G_DEFINE_TYPE (MetaOutputKms, meta_output_kms, META_TYPE_OUTPUT) +G_DEFINE_TYPE (MetaOutputKms, meta_output_kms, META_TYPE_OUTPUT_NATIVE) MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutputKms *output_kms) diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h index da7b0018548..f6443efa403 100644 --- a/src/backends/native/meta-output-kms.h +++ b/src/backends/native/meta-output-kms.h @@ -26,11 +26,12 @@ #include "backends/meta-output.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-kms-types.h" +#include "backends/native/meta-output-native.h" #define META_TYPE_OUTPUT_KMS (meta_output_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaOutputKms, meta_output_kms, META, OUTPUT_KMS, - MetaOutput) + MetaOutputNative) void meta_output_kms_set_power_save_mode (MetaOutputKms *output_kms, uint64_t dpms_state, diff --git a/src/backends/native/meta-output-native.c b/src/backends/native/meta-output-native.c new file mode 100644 index 00000000000..102c8152804 --- /dev/null +++ b/src/backends/native/meta-output-native.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-output-native.h" + +G_DEFINE_ABSTRACT_TYPE (MetaOutputNative, meta_output_native, + META_TYPE_OUTPUT) + +static void +meta_output_native_init (MetaOutputNative *output_native) +{ +} + +static void +meta_output_native_class_init (MetaOutputNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-output-native.h b/src/backends/native/meta-output-native.h new file mode 100644 index 00000000000..a93cbfd7f75 --- /dev/null +++ b/src/backends/native/meta-output-native.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_OUTPUT_NATIVE_H +#define META_OUTPUT_NATIVE_H + +#include "backends/meta-output.h" + +#define META_TYPE_OUTPUT_NATIVE (meta_output_native_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaOutputNative, meta_output_native, + META, OUTPUT_NATIVE, + MetaOutput) + +struct _MetaOutputNativeClass +{ + MetaOutputClass parent_class; +}; + +#endif /* META_OUTPUT_NATIVE_H */ diff --git a/src/meson.build b/src/meson.build index 30a08532596..705a7040704 100644 --- a/src/meson.build +++ b/src/meson.build @@ -674,6 +674,8 @@ if have_native_backend 'backends/native/meta-monitor-manager-native.h', 'backends/native/meta-output-kms.c', 'backends/native/meta-output-kms.h', + 'backends/native/meta-output-native.c', + 'backends/native/meta-output-native.h', 'backends/native/meta-kms-connector-private.h', 'backends/native/meta-kms-connector.c', 'backends/native/meta-kms-connector.h', -- GitLab From 074d4f3418168ee19c81ff767e60cc2248843b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 17 Dec 2020 22:48:28 +0100 Subject: [PATCH 04/38] output/kms: Make EDID be read via MetaOutputNative object Part-of: --- src/backends/native/meta-monitor-manager-native.c | 2 +- src/backends/native/meta-output-kms.c | 8 ++++++-- src/backends/native/meta-output-kms.h | 2 -- src/backends/native/meta-output-native.c | 8 ++++++++ src/backends/native/meta-output-native.h | 4 ++++ 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/backends/native/meta-monitor-manager-native.c b/src/backends/native/meta-monitor-manager-native.c index 9ba58992268..d0253d89ab8 100644 --- a/src/backends/native/meta-monitor-manager-native.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -89,7 +89,7 @@ static GBytes * meta_monitor_manager_native_read_edid (MetaMonitorManager *manager, MetaOutput *output) { - return meta_output_kms_read_edid (META_OUTPUT_KMS (output)); + return meta_output_native_read_edid (META_OUTPUT_NATIVE (output)); } static void diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index b976c116dac..eff8db5a9d4 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -110,9 +110,10 @@ meta_output_kms_can_clone (MetaOutputKms *output_kms, other_output_kms->kms_connector); } -GBytes * -meta_output_kms_read_edid (MetaOutputKms *output_kms) +static GBytes * +meta_output_kms_read_edid (MetaOutputNative *output_native) { + MetaOutputKms *output_kms = META_OUTPUT_KMS (output_native); const MetaKmsConnectorState *connector_state; GBytes *edid_data; @@ -387,4 +388,7 @@ meta_output_kms_init (MetaOutputKms *output_kms) static void meta_output_kms_class_init (MetaOutputKmsClass *klass) { + MetaOutputNativeClass *output_native_class = META_OUTPUT_NATIVE_CLASS (klass); + + output_native_class->read_edid = meta_output_kms_read_edid; } diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h index f6443efa403..52acc6032a0 100644 --- a/src/backends/native/meta-output-kms.h +++ b/src/backends/native/meta-output-kms.h @@ -47,8 +47,6 @@ MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutputKms *output_kms) uint32_t meta_output_kms_get_connector_id (MetaOutputKms *output_kms); -GBytes * meta_output_kms_read_edid (MetaOutputKms *output_kms); - MetaOutputKms * meta_output_kms_new (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, MetaOutput *old_output, diff --git a/src/backends/native/meta-output-native.c b/src/backends/native/meta-output-native.c index 102c8152804..f21b2ebc659 100644 --- a/src/backends/native/meta-output-native.c +++ b/src/backends/native/meta-output-native.c @@ -24,6 +24,14 @@ G_DEFINE_ABSTRACT_TYPE (MetaOutputNative, meta_output_native, META_TYPE_OUTPUT) +GBytes * +meta_output_native_read_edid (MetaOutputNative *output_native) +{ + MetaOutputNativeClass *klass = META_OUTPUT_NATIVE_GET_CLASS (output_native); + + return klass->read_edid (output_native); +} + static void meta_output_native_init (MetaOutputNative *output_native) { diff --git a/src/backends/native/meta-output-native.h b/src/backends/native/meta-output-native.h index a93cbfd7f75..f0475ae3bd8 100644 --- a/src/backends/native/meta-output-native.h +++ b/src/backends/native/meta-output-native.h @@ -30,6 +30,10 @@ G_DECLARE_DERIVABLE_TYPE (MetaOutputNative, meta_output_native, struct _MetaOutputNativeClass { MetaOutputClass parent_class; + + GBytes * (* read_edid) (MetaOutputNative *output_native); }; +GBytes * meta_output_native_read_edid (MetaOutputNative *output_native); + #endif /* META_OUTPUT_NATIVE_H */ -- GitLab From c4a422bc24e4e20fd02528a2d4dabc84cc126e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 14 Jan 2021 11:15:53 +0100 Subject: [PATCH 05/38] crtc/kms: Add an abstract MetaCrtcNative that sits under MetaCrtcKms There is going to me another non-abstract MetaCrtcNative type, just as there will be for MetaOutputNative. Part-of: --- src/backends/native/meta-crtc-kms.c | 4 +-- src/backends/native/meta-crtc-kms.h | 3 ++- src/backends/native/meta-crtc-native.c | 35 ++++++++++++++++++++++++++ src/backends/native/meta-crtc-native.h | 35 ++++++++++++++++++++++++++ src/meson.build | 2 ++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/backends/native/meta-crtc-native.c create mode 100644 src/backends/native/meta-crtc-native.h diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 02b4999bf38..fb38e4d6723 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -40,7 +40,7 @@ struct _MetaCrtcKms { - MetaCrtc parent; + MetaCrtcNative parent; MetaKmsCrtc *kms_crtc; @@ -54,7 +54,7 @@ struct _MetaCrtcKms static GQuark kms_crtc_crtc_kms_quark; -G_DEFINE_TYPE (MetaCrtcKms, meta_crtc_kms, META_TYPE_CRTC) +G_DEFINE_TYPE (MetaCrtcKms, meta_crtc_kms, META_TYPE_CRTC_NATIVE) gpointer meta_crtc_kms_get_cursor_renderer_private (MetaCrtcKms *crtc_kms) diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index 8c4df1fad03..df957be15cc 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -28,6 +28,7 @@ #include "backends/meta-backend-types.h" #include "backends/meta-crtc.h" +#include "backends/native/meta-crtc-native.h" #include "backends/native/meta-drm-buffer.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-kms-crtc.h" @@ -36,7 +37,7 @@ #define META_TYPE_CRTC_KMS (meta_crtc_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaCrtcKms, meta_crtc_kms, META, CRTC_KMS, - MetaCrtc) + MetaCrtcNative) gpointer meta_crtc_kms_get_cursor_renderer_private (MetaCrtcKms *crtc_kms); diff --git a/src/backends/native/meta-crtc-native.c b/src/backends/native/meta-crtc-native.c new file mode 100644 index 00000000000..3a0e7a95216 --- /dev/null +++ b/src/backends/native/meta-crtc-native.c @@ -0,0 +1,35 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-crtc-native.h" + +G_DEFINE_ABSTRACT_TYPE (MetaCrtcNative, meta_crtc_native, + META_TYPE_CRTC) + +static void +meta_crtc_native_init (MetaCrtcNative *crtc_native) +{ +} + +static void +meta_crtc_native_class_init (MetaCrtcNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-crtc-native.h b/src/backends/native/meta-crtc-native.h new file mode 100644 index 00000000000..61ea15be31c --- /dev/null +++ b/src/backends/native/meta-crtc-native.h @@ -0,0 +1,35 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_CRTC_NATIVE_H +#define META_CRTC_NATIVE_H + +#include "backends/meta-crtc.h" + +#define META_TYPE_CRTC_NATIVE (meta_crtc_native_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaCrtcNative, meta_crtc_native, + META, CRTC_NATIVE, + MetaCrtc) + +struct _MetaCrtcNativeClass +{ + MetaCrtcClass parent_class; +}; + +#endif /* META_CRTC_NATIVE_H */ diff --git a/src/meson.build b/src/meson.build index 705a7040704..dc968ad2ef2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -645,6 +645,8 @@ if have_native_backend 'backends/native/meta-cogl-utils.h', 'backends/native/meta-crtc-kms.c', 'backends/native/meta-crtc-kms.h', + 'backends/native/meta-crtc-native.c', + 'backends/native/meta-crtc-native.h', 'backends/native/meta-crtc-mode-kms.c', 'backends/native/meta-crtc-mode-kms.h', 'backends/native/meta-cursor-renderer-native.c', -- GitLab From 7c25953c65ffc2c81c481e501046777df5372e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 18 Jan 2021 18:27:07 +0100 Subject: [PATCH 06/38] kms/impl-device: Make non-abstract types explicitly init mode setting This is a step towards making it possible to add a MetaKmsImplDevice that doesn't actually do any mode setting. Part-of: --- .../native/meta-kms-impl-device-atomic.c | 25 +++++++++++++++++-- .../native/meta-kms-impl-device-simple.c | 6 +---- src/backends/native/meta-kms-impl-device.c | 21 +++------------- src/backends/native/meta-kms-impl-device.h | 3 +++ 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index a7c219ef365..d2da354d375 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -44,8 +44,13 @@ struct _MetaKmsImplDeviceAtomic GHashTable *page_flip_datas; }; -G_DEFINE_TYPE (MetaKmsImplDeviceAtomic, meta_kms_impl_device_atomic, - META_TYPE_KMS_IMPL_DEVICE) +static void +initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDeviceAtomic, meta_kms_impl_device_atomic, + META_TYPE_KMS_IMPL_DEVICE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_iface_init)) static uint32_t store_new_blob (MetaKmsImplDevice *impl_device, @@ -1006,6 +1011,16 @@ meta_kms_impl_device_atomic_finalize (GObject *object) G_OBJECT_CLASS (meta_kms_impl_device_atomic_parent_class)->finalize (object); } +static gboolean +meta_kms_impl_device_atomic_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); + + return meta_kms_impl_device_init_mode_setting (impl_device, error); +} + static void meta_kms_impl_device_atomic_init (MetaKmsImplDeviceAtomic *impl_device_atomic) { @@ -1015,6 +1030,12 @@ meta_kms_impl_device_atomic_init (MetaKmsImplDeviceAtomic *impl_device_atomic) (GDestroyNotify) meta_kms_page_flip_data_unref); } +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = meta_kms_impl_device_atomic_initable_init; +} + static void meta_kms_impl_device_atomic_class_init (MetaKmsImplDeviceAtomicClass *klass) { diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index 99c09a68772..07f80c21f81 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -58,8 +58,6 @@ struct _MetaKmsImplDeviceSimple GHashTable *cached_mode_sets; }; -static GInitableIface *initable_parent_iface; - static void initable_iface_init (GInitableIface *iface); @@ -1507,7 +1505,7 @@ meta_kms_impl_device_simple_initable_init (GInitable *initable, MetaKmsDevice *device = meta_kms_impl_device_get_device (impl_device); GList *l; - if (!initable_parent_iface->init (initable, cancellable, error)) + if (!meta_kms_impl_device_init_mode_setting (impl_device, error)) return FALSE; impl_device_simple->cached_mode_sets = @@ -1546,8 +1544,6 @@ meta_kms_impl_device_simple_init (MetaKmsImplDeviceSimple *impl_device_simple) static void initable_iface_init (GInitableIface *iface) { - initable_parent_iface = g_type_interface_peek_parent (iface); - iface->init = meta_kms_impl_device_simple_initable_init; } diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index b2f1c3f1119..1f72de75b54 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -75,14 +75,9 @@ typedef struct _MetaKmsImplDevicePrivate GList *fallback_modes; } MetaKmsImplDevicePrivate; -static void -initable_iface_init (GInitableIface *iface); - G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDevice, meta_kms_impl_device, G_TYPE_OBJECT, - G_ADD_PRIVATE (MetaKmsImplDevice) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_iface_init)) + G_ADD_PRIVATE (MetaKmsImplDevice)) MetaKmsDevice * meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device) @@ -786,12 +781,10 @@ meta_kms_impl_device_finalize (GObject *object) G_OBJECT_CLASS (meta_kms_impl_device_parent_class)->finalize (object); } -static gboolean -meta_kms_impl_device_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +gboolean +meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, + GError **error) { - MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); MetaKmsImplDevicePrivate *priv = meta_kms_impl_device_get_instance_private (impl_device); drmModeRes *drm_resources; @@ -829,12 +822,6 @@ meta_kms_impl_device_init (MetaKmsImplDevice *device) { } -static void -initable_iface_init (GInitableIface *initable_iface) -{ - initable_iface->init = meta_kms_impl_device_initable_init; -} - static void meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass) { diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index a3d31daebf6..5b3585aa78d 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -140,4 +140,7 @@ void meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_de int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device); +gboolean meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, + GError **error); + #endif /* META_KMS_IMPL_DEVICE_H */ -- GitLab From 34b0f9c12427598e5ce537271c58c0ef50aa0c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 18 Jan 2021 18:30:02 +0100 Subject: [PATCH 07/38] kms/device: Move universal plane cap check to mode set init This leaves only the atomic mode setting cap check before creating the impl device, aiming to make it possible to create a non-mode-setting MetaKmsImplDevice implementation. Part-of: --- src/backends/native/meta-kms-device.c | 12 ++---------- src/backends/native/meta-kms-impl-device.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index b5b50d602c4..9084d248fe6 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -281,22 +281,12 @@ meta_create_kms_impl_device (MetaKmsDevice *device, { GType impl_device_type; gboolean supports_atomic_mode_setting; - int ret; g_autofree char *driver_name = NULL; g_autofree char *driver_description = NULL; const char *atomic_kms_enable_env; meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); - ret = drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - if (ret != 0) - { - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), - "Failed to activate universal planes: %s", - g_strerror (-ret)); - return NULL; - } - if (!get_driver_info (fd, &driver_name, &driver_description)) { driver_name = g_strdup ("unknown"); @@ -340,6 +330,8 @@ meta_create_kms_impl_device (MetaKmsDevice *device, } else { + int ret; + ret = drmSetClientCap (fd, DRM_CLIENT_CAP_ATOMIC, 1); if (ret == 0) supports_atomic_mode_setting = TRUE; diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 1f72de75b54..f2a000fd1aa 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -787,8 +787,18 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, { MetaKmsImplDevicePrivate *priv = meta_kms_impl_device_get_instance_private (impl_device); + int ret; drmModeRes *drm_resources; + ret = drmSetClientCap (priv->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "Failed to activate universal planes: %s", + g_strerror (-ret)); + return FALSE; + } + drm_resources = drmModeGetResources (priv->fd); if (!drm_resources) { -- GitLab From 59a10cd18827100643804299874b35db31425943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 18 Jan 2021 22:34:04 +0100 Subject: [PATCH 08/38] monitor-manager/native: Allow starting without outputs when headless This will allow starting, then adding virtual outputs when needed e.g. via the screen cast API. Part-of: --- src/backends/native/meta-backend-native.c | 2 + .../native/meta-monitor-manager-native.c | 48 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index ebd8570d07e..45fb7b421dd 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -212,10 +212,12 @@ static MetaMonitorManager * meta_backend_native_create_monitor_manager (MetaBackend *backend, GError **error) { + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaMonitorManager *manager; manager = g_initable_new (META_TYPE_MONITOR_MANAGER_NATIVE, NULL, error, "backend", backend, + "needs-outputs", !backend_native->is_headless, NULL); if (!manager) return NULL; diff --git a/src/backends/native/meta-monitor-manager-native.c b/src/backends/native/meta-monitor-manager-native.c index d0253d89ab8..30a15350619 100644 --- a/src/backends/native/meta-monitor-manager-native.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -63,6 +63,17 @@ #include "meta/main.h" #include "meta/meta-x11-errors.h" +enum +{ + PROP_0, + + PROP_NEED_OUTPUTS, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + struct _MetaMonitorManagerNative { MetaMonitorManager parent_instance; @@ -70,6 +81,8 @@ struct _MetaMonitorManagerNative gulong kms_resources_changed_handler_id; GHashTable *crtc_gamma_cache; + + gboolean needs_outputs; }; struct _MetaMonitorManagerNativeClass @@ -588,6 +601,26 @@ meta_monitor_manager_native_get_default_layout_mode (MetaMonitorManager *manager return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; } +static void +meta_monitor_manager_native_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (object); + + switch (prop_id) + { + case PROP_NEED_OUTPUTS: + manager_native->needs_outputs = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void meta_monitor_manager_native_dispose (GObject *object) { @@ -625,7 +658,8 @@ meta_monitor_manager_native_initable_init (GInitable *initable, break; } } - if (!can_have_outputs) + + if (manager_native->needs_outputs && !can_have_outputs) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No GPUs with outputs found"); @@ -649,6 +683,7 @@ initable_iface_init (GInitableIface *initable_iface) static void meta_monitor_manager_native_init (MetaMonitorManagerNative *manager_native) { + manager_native->needs_outputs = TRUE; } static void @@ -657,6 +692,7 @@ meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + object_class->set_property = meta_monitor_manager_native_set_property; object_class->dispose = meta_monitor_manager_native_dispose; manager_class->read_edid = @@ -685,4 +721,14 @@ meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) meta_monitor_manager_native_get_max_screen_size; manager_class->get_default_layout_mode = meta_monitor_manager_native_get_default_layout_mode; + + obj_props[PROP_NEED_OUTPUTS] = + g_param_spec_boolean ("needs-outputs", + "needs-outputs", + "Whether any outputs are needed for operation", + TRUE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); } -- GitLab From 0786f44b0be5719bbddb8776f246ed79337d4c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 11:47:59 +0100 Subject: [PATCH 09/38] seat/impl: Make it possible to run without libinput Add a flag to MetaSeatNative and MetaSeatImpl that tells it not to attempt to create a libinput context. This is intended to be used when mutter is to run headless, as in without any input devices other than virtual ones. Currently not hooked up. Part-of: --- .../native/meta-backend-native-types.h | 6 ++ src/backends/native/meta-seat-impl.c | 93 +++++++++++++------ src/backends/native/meta-seat-impl.h | 6 +- src/backends/native/meta-seat-native.c | 20 +++- src/backends/native/meta-seat-native.h | 1 + src/meson.build | 20 +++- 6 files changed, 113 insertions(+), 33 deletions(-) diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h index 0668a84e4f1..3efbca9ca43 100644 --- a/src/backends/native/meta-backend-native-types.h +++ b/src/backends/native/meta-backend-native-types.h @@ -28,4 +28,10 @@ typedef struct _MetaKeymapNative MetaKeymapNative; typedef struct _MetaRendererNative MetaRendererNative; typedef struct _MetaGpuKms MetaGpuKms; +typedef enum _MetaSeatNativeFlag +{ + META_SEAT_NATIVE_FLAG_NONE = 0, + META_SEAT_NATIVE_FLAG_NO_LIBINPUT = 1 << 0, +} MetaSeatNativeFlag; + #endif /* META_BACKEND_NATIVE_TYPES_H */ diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c index 71da8f8fac3..a67698ce15f 100644 --- a/src/backends/native/meta-seat-impl.c +++ b/src/backends/native/meta-seat-impl.c @@ -40,6 +40,8 @@ #include "clutter/clutter-mutter.h" #include "core/bell.h" +#include "meta-private-enum-types.h" + /* * Clutter makes the assumption that two core devices have ID's 2 and 3 (core * pointer and core keyboard). @@ -96,6 +98,7 @@ enum PROP_0, PROP_SEAT, PROP_SEAT_ID, + PROP_FLAGS, N_PROPS, }; @@ -259,9 +262,12 @@ keyboard_repeat (gpointer data) /* There might be events queued in libinput that could cancel the repeat timer. */ - dispatch_libinput (seat_impl); - if (!seat_impl->repeat_source) - return G_SOURCE_REMOVE; + if (seat_impl->libinput) + { + dispatch_libinput (seat_impl); + if (!seat_impl->repeat_source) + return G_SOURCE_REMOVE; + } g_return_val_if_fail (seat_impl->repeat_device != NULL, G_SOURCE_REMOVE); @@ -2654,50 +2660,71 @@ meta_seat_impl_set_keyboard_numlock_in_impl (MetaSeatImpl *seat_impl, seat_impl->xkb); } -static gpointer -input_thread (MetaSeatImpl *seat_impl) +static gboolean +init_libinput (MetaSeatImpl *seat_impl, + GError **error) { MetaEventSource *source; struct udev *udev; - struct xkb_keymap *xkb_keymap; - - g_main_context_push_thread_default (seat_impl->input_context); + struct libinput *libinput; udev = udev_new (); if (G_UNLIKELY (udev == NULL)) { g_warning ("Failed to create udev object"); seat_impl->input_thread_initialized = TRUE; - return NULL; + return FALSE; } - seat_impl->libinput = libinput_udev_create_context (&libinput_interface, - seat_impl, udev); - if (seat_impl->libinput == NULL) + libinput = libinput_udev_create_context (&libinput_interface, + seat_impl, udev); + udev_unref (udev); + + if (libinput == NULL) { - g_critical ("Failed to create the libinput object."); - seat_impl->input_thread_initialized = TRUE; - return NULL; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to create the libinput object."); + return FALSE; } - if (libinput_udev_assign_seat (seat_impl->libinput, seat_impl->seat_id) == -1) + if (libinput_udev_assign_seat (libinput, seat_impl->seat_id) == -1) { - g_critical ("Failed to assign a seat to the libinput object."); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to assign a seat to the libinput object."); libinput_unref (seat_impl->libinput); - seat_impl->libinput = NULL; - seat_impl->input_thread_initialized = TRUE; - return NULL; + return FALSE; } - udev_unref (udev); + seat_impl->libinput = libinput; + source = meta_event_source_new (seat_impl); + seat_impl->event_source = source; + + return TRUE; +} + +static gpointer +input_thread (MetaSeatImpl *seat_impl) +{ + struct xkb_keymap *xkb_keymap; + + g_main_context_push_thread_default (seat_impl->input_context); + + if (!(seat_impl->flags & META_SEAT_NATIVE_FLAG_NO_LIBINPUT)) + { + g_autoptr (GError) error = NULL; + + if (!init_libinput (seat_impl, &error)) + { + g_critical ("Failed to initialize seat: %s", error->message); + seat_impl->input_thread_initialized = TRUE; + return NULL; + } + } seat_impl->input_settings = meta_input_settings_native_new_in_impl (seat_impl); g_signal_connect_object (seat_impl->input_settings, "kbd-a11y-changed", G_CALLBACK (kbd_a11y_changed_cb), seat_impl, 0); - source = meta_event_source_new (seat_impl); - seat_impl->event_source = source; - seat_impl->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL); xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap); @@ -2804,6 +2831,9 @@ meta_seat_impl_set_property (GObject *object, case PROP_SEAT_ID: seat_impl->seat_id = g_value_dup_string (value); break; + case PROP_FLAGS: + seat_impl->flags = g_value_get_flags (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -3050,6 +3080,15 @@ meta_seat_impl_class_init (MetaSeatImplClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags", + META_TYPE_SEAT_NATIVE_FLAG, + META_SEAT_NATIVE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + signals[KBD_A11Y_FLAGS_CHANGED] = g_signal_new ("kbd-a11y-flags-changed", G_TYPE_FROM_CLASS (object_class), @@ -3462,13 +3501,15 @@ meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl, } MetaSeatImpl * -meta_seat_impl_new (MetaSeatNative *seat_native, - const char *seat_id) +meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id, + MetaSeatNativeFlag flags) { return g_initable_new (META_TYPE_SEAT_IMPL, NULL, NULL, "seat", seat_native, "seat-id", seat_id, + "flags", flags, NULL); } diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h index d49d1660f51..eed122f6c50 100644 --- a/src/backends/native/meta-seat-impl.h +++ b/src/backends/native/meta-seat-impl.h @@ -67,6 +67,7 @@ struct _MetaSeatImpl MetaSeatNative *seat_native; char *seat_id; + MetaSeatNativeFlag flags; MetaEventSource *event_source; struct libinput *libinput; GRWLock state_lock; @@ -126,8 +127,9 @@ struct _MetaSeatImpl G_DECLARE_FINAL_TYPE (MetaSeatImpl, meta_seat_impl, META, SEAT_IMPL, GObject) -MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat_native, - const char *seat_id); +MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id, + MetaSeatNativeFlag flags); void meta_seat_impl_destroy (MetaSeatImpl *seat_impl); diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c index c0bfe222332..133bf58fe10 100644 --- a/src/backends/native/meta-seat-native.c +++ b/src/backends/native/meta-seat-native.c @@ -37,10 +37,13 @@ #include "clutter/clutter-mutter.h" #include "core/bell.h" +#include "meta-private-enum-types.h" + enum { PROP_0, PROP_SEAT_ID, + PROP_FLAGS, N_PROPS, /* This property is overridden */ @@ -153,7 +156,7 @@ meta_seat_native_constructed (GObject *object) { MetaSeatNative *seat = META_SEAT_NATIVE (object); - seat->impl = meta_seat_impl_new (seat, seat->seat_id); + seat->impl = meta_seat_impl_new (seat, seat->seat_id, seat->flags); g_signal_connect (seat->impl, "kbd-a11y-flags-changed", G_CALLBACK (proxy_kbd_a11y_flags_changed), seat); g_signal_connect (seat->impl, "kbd-a11y-mods-state-changed", @@ -187,6 +190,9 @@ meta_seat_native_set_property (GObject *object, case PROP_SEAT_ID: seat_native->seat_id = g_value_dup_string (value); break; + case PROP_FLAGS: + seat_native->flags = g_value_get_flags (value); + break; case PROP_TOUCH_MODE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -209,6 +215,9 @@ meta_seat_native_get_property (GObject *object, case PROP_TOUCH_MODE: g_value_set_boolean (value, seat_native->touch_mode); break; + case PROP_FLAGS: + g_value_set_flags (value, seat_native->flags); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -393,6 +402,15 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags", + META_TYPE_SEAT_NATIVE_FLAG, + META_SEAT_NATIVE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_properties (object_class, N_PROPS, props); g_object_class_override_property (object_class, PROP_TOUCH_MODE, diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h index 7f94828d0e0..dca2679863a 100644 --- a/src/backends/native/meta-seat-native.h +++ b/src/backends/native/meta-seat-native.h @@ -44,6 +44,7 @@ struct _MetaSeatNative MetaSeatImpl *impl; char *seat_id; + MetaSeatNativeFlag flags; GList *devices; struct xkb_keymap *xkb_keymap; diff --git a/src/meson.build b/src/meson.build index dc968ad2ef2..196abf71f45 100644 --- a/src/meson.build +++ b/src/meson.build @@ -744,13 +744,25 @@ if have_wayland_eglstream ] endif -mutter_built_sources = [] +mutter_private_enum_sources = [] if have_remote_desktop + mutter_private_enum_sources += [ + 'backends/meta-screen-cast.h', + ] +endif + +if have_native_backend + mutter_private_enum_sources += [ + 'backends/native/meta-backend-native-types.h', + ] +endif + +mutter_built_sources = [] + +if mutter_private_enum_sources.length() > 0 mutter_private_enum_types = gnome.mkenums('meta-private-enum-types', - sources: [ - 'backends/meta-screen-cast.h', - ], + sources: mutter_private_enum_sources, c_template: 'meta-private-enum-types.c.in', h_template: 'meta-private-enum-types.h.in', ) -- GitLab From 739283d396e21e06656d2e088bcb95ef4c7bb08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 11:50:52 +0100 Subject: [PATCH 10/38] backend/native: Add getter for is-headless state Will be used to determine how to run subsystems. Part-of: --- src/backends/native/meta-backend-native.c | 6 ++++++ src/backends/native/meta-backend-native.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 45fb7b421dd..8f916642e0c 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -335,6 +335,12 @@ meta_backend_native_get_seat_id (MetaBackendNative *backend_native) return meta_launcher_get_seat_id (backend_native->launcher); } +gboolean +meta_backend_native_is_headless (MetaBackendNative *backend_native) +{ + return backend_native->is_headless; +} + static void meta_backend_native_set_pointer_constraint (MetaBackend *backend, MetaPointerConstraint *constraint) diff --git a/src/backends/native/meta-backend-native.h b/src/backends/native/meta-backend-native.h index b0d82d0161b..0c7df66db8f 100644 --- a/src/backends/native/meta-backend-native.h +++ b/src/backends/native/meta-backend-native.h @@ -49,4 +49,6 @@ MetaKms * meta_backend_native_get_kms (MetaBackendNative *native); const char * meta_backend_native_get_seat_id (MetaBackendNative *backend_native); +gboolean meta_backend_native_is_headless (MetaBackendNative *backend_native); + #endif /* META_BACKEND_NATIVE_H */ -- GitLab From ee4e78b1002d30654ad439b0d227cca39edceaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 14:54:45 +0100 Subject: [PATCH 11/38] kms: Add way to run without mode setting Currently our only entry point for DRM devices is MetaKms*, but in order to run without being DRM master, we cannot use /dev/dri/card*, nor can we be either of the existing MetaKmsImplDevice implementation (legacy KMS, and atomic KMS), as they both depend on being DRM master. Thus to handle running without being DRM master (i.e. headless), add a "dummy" MetaKmsImplDevice implementation, that doesn't do any mode setting at all, and that switches to operate on the render node, instead of the card node itself. This means we still use the same GBM code paths as the regular native backend paths, except we never make use of any CRTC backed onscreen framebuffers. Eventually, this "dummy" MetaKmsImplDevice will be replaced separating "KMS" device objects from "render" device objects, but that will require more significant changes. It will, however, be necessary for e.g. going from being headless, only having access to a render node, to turning into a real session, with a seat, being DRM master, and having access to a card node. This is currently not hooked up, but will be in a later commit. Part-of: --- src/backends/native/meta-backend-native.c | 4 +- src/backends/native/meta-kms-device.c | 119 +++++++++++++++--- .../native/meta-kms-impl-device-dummy.c | 69 ++++++++++ .../native/meta-kms-impl-device-dummy.h | 30 +++++ src/backends/native/meta-kms-impl-device.c | 18 +++ src/backends/native/meta-kms-types.h | 1 + src/backends/native/meta-kms.c | 19 ++- src/backends/native/meta-kms.h | 11 +- src/meson.build | 3 + 9 files changed, 248 insertions(+), 26 deletions(-) create mode 100644 src/backends/native/meta-kms-impl-device-dummy.c create mode 100644 src/backends/native/meta-kms-impl-device-dummy.h diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 8f916642e0c..eb43a54ec53 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -531,7 +531,9 @@ meta_backend_native_initable_init (GInitable *initable, native->udev = meta_udev_new (native); - native->kms = meta_kms_new (META_BACKEND (native), error); + native->kms = meta_kms_new (META_BACKEND (native), + META_KMS_FLAG_NONE, + error); if (!native->kms) return FALSE; diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index 9084d248fe6..c388096d593 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -23,10 +23,14 @@ #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device.h" +#include +#include +#include #include #include "backends/native/meta-backend-native.h" #include "backends/native/meta-kms-impl-device-atomic.h" +#include "backends/native/meta-kms-impl-device-dummy.h" #include "backends/native/meta-kms-impl-device-simple.h" #include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl.h" @@ -227,6 +231,7 @@ typedef struct _CreateImplDeviceData MetaKmsDevice *device; int fd; const char *path; + MetaKmsDeviceFlag flags; MetaKmsImplDevice *out_impl_device; GList *out_crtcs; @@ -236,6 +241,7 @@ typedef struct _CreateImplDeviceData GList *out_fallback_modes; char *out_driver_name; char *out_driver_description; + char *out_path; } CreateImplDeviceData; static gboolean @@ -273,17 +279,21 @@ get_driver_info (int fd, } static MetaKmsImplDevice * -meta_create_kms_impl_device (MetaKmsDevice *device, - MetaKmsImpl *impl, - int fd, - const char *path, - GError **error) +meta_create_kms_impl_device (MetaKmsDevice *device, + MetaKmsImpl *impl, + int fd, + const char *path, + MetaKmsDeviceFlag flags, + GError **error) { GType impl_device_type; gboolean supports_atomic_mode_setting; g_autofree char *driver_name = NULL; g_autofree char *driver_description = NULL; const char *atomic_kms_enable_env; + int impl_fd; + g_autofree char *impl_path = NULL; + MetaKmsImplDevice *impl_device; meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); @@ -294,7 +304,36 @@ meta_create_kms_impl_device (MetaKmsDevice *device, } atomic_kms_enable_env = getenv ("MUTTER_DEBUG_ENABLE_ATOMIC_KMS"); - if (atomic_kms_enable_env) + + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + { + g_autofree char *render_node_path = NULL; + + render_node_path = drmGetRenderDeviceNameFromFd (fd); + if (!render_node_path) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Couldn't find render node device for '%s' (%s)", + path, driver_name); + return NULL; + } + + impl_fd = open (render_node_path, O_RDWR | O_CLOEXEC, 0); + if (impl_fd == -1) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to open render node '%s': %s", + render_node_path, g_strerror (errno)); + return NULL; + } + + g_message ("Adding device '%s' (from '%s', %s) using no mode setting.", + render_node_path, path, driver_name); + + impl_path = g_steal_pointer (&render_node_path); + impl_device_type = META_TYPE_KMS_IMPL_DEVICE_DUMMY; + } + else if (atomic_kms_enable_env) { if (g_strcmp0 (atomic_kms_enable_env, "1") == 0) { @@ -316,6 +355,9 @@ meta_create_kms_impl_device (MetaKmsDevice *device, atomic_kms_enable_env); } + impl_fd = dup (fd); + impl_path = g_strdup (path); + g_message ("Mode setting implementation for '%s' (%s) forced (%s).", path, driver_name, impl_device_type == META_TYPE_KMS_IMPL_DEVICE_ATOMIC ? @@ -326,6 +368,8 @@ meta_create_kms_impl_device (MetaKmsDevice *device, g_message ("Adding device '%s' (%s) using non-atomic mode setting" " (using atomic mode setting not allowed).", path, driver_name); + impl_fd = dup (fd); + impl_path = g_strdup (path); impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE; } else @@ -350,16 +394,29 @@ meta_create_kms_impl_device (MetaKmsDevice *device, path, driver_name); impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE; } + + impl_fd = dup (fd); + impl_path = g_strdup (path); + } + + impl_device = g_initable_new (impl_device_type, NULL, error, + "device", device, + "impl", impl, + "fd", impl_fd, + "path", impl_path, + "flags", flags, + "driver-name", driver_name, + "driver-description", driver_description, + NULL); + if (!impl_device) + { + close (impl_fd); + return NULL; } - return g_initable_new (impl_device_type, NULL, error, - "device", device, - "impl", impl, - "fd", fd, - "path", path, - "driver-name", driver_name, - "driver-description", driver_description, - NULL); + close (fd); + + return impl_device; } static gpointer @@ -374,6 +431,7 @@ create_impl_device_in_impl (MetaKmsImpl *impl, impl, data->fd, data->path, + data->flags, error); if (!impl_device) return FALSE; @@ -391,6 +449,7 @@ create_impl_device_in_impl (MetaKmsImpl *impl, g_strdup (meta_kms_impl_device_get_driver_name (impl_device)); data->out_driver_description = g_strdup (meta_kms_impl_device_get_driver_description (impl_device)); + data->out_path = g_strdup (meta_kms_impl_device_get_path (impl_device)); return GINT_TO_POINTER (TRUE); } @@ -408,9 +467,22 @@ meta_kms_device_new (MetaKms *kms, CreateImplDeviceData data; int fd; - fd = meta_launcher_open_restricted (launcher, path, error); - if (fd == -1) - return NULL; + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + { + fd = open (path, O_RDWR | O_CLOEXEC, 0); + if (fd == -1) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to open DRM device: %s", g_strerror (errno)); + return NULL; + } + } + else + { + fd = meta_launcher_open_restricted (launcher, path, error); + if (fd == -1) + return NULL; + } device = g_object_new (META_TYPE_KMS_DEVICE, NULL); device->kms = kms; @@ -419,11 +491,15 @@ meta_kms_device_new (MetaKms *kms, .device = device, .fd = fd, .path = path, + .flags = flags, }; if (!meta_kms_run_impl_task_sync (kms, create_impl_device_in_impl, &data, error)) { - meta_launcher_close_restricted (launcher, fd); + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + close (fd); + else + meta_launcher_close_restricted (launcher, fd); g_object_unref (device); return NULL; } @@ -438,6 +514,8 @@ meta_kms_device_new (MetaKms *kms, device->fallback_modes = data.out_fallback_modes; device->driver_name = data.out_driver_name; device->driver_description = data.out_driver_description; + free (device->path); + device->path = data.out_path; return device; } @@ -495,7 +573,10 @@ meta_kms_device_finalize (GObject *object) } else { - meta_launcher_close_restricted (launcher, data.out_fd); + if (device->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + close (data.out_fd); + else + meta_launcher_close_restricted (launcher, data.out_fd); } } G_OBJECT_CLASS (meta_kms_device_parent_class)->finalize (object); diff --git a/src/backends/native/meta-kms-impl-device-dummy.c b/src/backends/native/meta-kms-impl-device-dummy.c new file mode 100644 index 00000000000..c1a0a44307f --- /dev/null +++ b/src/backends/native/meta-kms-impl-device-dummy.c @@ -0,0 +1,69 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-kms-impl-device-dummy.h" + +struct _MetaKmsImplDeviceDummy +{ + MetaKmsImplDevice parent; +}; + +static void +initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy, + META_TYPE_KMS_IMPL_DEVICE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_iface_init)) + +static void +meta_kms_impl_device_dummy_discard_pending_page_flips (MetaKmsImplDevice *impl) +{ +} + +static void +meta_kms_impl_device_dummy_init (MetaKmsImplDeviceDummy *impl_device_dummy) +{ +} + +static gboolean +meta_kms_impl_device_dummy_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} + +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = meta_kms_impl_device_dummy_initable_init; +} + +static void +meta_kms_impl_device_dummy_class_init (MetaKmsImplDeviceDummyClass *klass) +{ + MetaKmsImplDeviceClass *impl_device_class = + META_KMS_IMPL_DEVICE_CLASS (klass); + + impl_device_class->discard_pending_page_flips = + meta_kms_impl_device_dummy_discard_pending_page_flips; +} diff --git a/src/backends/native/meta-kms-impl-device-dummy.h b/src/backends/native/meta-kms-impl-device-dummy.h new file mode 100644 index 00000000000..9576939ad89 --- /dev/null +++ b/src/backends/native/meta-kms-impl-device-dummy.h @@ -0,0 +1,30 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_KMS_IMPL_DEVICE_DUMMY_H +#define META_KMS_IMPL_DEVICE_DUMMY_H + +#include "backends/native/meta-kms-impl-device.h" + +#define META_TYPE_KMS_IMPL_DEVICE_DUMMY (meta_kms_impl_device_dummy_get_type ()) +G_DECLARE_FINAL_TYPE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy, + META, KMS_IMPL_DEVICE_DUMMY, + MetaKmsImplDevice) + +#endif /* META_KMS_IMPL_DEVICE_DUMMY_H */ diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index f2a000fd1aa..d0247ef71f9 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -37,6 +37,7 @@ #include "backends/native/meta-kms-update.h" #include "meta-default-modes.h" +#include "meta-private-enum-types.h" enum { @@ -46,6 +47,7 @@ enum PROP_IMPL, PROP_FD, PROP_PATH, + PROP_FLAGS, PROP_DRIVER_NAME, PROP_DRIVER_DESCRIPTION, @@ -62,6 +64,7 @@ typedef struct _MetaKmsImplDevicePrivate int fd; GSource *fd_source; char *path; + MetaKmsDeviceFlag flags; char *driver_name; char *driver_description; @@ -712,6 +715,9 @@ meta_kms_impl_device_get_property (GObject *object, case PROP_PATH: g_value_set_string (value, priv->path); break; + case PROP_FLAGS: + g_value_set_flags (value, priv->flags); + break; case PROP_DRIVER_NAME: g_value_set_string (value, priv->driver_name); break; @@ -748,6 +754,9 @@ meta_kms_impl_device_set_property (GObject *object, case PROP_PATH: priv->path = g_value_dup_string (value); break; + case PROP_FLAGS: + priv->flags = g_value_get_flags (value); + break; case PROP_DRIVER_NAME: priv->driver_name = g_value_dup_string (value); break; @@ -873,6 +882,15 @@ meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "flags", + "KMS impl device flags", + META_TYPE_KMS_DEVICE_FLAG, + META_KMS_DEVICE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_props[PROP_DRIVER_NAME] = g_param_spec_string ("driver-name", "driver-name", diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index cf1adc44efd..01db55a4029 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -61,6 +61,7 @@ typedef enum _MetaKmsDeviceFlag META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1, META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS = 1 << 2, META_KMS_DEVICE_FLAG_PREFERRED_PRIMARY = 1 << 3, + META_KMS_DEVICE_FLAG_NO_MODE_SETTING = 1 << 4, } MetaKmsDeviceFlag; typedef enum _MetaKmsPlaneType MetaKmsPlaneType; diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index ee77975bd46..6514f89f6ea 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -158,6 +158,8 @@ struct _MetaKms { GObject parent; + MetaKmsFlags flags; + MetaBackend *backend; gulong hotplug_handler_id; @@ -614,6 +616,9 @@ meta_kms_create_device (MetaKms *kms, { MetaKmsDevice *device; + if (kms->flags & META_KMS_FLAG_NO_MODE_SETTING) + flags |= META_KMS_DEVICE_FLAG_NO_MODE_SETTING; + device = meta_kms_device_new (kms, path, flags, error); if (!device) return NULL; @@ -624,14 +629,16 @@ meta_kms_create_device (MetaKms *kms, } MetaKms * -meta_kms_new (MetaBackend *backend, - GError **error) +meta_kms_new (MetaBackend *backend, + MetaKmsFlags flags, + GError **error) { MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaUdev *udev = meta_backend_native_get_udev (backend_native); MetaKms *kms; kms = g_object_new (META_TYPE_KMS, NULL); + kms->flags = flags; kms->backend = backend; kms->impl = meta_kms_impl_new (kms); if (!kms->impl) @@ -640,8 +647,12 @@ meta_kms_new (MetaBackend *backend, return NULL; } - kms->hotplug_handler_id = - g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms); + if (!(flags & META_KMS_FLAG_NO_MODE_SETTING)) + { + kms->hotplug_handler_id = + g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms); + } + kms->removed_handler_id = g_signal_connect (udev, "device-removed", G_CALLBACK (on_udev_device_removed), kms); diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index 7bbd78e0c5e..27b4e3537ec 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -25,6 +25,12 @@ #include "backends/meta-backend-private.h" #include "backends/native/meta-kms-types.h" +typedef enum _MetaKmsFlags +{ + META_KMS_FLAG_NONE = 0, + META_KMS_FLAG_NO_MODE_SETTING = 1 << 0, +} MetaKmsFlags; + typedef enum _MetaKmsUpdateFlag { META_KMS_UPDATE_FLAG_NONE = 0, @@ -57,7 +63,8 @@ MetaKmsDevice * meta_kms_create_device (MetaKms *kms, MetaKmsDeviceFlag flags, GError **error); -MetaKms * meta_kms_new (MetaBackend *backend, - GError **error); +MetaKms * meta_kms_new (MetaBackend *backend, + MetaKmsFlags flags, + GError **error); #endif /* META_KMS_H */ diff --git a/src/meson.build b/src/meson.build index 196abf71f45..6f52ab71412 100644 --- a/src/meson.build +++ b/src/meson.build @@ -689,6 +689,8 @@ if have_native_backend 'backends/native/meta-kms-device.h', 'backends/native/meta-kms-impl-device-atomic.c', 'backends/native/meta-kms-impl-device-atomic.h', + 'backends/native/meta-kms-impl-device-dummy.c', + 'backends/native/meta-kms-impl-device-dummy.h', 'backends/native/meta-kms-impl-device-simple.c', 'backends/native/meta-kms-impl-device-simple.h', 'backends/native/meta-kms-impl-device.c', @@ -755,6 +757,7 @@ endif if have_native_backend mutter_private_enum_sources += [ 'backends/native/meta-backend-native-types.h', + 'backends/native/meta-kms-types.h', ] endif -- GitLab From 1e2ef9023dcac27a433300fd876d5c37c9353bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 15:03:17 +0100 Subject: [PATCH 12/38] backend/native: Hook up 'headless' mode to input and KMS subsystems With this commit, it's possible to run mutter without being DRM master. It's not yet possible to add virtual monitors, but one can for example already add virtual input devices. This currently doesn't try to hook up to any logind session, thus will not have a real seat assigned. Currently it's hard coded to "seat0". Part-of: --- src/backends/native/meta-backend-native.c | 30 ++++++++++++++----- .../native/meta-clutter-backend-native.c | 7 +++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index eb43a54ec53..65000cb529f 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -332,7 +332,10 @@ meta_backend_native_lock_layout_group (MetaBackend *backend, const char * meta_backend_native_get_seat_id (MetaBackendNative *backend_native) { - return meta_launcher_get_seat_id (backend_native->launcher); + if (backend_native->is_headless) + return "seat0"; + else + return meta_launcher_get_seat_id (backend_native->launcher); } gboolean @@ -513,6 +516,7 @@ meta_backend_native_initable_init (GInitable *initable, GError **error) { MetaBackendNative *native = META_BACKEND_NATIVE (initable); + MetaKmsFlags kms_flags; if (!meta_is_stage_views_enabled ()) { @@ -521,9 +525,12 @@ meta_backend_native_initable_init (GInitable *initable, return FALSE; } - native->launcher = meta_launcher_new (error); - if (!native->launcher) - return FALSE; + if (!native->is_headless) + { + native->launcher = meta_launcher_new (error); + if (!native->launcher) + return FALSE; + } #ifdef HAVE_WAYLAND meta_backend_init_wayland_display (META_BACKEND (native)); @@ -531,9 +538,11 @@ meta_backend_native_initable_init (GInitable *initable, native->udev = meta_udev_new (native); - native->kms = meta_kms_new (META_BACKEND (native), - META_KMS_FLAG_NONE, - error); + kms_flags = META_KMS_FLAG_NONE; + if (native->is_headless) + kms_flags |= META_KMS_FLAG_NO_MODE_SETTING; + + native->kms = meta_kms_new (META_BACKEND (native), kms_flags, error); if (!native->kms) return FALSE; @@ -639,6 +648,13 @@ meta_activate_vt (int vt, GError **error) MetaBackendNative *native = META_BACKEND_NATIVE (backend); MetaLauncher *launcher = meta_backend_native_get_launcher (native); + if (native->is_headless) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Can't switch VT while headless"); + return FALSE; + } + return meta_launcher_activate_vt (launcher, vt, error); } diff --git a/src/backends/native/meta-clutter-backend-native.c b/src/backends/native/meta-clutter-backend-native.c index 798f670c187..46156d8988a 100644 --- a/src/backends/native/meta-clutter-backend-native.c +++ b/src/backends/native/meta-clutter-backend-native.c @@ -106,12 +106,19 @@ meta_clutter_backend_native_init_events (ClutterBackend *clutter_backend) MetaBackend *backend = meta_get_backend (); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); const char *seat_id; + MetaSeatNativeFlag flags; seat_id = meta_backend_native_get_seat_id (backend_native); + if (meta_backend_native_is_headless (backend_native)) + flags = META_SEAT_NATIVE_FLAG_NO_LIBINPUT; + else + flags = META_SEAT_NATIVE_FLAG_NONE; + clutter_backend_native->main_seat = g_object_new (META_TYPE_SEAT_NATIVE, "backend", clutter_backend, "seat-id", seat_id, + "flags", flags, NULL); } -- GitLab From 9bf57f82d3814bf49a465f1e40a314d6229529e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 17:46:54 +0100 Subject: [PATCH 13/38] main: Make it possible to set properties when overriding configuration This makes it possible to pass custom properties to backends when constructing tests. This will be used to create "headless" native backend instances for testing the headless native backend. Part-of: --- src/core/main-private.h | 4 +- src/core/main.c | 65 +++++++++++++++++++++-- src/tests/clutter/interactive/test-main.c | 3 +- src/tests/headless-start-test.c | 3 +- src/tests/stage-view-tests.c | 3 +- src/tests/unit-tests.c | 3 +- 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/core/main-private.h b/src/core/main-private.h index d6d28facb3f..7e6d6eba7f6 100644 --- a/src/core/main-private.h +++ b/src/core/main-private.h @@ -47,7 +47,9 @@ typedef enum _MetaDisplayPolicy META_EXPORT_TEST void meta_override_compositor_configuration (MetaCompositorType compositor_type, - GType backend_gtype); + GType backend_gtype, + const char *first_property_name, + ...); META_EXPORT_TEST MetaDisplayPolicy meta_get_x11_display_policy (void); diff --git a/src/core/main.c b/src/core/main.c index f908fd217fc..a6c6fc8562d 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -581,14 +582,61 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, static gboolean _compositor_configuration_overridden = FALSE; static MetaCompositorType _compositor_type_override; static GType _backend_gtype_override; +static GArray *_backend_property_names; +static GArray *_backend_property_values; void meta_override_compositor_configuration (MetaCompositorType compositor_type, - GType backend_gtype) + GType backend_gtype, + const char *first_property_name, + ...) { + va_list var_args; + GArray *names; + GArray *values; + GObjectClass *object_class; + const char *property_name; + + names = g_array_new (FALSE, FALSE, sizeof (const char *)); + values = g_array_new (FALSE, FALSE, sizeof (GValue)); + g_array_set_clear_func (values, (GDestroyNotify) g_value_unset); + + object_class = g_type_class_ref (backend_gtype); + + property_name = first_property_name; + + va_start (var_args, first_property_name); + + while (property_name) + { + GValue value = G_VALUE_INIT; + GParamSpec *pspec; + GType ptype; + char *error = NULL; + + pspec = g_object_class_find_property (object_class, + property_name); + g_assert (pspec); + + ptype = G_PARAM_SPEC_VALUE_TYPE (pspec); + G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error); + g_assert (!error); + + g_array_append_val (names, property_name); + g_array_append_val (values, value); + + property_name = va_arg (var_args, const char *); + } + + va_end (var_args); + + g_type_class_unref (object_class); + _compositor_configuration_overridden = TRUE; _compositor_type_override = compositor_type; _backend_gtype_override = backend_gtype; + _backend_property_names = names; + _backend_property_values = values; } /** @@ -647,9 +695,9 @@ meta_init (void) { compositor_type = _compositor_type_override; backend_gtype = _backend_gtype_override; - n_properties = 0; - prop_names = NULL; - prop_values = NULL; + n_properties = _backend_property_names->len; + prop_names = (const char **) _backend_property_names->data; + prop_values = (GValue *) _backend_property_values->data; } else { @@ -693,6 +741,12 @@ meta_init (void) for (i = 0; i < n_properties; i++) g_value_reset (&prop_values[i]); + if (_backend_property_names) + { + g_array_free (_backend_property_names, TRUE); + g_array_free (_backend_property_values, TRUE); + } + meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); if (opt_replace_wm) @@ -864,7 +918,8 @@ meta_test_init (void) int fd = g_mkstemp (display_name); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_X11_NESTED); + META_TYPE_BACKEND_X11_NESTED, + NULL); meta_wayland_override_display_name (display_name); meta_xwayland_override_display_number (512 + rand() % 512); meta_init (); diff --git a/src/tests/clutter/interactive/test-main.c b/src/tests/clutter/interactive/test-main.c index 95b45bb4c06..f3d3084630c 100644 --- a/src/tests/clutter/interactive/test-main.c +++ b/src/tests/clutter/interactive/test-main.c @@ -129,7 +129,8 @@ main (int argc, char **argv) meta_wayland_override_display_name ("mutter-test-display"); meta_xwayland_override_display_number (512); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_X11_NESTED); + META_TYPE_BACKEND_X11_NESTED, + NULL); meta_init (); module = g_module_open (NULL, 0); diff --git a/src/tests/headless-start-test.c b/src/tests/headless-start-test.c index 027dd9cb761..072dd8f2092 100644 --- a/src/tests/headless-start-test.c +++ b/src/tests/headless-start-test.c @@ -217,7 +217,8 @@ main (int argc, char *argv[]) meta_plugin_manager_load (test_get_plugin_name ()); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_TEST); + META_TYPE_BACKEND_TEST, + NULL); meta_init (); meta_register_with_session (); diff --git a/src/tests/stage-view-tests.c b/src/tests/stage-view-tests.c index 101fbdcdaab..4131abfb8c7 100644 --- a/src/tests/stage-view-tests.c +++ b/src/tests/stage-view-tests.c @@ -1192,7 +1192,8 @@ main (int argc, char *argv[]) meta_plugin_manager_load (test_get_plugin_name ()); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_TEST); + META_TYPE_BACKEND_TEST, + NULL); meta_init (); meta_register_with_session (); diff --git a/src/tests/unit-tests.c b/src/tests/unit-tests.c index 0ec709c1f4e..308a2f278d0 100644 --- a/src/tests/unit-tests.c +++ b/src/tests/unit-tests.c @@ -269,7 +269,8 @@ main (int argc, char *argv[]) meta_plugin_manager_load (test_get_plugin_name ()); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_TEST); + META_TYPE_BACKEND_TEST, + NULL); meta_init (); meta_register_with_session (); -- GitLab From 78ba1429c8d4baba055a000838f7dbce84045dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Jan 2021 17:48:04 +0100 Subject: [PATCH 14/38] tests: Add headless native backend test It doesn't do anything more than construct and tear down, but it's a start. Don't run the test as part of CI yet, as doesn't have the DRM devices needed. Part-of: --- .gitlab-ci.yml | 6 +- meson.build | 7 +++ meson_options.txt | 6 ++ src/backends/native/meta-backend-native.h | 1 + src/tests/meson.build | 24 ++++++++ src/tests/native-headless.c | 75 +++++++++++++++++++++++ 6 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 src/tests/native-headless.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e89e3f60657..c57faef9d04 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -191,7 +191,7 @@ build-fedora-container@aarch64: - .fdo.distribution-image@fedora stage: build script: - - meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr + - meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true -Dnative_tests=false --werror --prefix /usr - ninja -C build - ninja -C build install artifacts: @@ -221,7 +221,7 @@ build-without-opengl-and-glx@x86_64: needs: - build-fedora-container@x86_64 script: - - meson . build -Dbuildtype=debugoptimized -Dopengl=false -Dglx=false -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr + - meson . build -Dbuildtype=debugoptimized -Dopengl=false -Dglx=false -Degl_device=true -Dwayland_eglstream=true -Dnative_tests=false --werror --prefix /usr - ninja -C build - ninja -C build install artifacts: @@ -236,7 +236,7 @@ build-without-native-backend-and-wayland@x86_64: needs: - build-fedora-container@x86_64 script: - - meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false --werror --prefix /usr + - meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false -Dnative_tests=false --werror --prefix /usr - ninja -C build - ninja -C build install artifacts: diff --git a/meson.build b/meson.build index 4becf2b7d64..c4bfdfe25cf 100644 --- a/meson.build +++ b/meson.build @@ -262,6 +262,7 @@ have_tests = get_option('tests') have_core_tests = false have_cogl_tests = false have_clutter_tests = false +have_native_tests = false have_installed_tests = false if have_tests @@ -271,6 +272,12 @@ if have_tests error('Tests require Wayland to be enabled') endif endif + have_native_tests = get_option('native_tests') + if have_native_tests + if not have_native_backend + error('Native tests require the native backend') + endif + endif have_cogl_tests = get_option('cogl_tests') have_clutter_tests = get_option('clutter_tests') diff --git a/meson_options.txt b/meson_options.txt index a0fb6163677..84e7dcc6c9c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -117,6 +117,12 @@ option('core_tests', description: 'Enable mutter core tests' ) +option('native_tests', + type: 'boolean', + value: true, + description: 'Enable mutter native backend tests' +) + option('tests', type: 'boolean', value: true, diff --git a/src/backends/native/meta-backend-native.h b/src/backends/native/meta-backend-native.h index 0c7df66db8f..aad4c8413fe 100644 --- a/src/backends/native/meta-backend-native.h +++ b/src/backends/native/meta-backend-native.h @@ -32,6 +32,7 @@ #include "backends/native/meta-udev.h" #define META_TYPE_BACKEND_NATIVE (meta_backend_native_get_type ()) +META_EXPORT_TEST G_DECLARE_FINAL_TYPE (MetaBackendNative, meta_backend_native, META, BACKEND_NATIVE, MetaBackend) diff --git a/src/tests/meson.build b/src/tests/meson.build index 05c6aaf701f..fbdca617c4c 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -157,6 +157,21 @@ anonymous_file_test = executable('anonymous-file-tests', install_dir: mutter_installed_tests_libexecdir, ) +if have_native_tests + native_headless_tests = executable('mutter-native-headless-tests', + sources: [ + 'native-headless.c', + 'test-utils.c', + 'test-utils.h', + ], + include_directories: tests_includepath, + c_args: tests_c_args, + dependencies: [tests_deps], + install: have_installed_tests, + install_dir: mutter_installed_tests_libexecdir, + ) +endif + stacking_tests = [ 'basic-x11', 'basic-wayland', @@ -223,3 +238,12 @@ test('anonymous-file', anonymous_file_test, is_parallel: false, timeout: 60, ) + +if have_native_tests + test('native-headless', native_headless_tests, + suite: ['core', 'mutter/native/headless'], + env: test_env, + is_parallel: false, + timeout: 60, + ) +endif diff --git a/src/tests/native-headless.c b/src/tests/native-headless.c new file mode 100644 index 00000000000..4929fa221cc --- /dev/null +++ b/src/tests/native-headless.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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/meta-settings-private.h" +#include "backends/native/meta-backend-native.h" +#include "compositor/meta-plugin-manager.h" +#include "core/main-private.h" +#include "meta/main.h" +#include "meta/meta-backend.h" +#include "tests/test-utils.h" + +static void +init_tests (void) +{ +} + +static gboolean +run_tests (gpointer data) +{ + MetaBackend *backend = meta_get_backend (); + MetaSettings *settings = meta_backend_get_settings (backend); + gboolean ret; + + meta_settings_override_experimental_features (settings); + meta_settings_enable_experimental_feature ( + settings, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER); + + ret = g_test_run (); + + meta_quit (ret != 0); + + return FALSE; +} + +int +main (int argc, + char **argv) +{ + test_init (&argc, &argv); + init_tests (); + + meta_plugin_manager_load (test_get_plugin_name ()); + + meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, + META_TYPE_BACKEND_NATIVE, + "headless", TRUE, + NULL); + + meta_init (); + meta_register_with_session (); + + g_idle_add (run_tests, NULL); + + return meta_run (); +} -- GitLab From 19c4667d6aeaf46eae8f2a6134617f1d12a759bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 25 Jan 2021 21:12:51 +0100 Subject: [PATCH 15/38] renderer/native: Downgrade warning to message about no hw-accel dGPU path Warnings should be for errors, not non-optimal system configurations. Part-of: --- src/backends/native/meta-renderer-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 0839904b463..bacf0f96e30 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -1361,7 +1361,7 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data) if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error)) return; - g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s", + g_message ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s", error->message); g_error_free (error); -- GitLab From 6aef4b39708cc391c6e3afb9c1211cc5f6227bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 14:49:25 +0100 Subject: [PATCH 16/38] monitor: Attach to backend instead of GPU Prepare for the future when a monitor isn't necessarily attached to a mode setting device, which is practically what MetaGpu represents. Part-of: --- src/backends/meta-monitor-manager.c | 4 ++-- src/backends/meta-monitor.c | 20 +++++++++---------- src/backends/meta-monitor.h | 8 +++----- .../meta-screen-cast-monitor-stream.c | 3 +-- .../native/meta-cursor-renderer-native.c | 3 ++- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 0fbdf566192..620b60d0a62 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -2872,7 +2872,7 @@ rebuild_monitors (MetaMonitorManager *manager) { MetaMonitorTiled *monitor_tiled; - monitor_tiled = meta_monitor_tiled_new (gpu, manager, output); + monitor_tiled = meta_monitor_tiled_new (manager, output); manager->monitors = g_list_append (manager->monitors, monitor_tiled); } @@ -2881,7 +2881,7 @@ rebuild_monitors (MetaMonitorManager *manager) { MetaMonitorNormal *monitor_normal; - monitor_normal = meta_monitor_normal_new (gpu, manager, output); + monitor_normal = meta_monitor_normal_new (manager, output); manager->monitors = g_list_append (manager->monitors, monitor_normal); } diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c index 0be7994ad55..8f147b70c21 100644 --- a/src/backends/meta-monitor.c +++ b/src/backends/meta-monitor.c @@ -55,7 +55,7 @@ typedef struct _MetaMonitorModeTiled typedef struct _MetaMonitorPrivate { - MetaGpu *gpu; + MetaBackend *backend; GList *outputs; GList *modes; @@ -288,12 +288,12 @@ meta_monitor_make_display_name (MetaMonitor *monitor, } } -MetaGpu * -meta_monitor_get_gpu (MetaMonitor *monitor) +MetaBackend * +meta_monitor_get_backend (MetaMonitor *monitor) { MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); - return priv->gpu; + return priv->backend; } GList * @@ -660,8 +660,7 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) } MetaMonitorNormal * -meta_monitor_normal_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +meta_monitor_normal_new (MetaMonitorManager *monitor_manager, MetaOutput *output) { MetaMonitorNormal *monitor_normal; @@ -672,7 +671,7 @@ meta_monitor_normal_new (MetaGpu *gpu, monitor = META_MONITOR (monitor_normal); monitor_priv = meta_monitor_get_instance_private (monitor); - monitor_priv->gpu = gpu; + monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager); monitor_priv->outputs = g_list_append (NULL, g_object_ref (output)); meta_output_set_monitor (output, monitor); @@ -1348,8 +1347,7 @@ meta_monitor_tiled_generate_modes (MetaMonitorTiled *monitor_tiled) } MetaMonitorTiled * -meta_monitor_tiled_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, MetaOutput *output) { const MetaOutputInfo *output_info = meta_output_get_info (output); @@ -1361,13 +1359,13 @@ meta_monitor_tiled_new (MetaGpu *gpu, monitor = META_MONITOR (monitor_tiled); monitor_priv = meta_monitor_get_instance_private (monitor); - monitor_priv->gpu = gpu; + monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager); monitor_tiled->tile_group_id = output_info->tile_info.group_id; monitor_priv->winsys_id = meta_output_get_id (output); monitor_tiled->origin_output = output; - add_tiled_monitor_outputs (gpu, monitor_tiled); + add_tiled_monitor_outputs (meta_output_get_gpu (output), monitor_tiled); monitor_tiled->main_output = find_untiled_output (monitor_tiled); diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index c158b7c9409..eceb645c22f 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -95,17 +95,15 @@ G_DECLARE_FINAL_TYPE (MetaMonitorTiled, meta_monitor_tiled, META, MONITOR_TILED, MetaMonitor) -MetaMonitorTiled * meta_monitor_tiled_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +MetaMonitorTiled * meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, MetaOutput *output); -MetaMonitorNormal * meta_monitor_normal_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +MetaMonitorNormal * meta_monitor_normal_new (MetaMonitorManager *monitor_manager, MetaOutput *output); MetaMonitorSpec * meta_monitor_get_spec (MetaMonitor *monitor); -MetaGpu * meta_monitor_get_gpu (MetaMonitor *monitor); +MetaBackend * meta_monitor_get_backend (MetaMonitor *monitor); META_EXPORT_TEST gboolean meta_monitor_is_active (MetaMonitor *monitor); diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index 9c138611cae..d3ad20b3c1e 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -113,8 +113,7 @@ meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, MetaScreenCastFlag flags, GError **error) { - MetaGpu *gpu = meta_monitor_get_gpu (monitor); - MetaBackend *backend = meta_gpu_get_backend (gpu); + MetaBackend *backend = meta_monitor_get_backend (monitor); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); MetaScreenCastMonitorStream *monitor_stream; diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index bb436b2c052..3d83e6e478d 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -985,9 +985,10 @@ calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer, for (l_mon = monitors; l_mon; l_mon = l_mon->next) { MetaMonitor *monitor = l_mon->data; + MetaOutput *output = meta_monitor_get_main_output (monitor); MetaGpu *gpu; - gpu = meta_monitor_get_gpu (monitor); + gpu = meta_output_get_gpu (output); if (!g_list_find (gpus, gpu)) gpus = g_list_prepend (gpus, gpu); } -- GitLab From b91740df0e739e0f0ec730201ac4e7571eba8454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 16:13:18 +0100 Subject: [PATCH 17/38] crtc/kms: Make the 'transform-handled' API pass through MetaCrtcNative In preparation for creating another non-KMS backend virtual CRTC. Part-of: --- src/backends/native/meta-crtc-kms.c | 22 ++++++++++++++----- src/backends/native/meta-crtc-kms.h | 3 --- src/backends/native/meta-crtc-native.c | 9 ++++++++ src/backends/native/meta-crtc-native.h | 6 +++++ .../native/meta-monitor-manager-native.c | 3 ++- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index fb38e4d6723..f1bc79146af 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -74,9 +74,9 @@ meta_crtc_kms_set_cursor_renderer_private (MetaCrtcKms *crtc_kms, crtc_kms->cursor_renderer_private_destroy_notify = destroy_notify; } -gboolean -meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, - MetaMonitorTransform transform) +static gboolean +is_transform_handled (MetaCrtcKms *crtc_kms, + MetaMonitorTransform transform) { if (!crtc_kms->primary_plane) return FALSE; @@ -85,6 +85,15 @@ meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, transform); } +static gboolean +meta_crtc_kms_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc_native); + + return is_transform_handled (crtc_kms, transform); +} + void meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, MetaKmsPlaneAssignment *kms_plane_assignment) @@ -96,9 +105,9 @@ meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, crtc_config = meta_crtc_get_config (crtc); hw_transform = crtc_config->transform; - if (!meta_crtc_kms_is_transform_handled (crtc_kms, hw_transform)) + if (!is_transform_handled (crtc_kms, hw_transform)) hw_transform = META_MONITOR_TRANSFORM_NORMAL; - if (!meta_crtc_kms_is_transform_handled (crtc_kms, hw_transform)) + if (!is_transform_handled (crtc_kms, hw_transform)) return; meta_kms_plane_update_set_rotation (crtc_kms->primary_plane, @@ -369,6 +378,9 @@ static void meta_crtc_kms_class_init (MetaCrtcKmsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaCrtcNativeClass *crtc_native_class = META_CRTC_NATIVE_CLASS (klass); object_class->dispose = meta_crtc_kms_dispose; + + crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled; } diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index df957be15cc..f8d241bbb51 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -45,9 +45,6 @@ void meta_crtc_kms_set_cursor_renderer_private (MetaCrtcKms *crtc_kms, gpointer cursor_renderer_private, GDestroyNotify destroy_notify); -gboolean meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, - MetaMonitorTransform transform); - void meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, MetaKmsPlaneAssignment *kms_plane_assignment); diff --git a/src/backends/native/meta-crtc-native.c b/src/backends/native/meta-crtc-native.c index 3a0e7a95216..5e5751780f0 100644 --- a/src/backends/native/meta-crtc-native.c +++ b/src/backends/native/meta-crtc-native.c @@ -24,6 +24,15 @@ G_DEFINE_ABSTRACT_TYPE (MetaCrtcNative, meta_crtc_native, META_TYPE_CRTC) +gboolean +meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + MetaCrtcNativeClass *klass = META_CRTC_NATIVE_GET_CLASS (crtc_native); + + return klass->is_transform_handled (crtc_native, transform); +} + static void meta_crtc_native_init (MetaCrtcNative *crtc_native) { diff --git a/src/backends/native/meta-crtc-native.h b/src/backends/native/meta-crtc-native.h index 61ea15be31c..0c16e589598 100644 --- a/src/backends/native/meta-crtc-native.h +++ b/src/backends/native/meta-crtc-native.h @@ -30,6 +30,12 @@ G_DECLARE_DERIVABLE_TYPE (MetaCrtcNative, meta_crtc_native, struct _MetaCrtcNativeClass { MetaCrtcClass parent_class; + + gboolean (* is_transform_handled) (MetaCrtcNative *crtc_native, + MetaMonitorTransform monitor_transform); }; +gboolean meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform); + #endif /* META_CRTC_NATIVE_H */ diff --git a/src/backends/native/meta-monitor-manager-native.c b/src/backends/native/meta-monitor-manager-native.c index 30a15350619..0b9471c255b 100644 --- a/src/backends/native/meta-monitor-manager-native.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -528,7 +528,8 @@ meta_monitor_manager_native_is_transform_handled (MetaMonitorManager *manager, MetaCrtc *crtc, MetaMonitorTransform transform) { - return meta_crtc_kms_is_transform_handled (META_CRTC_KMS (crtc), transform); + return meta_crtc_native_is_transform_handled (META_CRTC_NATIVE (crtc), + transform); } static float -- GitLab From 47a67252078ba5c78ec5e17dae5e32bf91c8da08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 27 Jan 2021 23:16:05 +0100 Subject: [PATCH 18/38] monitor: Unset output monitor when disposing When rebuilding the monitors (e.g. during hotplug), make sure to detach the disposed monitors from any outputs before creating the new monitors. While this isn't currently needed, as outputs are too being recreated, with the to be introduced virtual outputs that are created for virtual monitors, this is not always the case anymore, as these virtual outputs are not regenerated each time anything changes. Prepare for this by making sure that cleaning up disposed monitors detach themself properly from the outputs, so new ones can attach themself to outputs without running into conflicts. Part-of: --- src/backends/meta-monitor-manager.c | 9 ++++++++- src/backends/meta-monitor.c | 1 + src/backends/meta-output.c | 10 ++++++++++ src/backends/meta-output.h | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 620b60d0a62..8744d729e8d 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -2843,6 +2843,13 @@ meta_monitor_manager_get_power_save_mode (MetaMonitorManager *manager) return priv->power_save_mode; } +static void +destroy_monitor (MetaMonitor *monitor) +{ + g_object_run_dispose (G_OBJECT (monitor)); + g_object_unref (monitor); +} + static void rebuild_monitors (MetaMonitorManager *manager) { @@ -2851,7 +2858,7 @@ rebuild_monitors (MetaMonitorManager *manager) if (manager->monitors) { - g_list_free_full (manager->monitors, g_object_unref); + g_list_free_full (manager->monitors, (GDestroyNotify) destroy_monitor); manager->monitors = NULL; } diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c index 8f147b70c21..e02f8ed4598 100644 --- a/src/backends/meta-monitor.c +++ b/src/backends/meta-monitor.c @@ -486,6 +486,7 @@ meta_monitor_dispose (GObject *object) if (priv->outputs) { + g_list_foreach (priv->outputs, (GFunc) meta_output_unset_monitor, NULL); g_list_free_full (priv->outputs, g_object_unref); priv->outputs = NULL; } diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c index c903110a650..432697d6d95 100644 --- a/src/backends/meta-output.c +++ b/src/backends/meta-output.c @@ -135,6 +135,16 @@ meta_output_set_monitor (MetaOutput *output, priv->monitor = monitor; } +void +meta_output_unset_monitor (MetaOutput *output) +{ + MetaOutputPrivate *priv = meta_output_get_instance_private (output); + + g_warn_if_fail (priv->monitor); + + priv->monitor = NULL; +} + const char * meta_output_get_name (MetaOutput *output) { diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index bed1996626a..3c4431c4d97 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -145,6 +145,8 @@ MetaMonitor * meta_output_get_monitor (MetaOutput *output); void meta_output_set_monitor (MetaOutput *output, MetaMonitor *monitor); +void meta_output_unset_monitor (MetaOutput *output); + const char * meta_output_get_name (MetaOutput *output); META_EXPORT_TEST -- GitLab From a0e4f5226c0d6b4358b040219c207689d5bf43f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 29 Jan 2021 10:06:18 +0100 Subject: [PATCH 19/38] workspace: Nag less about tiny but sane work areas It's useful to be able to have very very tiny monitors (e.g. 60x60 pixels) when doing reference testing, as tests have reference images that the output is compared to. Smaller reference images the less storage they use. To avoid annoying pointless warnings when this is done, change the pedantic workspace work area code to be more forgiving if the work area happens to match the display size. Part-of: --- src/core/workspace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/workspace.c b/src/core/workspace.c index 32ee8da93ab..321d3efb0ac 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -887,7 +887,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace) /* Lots of paranoia checks, forcing work_area_screen to be sane */ #define MIN_SANE_AREA 100 - if (work_area.width < MIN_SANE_AREA) + if (work_area.width < MIN_SANE_AREA && + work_area.width != display_rect.width) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining width = %d < %d", @@ -904,7 +905,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace) work_area.width += 2*amount; } } - if (work_area.height < MIN_SANE_AREA) + if (work_area.height < MIN_SANE_AREA && + work_area.height != display_rect.height) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining height = %d < %d", -- GitLab From b31a639378b8c284096fc194d76b1847e665aa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 3 Feb 2021 10:59:06 +0100 Subject: [PATCH 20/38] backend: Add 'prepare-shutdown' signal This will be used to avoid doing various work when we're shutting down, e.g. react to changes triggering monitor reconfigurations. Part-of: --- src/backends/meta-backend-private.h | 2 ++ src/backends/meta-backend.c | 14 ++++++++++++++ src/core/main.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 3926a3c63ae..0c328ffccde 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -110,6 +110,8 @@ void meta_init_backend (GType backend_gtype, const GValue *values); void meta_release_backend (void); +void meta_backend_prepare_shutdown (MetaBackend *backend); + #ifdef HAVE_WAYLAND MetaWaylandCompositor * meta_backend_get_wayland_compositor (MetaBackend *backend); diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 6b2780eebd9..e0249160dbd 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -94,6 +94,7 @@ enum LAST_DEVICE_CHANGED, LID_IS_CLOSED_CHANGED, GPU_ADDED, + PREPARE_SHUTDOWN, N_SIGNALS }; @@ -869,6 +870,13 @@ meta_backend_class_init (MetaBackendClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_GPU); + signals[PREPARE_SHUTDOWN] = + g_signal_new ("prepare-shutdown", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS"); stage_views_disabled = g_strcmp0 (mutter_stage_views, "0") == 0; @@ -1485,6 +1493,12 @@ meta_release_backend (void) g_clear_object (&_backend); } +void +meta_backend_prepare_shutdown (MetaBackend *backend) +{ + g_signal_emit (backend, signals[PREPARE_SHUTDOWN], 0); +} + /** * meta_is_stage_views_enabled: * diff --git a/src/core/main.c b/src/core/main.c index a6c6fc8562d..e204b68ffe6 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -344,6 +344,10 @@ static void meta_finalize (void) { MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); + + if (backend) + meta_backend_prepare_shutdown (backend); if (display) meta_display_close (display, -- GitLab From c8089f07a33ea22fdc6d8b57f40e8edc6e9927b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 28 Jan 2021 15:08:15 +0100 Subject: [PATCH 21/38] backend: Only show cursor when showing stage if pointer is present This avoids showing the cursor when initially there is no pointer device, nor touchscreen device. Part-of: --- src/backends/meta-backend.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index e0249160dbd..4eb0a8e7de5 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -456,6 +456,9 @@ on_device_added (ClutterSeat *seat, if (device_type == CLUTTER_TOUCHSCREEN_DEVICE) meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, FALSE); + else if (device_type == CLUTTER_POINTER_DEVICE && + !clutter_seat_has_touchscreen (seat)) + meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); if (device_type == CLUTTER_TOUCHSCREEN_DEVICE || device_type == CLUTTER_TABLET_DEVICE || @@ -566,8 +569,26 @@ static void on_stage_shown_cb (MetaBackend *backend) { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (priv->clutter_backend); + g_autoptr (GList) devices = NULL; + const GList *l; + + devices = clutter_seat_list_devices (seat); + for (l = devices; l; l = l->next) + { + ClutterInputDevice *device = l->data; + + if (clutter_input_device_get_device_mode (device) == + CLUTTER_INPUT_MODE_LOGICAL) + continue; - meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); + if (clutter_input_device_get_device_type (device) != + CLUTTER_POINTER_DEVICE) + continue; + + meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); + break; + } } static void -- GitLab From ba3805706795c90db436f6a1572ecf9f5ca5cf2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sun, 14 Feb 2021 00:17:36 +0100 Subject: [PATCH 22/38] plugins/default: Initialize background color in a predictable manner The order of which function argument expressions are executed is undefined, so don't rely on this for setting the background colors, as it results in different colors on different architectures. For example, it has been observed that the order of execution is reversed comparing x86_64 and aarch64, making these two architectures having different background color. Fix this confusion, and also reproduceability in future reference tests, by making the order of execution predictable. Part-of: --- src/compositor/plugins/default.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c index 1c73174d2fc..c89c84121f5 100644 --- a/src/compositor/plugins/default.c +++ b/src/compositor/plugins/default.c @@ -338,6 +338,9 @@ on_monitors_changed (MetaMonitorManager *monitor_manager, MetaRectangle rect; ClutterActor *background_actor; MetaBackground *background; + uint8_t red; + uint8_t green; + uint8_t blue; ClutterColor color; meta_display_get_monitor_geometry (display, i, &rect); @@ -353,11 +356,11 @@ on_monitors_changed (MetaMonitorManager *monitor_manager, parsing the driconf XML, but it's nice if the colors are reproducible. */ - clutter_color_init (&color, - g_rand_int_range (rand, 0, 255), - g_rand_int_range (rand, 0, 255), - g_rand_int_range (rand, 0, 255), - 255); + + blue = g_rand_int_range (rand, 0, 255); + green = g_rand_int_range (rand, 0, 255); + red = g_rand_int_range (rand, 0, 255); + clutter_color_init (&color, red, green, blue, 255); background = meta_background_new (display); meta_background_set_color (background, &color); -- GitLab From e7ae1978f8ec957a6ca389bf7a00155558e40b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 9 Mar 2021 19:19:47 +0100 Subject: [PATCH 23/38] kms/connector: Don't use MetaConnectorType for connector type Use uint32_t as that is what it is in the drm layer. MetaConnectorType will be less suitable, as it will grow custom connector types that can't be mapped. Part-of: --- src/backends/native/meta-kms-connector.c | 6 +++--- src/backends/native/meta-kms-connector.h | 2 +- src/backends/native/meta-output-kms.c | 11 ++++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 1ea4502845b..0ad16617623 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -42,7 +42,7 @@ struct _MetaKmsConnector MetaKmsDevice *device; uint32_t id; - MetaConnectorType type; + uint32_t type; uint32_t type_id; char *name; @@ -76,7 +76,7 @@ meta_kms_connector_get_prop_name (MetaKmsConnector *connector, return connector->prop_table.props[prop].name; } -MetaConnectorType +uint32_t meta_kms_connector_get_connector_type (MetaKmsConnector *connector) { return connector->type; @@ -621,7 +621,7 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device, connector = g_object_new (META_TYPE_KMS_CONNECTOR, NULL); connector->device = meta_kms_impl_device_get_device (impl_device); connector->id = drm_connector->connector_id; - connector->type = (MetaConnectorType) drm_connector->connector_type; + connector->type = drm_connector->connector_type; connector->type_id = drm_connector->connector_type_id; connector->name = make_connector_name (drm_connector); diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index 50ffdd851ef..a3a7136c5a5 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -61,7 +61,7 @@ typedef struct _MetaKmsConnectorState MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector); -MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector); +uint32_t meta_kms_connector_get_connector_type (MetaKmsConnector *connector); uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector); diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index eff8db5a9d4..8fcf91ab807 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -267,6 +267,12 @@ init_output_modes (MetaOutputInfo *output_info, return TRUE; } +static MetaConnectorType +meta_kms_connector_type_from_drm (uint32_t drm_connector_type) +{ + return (MetaConnectorType) drm_connector_type; +} + MetaOutputKms * meta_output_kms_new (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, @@ -279,6 +285,7 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, g_autoptr (MetaOutputInfo) output_info = NULL; MetaOutput *output; MetaOutputKms *output_kms; + uint32_t drm_connector_type; const MetaKmsConnectorState *connector_state; GArray *crtcs; GList *l; @@ -331,7 +338,9 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, meta_output_info_parse_edid (output_info, connector_state->edid_data); - output_info->connector_type = meta_kms_connector_get_connector_type (kms_connector); + drm_connector_type = meta_kms_connector_get_connector_type (kms_connector); + output_info->connector_type = + meta_kms_connector_type_from_drm (drm_connector_type); output_info->tile_info = connector_state->tile_info; -- GitLab From 1818d21da565814c01ab8a68a9d702553c7b654d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 16:49:28 +0100 Subject: [PATCH 24/38] Introduce virtual monitors Virtual monitors are monitors that isn't backed by any monitor like hardware. It would typically be backed by e.g. a remote desktop service, or a network display. It is currently only supported by the native backend, and whether the X11 backend will ever see virtual monitors is an open question. This rest of this commit message describes how it works under the native backend. Each virutal monitor consists of virtualized mode setting components: * A virtual CRTC mode (MetaCrtcModeVirtual) * A virtual CRTC (MetaCrtcVirtual) * A virtual connector (MetaOutputVirtual) In difference to the corresponding mode setting objects that represents KMS objects, the virtual ones isn't directly tied to a MetaGpu, other than the CoglFramebuffer being part of the GPU context of the primary GPU, which is the case for all monitors no matter what GPU they are connected to. Part of the reason for this is that a MetaGpu in practice represents a mode setting device, and its CRTCs and outputs, are all backed by real mode setting objects, while a virtual monitor is only backed by a framebuffer that is tied to the primary GPU. Maybe this will be reevaluated in the future, but since a virtual monitor is not tied to any GPU currently, so is the case for the virtual mode setting objects. The native rendering backend, including the cursor renderer, is adapted to handle the situation where a CRTC does not have a GPU associated with it; this in practice means that it e.g. will not try to upload HW cursor buffers when the cursor is only on a virtual monitor. The same applies to the native renderer, which is made to avoid creating MetaOnscreenNative for views that are backed by virtual CRTCs, as well as to avoid trying to mode set on such views. Part-of: --- src/backends/meta-backend-types.h | 3 + src/backends/meta-monitor-manager-private.h | 10 + src/backends/meta-monitor-manager.c | 98 ++++++++ src/backends/meta-output.h | 5 +- src/backends/meta-virtual-monitor.c | 238 ++++++++++++++++++ src/backends/meta-virtual-monitor.h | 68 +++++ .../native/meta-backend-native-types.h | 2 + src/backends/native/meta-crtc-mode-virtual.c | 70 ++++++ src/backends/native/meta-crtc-mode-virtual.h | 34 +++ src/backends/native/meta-crtc-virtual.c | 60 +++++ src/backends/native/meta-crtc-virtual.h | 32 +++ .../native/meta-cursor-renderer-native.c | 8 +- .../native/meta-monitor-manager-native.c | 75 +++++- src/backends/native/meta-output-kms.c | 2 + src/backends/native/meta-output-virtual.c | 80 ++++++ src/backends/native/meta-output-virtual.h | 36 +++ src/backends/native/meta-renderer-native.c | 104 +++++--- src/backends/native/meta-stage-native.c | 27 ++ .../native/meta-virtual-monitor-native.c | 80 ++++++ .../native/meta-virtual-monitor-native.h | 45 ++++ src/meson.build | 10 + 21 files changed, 1049 insertions(+), 38 deletions(-) create mode 100644 src/backends/meta-virtual-monitor.c create mode 100644 src/backends/meta-virtual-monitor.h create mode 100644 src/backends/native/meta-crtc-mode-virtual.c create mode 100644 src/backends/native/meta-crtc-mode-virtual.h create mode 100644 src/backends/native/meta-crtc-virtual.c create mode 100644 src/backends/native/meta-crtc-virtual.h create mode 100644 src/backends/native/meta-output-virtual.c create mode 100644 src/backends/native/meta-output-virtual.h create mode 100644 src/backends/native/meta-virtual-monitor-native.c create mode 100644 src/backends/native/meta-virtual-monitor-native.h diff --git a/src/backends/meta-backend-types.h b/src/backends/meta-backend-types.h index 146a8c3d7c3..eae62c02f24 100644 --- a/src/backends/meta-backend-types.h +++ b/src/backends/meta-backend-types.h @@ -59,6 +59,9 @@ typedef struct _MetaScreenCastStream MetaScreenCastStream; typedef struct _MetaWaylandCompositor MetaWaylandCompositor; +typedef struct _MetaVirtualMonitor MetaVirtualMonitor; +typedef struct _MetaVirtualMonitorInfo MetaVirtualMonitorInfo; + #ifdef HAVE_REMOTE_DESKTOP typedef struct _MetaRemoteDesktop MetaRemoteDesktop; #endif diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 70d61f823bd..fd30ebb58ee 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -261,6 +261,10 @@ struct _MetaMonitorManagerClass void (* set_output_ctm) (MetaOutput *output, const MetaOutputCtm *ctm); + + MetaVirtualMonitor * (* create_virtual_monitor) (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error); }; META_EXPORT_TEST @@ -388,6 +392,10 @@ gboolean meta_monitor_manager_get_max_screen_size (MetaMonitorManager MetaLogicalMonitorLayoutMode meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager); +MetaVirtualMonitor * meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error); + MetaMonitorConfigManager * meta_monitor_manager_get_config_manager (MetaMonitorManager *manager); @@ -424,4 +432,6 @@ void meta_monitor_manager_post_init (MetaMonitorManager *manager); MetaViewportInfo * meta_monitor_manager_get_viewports (MetaMonitorManager *manager); +GList * meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager); + #endif /* META_MONITOR_MANAGER_PRIVATE_H */ diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 8744d729e8d..005fa6791b5 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -53,6 +53,7 @@ #include "backends/meta-monitor-config-manager.h" #include "backends/meta-orientation-manager.h" #include "backends/meta-output.h" +#include "backends/meta-virtual-monitor.h" #include "backends/x11/meta-monitor-manager-xrandr.h" #include "clutter/clutter.h" #include "core/main-private.h" @@ -101,6 +102,10 @@ typedef struct _MetaMonitorManagerPrivate { MetaPowerSave power_save_mode; gboolean initial_orient_change_done; + + GList *virtual_monitors; + + gboolean shutting_down; } MetaMonitorManagerPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager, @@ -400,6 +405,16 @@ lid_is_closed_changed (MetaBackend *backend, meta_monitor_manager_lid_is_closed_changed (manager); } +static void +prepare_shutdown (MetaBackend *backend, + MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + + priv->shutting_down = TRUE; +} + /** * meta_monitor_manager_is_headless: * @manager: A #MetaMonitorManager object @@ -483,6 +498,60 @@ meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager) return manager_class->get_default_layout_mode (manager); } +static void +on_virtual_monitor_destroyed (MetaVirtualMonitor *virtual_monitor, + MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + MetaOutput *output; + + output = meta_virtual_monitor_get_output (virtual_monitor); + g_message ("Removed virtual monitor %s", meta_output_get_name (output)); + priv->virtual_monitors = g_list_remove (priv->virtual_monitors, + virtual_monitor); + + if (!priv->shutting_down) + meta_monitor_manager_reload (manager); +} + +MetaVirtualMonitor * +meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + MetaMonitorManagerClass *manager_class = + META_MONITOR_MANAGER_GET_CLASS (manager); + MetaVirtualMonitor *virtual_monitor; + MetaOutput *output; + + if (!manager_class->create_virtual_monitor) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Backend doesn't support creating virtual monitors"); + return NULL; + } + + virtual_monitor = manager_class->create_virtual_monitor (manager, info, + error); + if (!virtual_monitor) + return NULL; + + g_signal_connect (virtual_monitor, "destroy", + G_CALLBACK (on_virtual_monitor_destroyed), + manager); + + priv->virtual_monitors = g_list_append (priv->virtual_monitors, + virtual_monitor); + + output = meta_virtual_monitor_get_output (virtual_monitor); + g_message ("Added virtual monitor %s", meta_output_get_name (output)); + + return virtual_monitor; +} + static void meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager) { @@ -896,6 +965,10 @@ meta_monitor_manager_constructed (GObject *object) G_CALLBACK (lid_is_closed_changed), manager, 0); + g_signal_connect (backend, "prepare-shutdown", + G_CALLBACK (prepare_shutdown), + manager); + manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN; initialize_dbus_interface (manager); @@ -905,9 +978,13 @@ static void meta_monitor_manager_finalize (GObject *object) { MetaMonitorManager *manager = META_MONITOR_MANAGER (object); + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); g_list_free_full (manager->logical_monitors, g_object_unref); + g_warn_if_fail (!priv->virtual_monitors); + g_clear_signal_handler (&manager->experimental_features_changed_handler_id, manager->backend); @@ -2894,6 +2971,18 @@ rebuild_monitors (MetaMonitorManager *manager) } } } + + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitor *virtual_monitor = l->data; + MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor); + MetaMonitorNormal *monitor_normal; + + monitor_normal = meta_monitor_normal_new (manager, output); + manager->monitors = g_list_append (manager->monitors, + monitor_normal); + + } } void @@ -3365,3 +3454,12 @@ meta_monitor_manager_get_viewports (MetaMonitorManager *manager) return info; } + +GList * +meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + + return priv->virtual_monitors; +} diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index 3c4431c4d97..b96c118d816 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -39,7 +39,8 @@ struct _MetaTileInfo uint32_t tile_h; }; -/* This matches the values in drm_mode.h */ +/* The first 17 matches the values in drm_mode.h, the ones starting with + * 1000 do not. */ typedef enum { META_CONNECTOR_TYPE_Unknown = 0, @@ -59,6 +60,8 @@ typedef enum META_CONNECTOR_TYPE_eDP = 14, META_CONNECTOR_TYPE_VIRTUAL = 15, META_CONNECTOR_TYPE_DSI = 16, + + META_CONNECTOR_TYPE_META = 1000, } MetaConnectorType; typedef struct _MetaOutputInfo diff --git a/src/backends/meta-virtual-monitor.c b/src/backends/meta-virtual-monitor.c new file mode 100644 index 00000000000..2bd95ffd7db --- /dev/null +++ b/src/backends/meta-virtual-monitor.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2021 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/meta-virtual-monitor.h" + +#include "backends/meta-crtc.h" +#include "backends/meta-crtc-mode.h" +#include "backends/meta-output.h" + +enum +{ + DESTROY, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + +enum +{ + PROP_0, + + PROP_CRTC, + PROP_CRTC_MODE, + PROP_OUTPUT, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + +typedef struct _MetaVirtualMonitorPrivate +{ + MetaCrtc *crtc; + MetaCrtcMode *crtc_mode; + MetaOutput *output; + + gboolean is_destroyed; +} MetaVirtualMonitorPrivate; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaVirtualMonitor, meta_virtual_monitor, + G_TYPE_OBJECT) + +MetaVirtualMonitorInfo * +meta_virtual_monitor_info_new (int width, + int height, + float refresh_rate, + const char *vendor, + const char *product, + const char *serial) +{ + MetaVirtualMonitorInfo *info; + + info = g_new0 (MetaVirtualMonitorInfo, 1); + info->width = width; + info->height = height; + info->refresh_rate = refresh_rate; + info->vendor = g_strdup (vendor); + info->product = g_strdup (product); + info->serial = g_strdup (serial); + + return info; +} + +void +meta_virtual_monitor_info_free (MetaVirtualMonitorInfo *info) +{ + g_free (info->vendor); + g_free (info->product); + g_free (info->serial); + g_free (info); +} + +MetaCrtc * +meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->crtc; +} + +MetaCrtcMode * +meta_virtual_monitor_get_crtc_mode (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->crtc_mode; +} + +MetaOutput * +meta_virtual_monitor_get_output (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->output; +} + +static void +meta_virtual_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + switch (prop_id) + { + case PROP_CRTC: + priv->crtc = g_value_get_object (value); + break; + case PROP_CRTC_MODE: + priv->crtc_mode = g_value_get_object (value); + break; + case PROP_OUTPUT: + priv->output = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_virtual_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + switch (prop_id) + { + case PROP_CRTC: + g_value_set_object (value, priv->crtc); + break; + case PROP_CRTC_MODE: + g_value_set_object (value, priv->crtc_mode); + break; + case PROP_OUTPUT: + g_value_set_object (value, priv->output); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_virtual_monitor_dispose (GObject *object) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + if (!priv->is_destroyed) + { + g_signal_emit (virtual_monitor, signals[DESTROY], 0); + priv->is_destroyed = TRUE; + } + + g_clear_object (&priv->crtc); + g_clear_object (&priv->crtc_mode); + g_clear_object (&priv->output); + + G_OBJECT_CLASS (meta_virtual_monitor_parent_class)->dispose (object); +} + +static void +meta_virtual_monitor_init (MetaVirtualMonitor *virtual_monitor) +{ +} + +static void +meta_virtual_monitor_class_init (MetaVirtualMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_virtual_monitor_set_property; + object_class->get_property = meta_virtual_monitor_get_property; + object_class->dispose = meta_virtual_monitor_dispose; + + obj_props[PROP_CRTC] = + g_param_spec_object ("crtc", + "crtc", + "The virtual CRTC", + META_TYPE_CRTC, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_props[PROP_CRTC_MODE] = + g_param_spec_object ("crtc-mode", + "crtc-mode", + "The virtual CRTC mode", + META_TYPE_CRTC_MODE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_props[PROP_OUTPUT] = + g_param_spec_object ("output", + "output", + "The virtual output", + META_TYPE_OUTPUT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); + + signals[DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} diff --git a/src/backends/meta-virtual-monitor.h b/src/backends/meta-virtual-monitor.h new file mode 100644 index 00000000000..f2d102f00e5 --- /dev/null +++ b/src/backends/meta-virtual-monitor.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 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. + * + */ + +#ifndef META_VIRTUAL_MONITOR_H +#define META_VIRTUAL_MONITOR_H + +#include + +#include "backends/meta-backend-types.h" +#include "core/util-private.h" + +typedef struct _MetaVirtualMonitorInfo +{ + int width; + int height; + float refresh_rate; + + char *vendor; + char *product; + char *serial; +} MetaVirtualMonitorInfo; + +#define META_TYPE_VIRTUAL_MONITOR (meta_virtual_monitor_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaVirtualMonitor, meta_virtual_monitor, + META, VIRTUAL_MONITOR, + GObject) + +struct _MetaVirtualMonitorClass +{ + GObjectClass parent_class; +}; + +MetaVirtualMonitorInfo * meta_virtual_monitor_info_new (int width, + int height, + float refresh_rate, + const char *vendor, + const char *product, + const char *serial); + +void meta_virtual_monitor_info_free (MetaVirtualMonitorInfo *info); + +MetaCrtc * meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor); + +MetaCrtcMode * meta_virtual_monitor_get_crtc_mode (MetaVirtualMonitor *virtual_monitor); + +MetaOutput * meta_virtual_monitor_get_output (MetaVirtualMonitor *virtual_monitor); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaVirtualMonitorInfo, + meta_virtual_monitor_info_free) + +#endif /* META_VIRTUAL_MONITOR_H */ diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h index 3efbca9ca43..f16f6b1d0f8 100644 --- a/src/backends/native/meta-backend-native-types.h +++ b/src/backends/native/meta-backend-native-types.h @@ -27,6 +27,8 @@ typedef struct _MetaSeatImpl MetaSeatImpl; typedef struct _MetaKeymapNative MetaKeymapNative; typedef struct _MetaRendererNative MetaRendererNative; typedef struct _MetaGpuKms MetaGpuKms; +typedef struct _MetaCrtcVirtual MetaCrtcVirtual; +typedef struct _MetaCrtcModeVirtual MetaCrtcModeVirtual; typedef enum _MetaSeatNativeFlag { diff --git a/src/backends/native/meta-crtc-mode-virtual.c b/src/backends/native/meta-crtc-mode-virtual.c new file mode 100644 index 00000000000..3bb883049e5 --- /dev/null +++ b/src/backends/native/meta-crtc-mode-virtual.c @@ -0,0 +1,70 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-crtc-mode-virtual.h" + +#include "backends/meta-virtual-monitor.h" + +struct _MetaCrtcModeVirtual +{ + MetaCrtcMode parent; +}; + +#define META_CRTC_MODE_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaCrtcModeVirtual, meta_crtc_mode_virtual, + META_TYPE_CRTC_MODE) + +MetaCrtcModeVirtual * +meta_crtc_mode_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info) +{ + g_autoptr (MetaCrtcModeInfo) crtc_mode_info = NULL; + g_autofree char *crtc_mode_name = NULL; + MetaCrtcModeVirtual *mode_virtual; + + crtc_mode_info = meta_crtc_mode_info_new (); + crtc_mode_info->width = info->width; + crtc_mode_info->height = info->height; + crtc_mode_info->refresh_rate = info->refresh_rate; + + crtc_mode_name = g_strdup_printf ("%dx%d@%f", + info->width, + info->height, + info->refresh_rate); + mode_virtual = g_object_new (META_TYPE_CRTC_MODE_VIRTUAL, + "id", META_CRTC_MODE_VIRTUAL_ID_BIT | id, + "name", crtc_mode_name, + "info", crtc_mode_info, + NULL); + + return mode_virtual; +} + +static void +meta_crtc_mode_virtual_init (MetaCrtcModeVirtual *mode_virtual) +{ +} + +static void +meta_crtc_mode_virtual_class_init (MetaCrtcModeVirtualClass *klass) +{ +} diff --git a/src/backends/native/meta-crtc-mode-virtual.h b/src/backends/native/meta-crtc-mode-virtual.h new file mode 100644 index 00000000000..e3ddb289c9e --- /dev/null +++ b/src/backends/native/meta-crtc-mode-virtual.h @@ -0,0 +1,34 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_CRTC_MODE_VIRTUAL_H +#define META_CRTC_MODE_VIRTUAL_H + +#include "backends/meta-backend-types.h" +#include "backends/meta-crtc-mode.h" + +#define META_TYPE_CRTC_MODE_VIRTUAL (meta_crtc_mode_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCrtcModeVirtual, meta_crtc_mode_virtual, + META, CRTC_MODE_VIRTUAL, + MetaCrtcMode) + +MetaCrtcModeVirtual * meta_crtc_mode_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info); + +#endif /* META_CRTC_MODE_VIRTUAL_H */ diff --git a/src/backends/native/meta-crtc-virtual.c b/src/backends/native/meta-crtc-virtual.c new file mode 100644 index 00000000000..eee346a2335 --- /dev/null +++ b/src/backends/native/meta-crtc-virtual.c @@ -0,0 +1,60 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-crtc-virtual.h" + +struct _MetaCrtcVirtual +{ + MetaCrtcNative parent; +}; + +#define META_CRTC_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaCrtcVirtual, meta_crtc_virtual, META_TYPE_CRTC_NATIVE) + +MetaCrtcVirtual * +meta_crtc_virtual_new (uint64_t id) +{ + return g_object_new (META_TYPE_CRTC_VIRTUAL, + "id", META_CRTC_VIRTUAL_ID_BIT | id, + NULL); +} + +static gboolean +meta_crtc_virtual_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + return transform == META_MONITOR_TRANSFORM_NORMAL; +} + +static void +meta_crtc_virtual_init (MetaCrtcVirtual *crtc_virtual) +{ +} + +static void +meta_crtc_virtual_class_init (MetaCrtcVirtualClass *klass) +{ + MetaCrtcNativeClass *crtc_native_class = META_CRTC_NATIVE_CLASS (klass); + + crtc_native_class->is_transform_handled = + meta_crtc_virtual_is_transform_handled; +} diff --git a/src/backends/native/meta-crtc-virtual.h b/src/backends/native/meta-crtc-virtual.h new file mode 100644 index 00000000000..89b1bcc7a6e --- /dev/null +++ b/src/backends/native/meta-crtc-virtual.h @@ -0,0 +1,32 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_CRTC_VIRTUAL_H +#define META_CRTC_VIRTUAL_H + +#include "backends/native/meta-crtc-native.h" + +#define META_TYPE_CRTC_VIRTUAL (meta_crtc_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCrtcVirtual, meta_crtc_virtual, + META, CRTC_VIRTUAL, + MetaCrtcNative) + +MetaCrtcVirtual * meta_crtc_virtual_new (uint64_t id); + +#endif /* META_CRTC_VIRTUAL_H */ diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 3d83e6e478d..098ef24bdf2 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -542,6 +542,9 @@ meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_rend META_POWER_SAVE_ON) return; + if (!meta_crtc_get_gpu (crtc)) + return; + crtc_cursor_data = ensure_crtc_cursor_data (META_CRTC_KMS (crtc)); if (!crtc_cursor_data->hw_state_invalidated && !crtc_cursor_data->needs_sync_position) @@ -849,6 +852,9 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, float scale; GList *l; + if (!gpus) + return FALSE; + if (!cursor_sprite) return FALSE; @@ -989,7 +995,7 @@ calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer, MetaGpu *gpu; gpu = meta_output_get_gpu (output); - if (!g_list_find (gpus, gpu)) + if (gpu && !g_list_find (gpus, gpu)) gpus = g_list_prepend (gpus, gpu); } } diff --git a/src/backends/native/meta-monitor-manager-native.c b/src/backends/native/meta-monitor-manager-native.c index 0b9471c255b..82cf0373eaf 100644 --- a/src/backends/native/meta-monitor-manager-native.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -59,6 +59,7 @@ #include "backends/native/meta-launcher.h" #include "backends/native/meta-output-kms.h" #include "backends/native/meta-renderer-native.h" +#include "backends/native/meta-virtual-monitor-native.h" #include "clutter/clutter.h" #include "meta/main.h" #include "meta/meta-x11-errors.h" @@ -90,6 +91,8 @@ struct _MetaMonitorManagerNativeClass MetaMonitorManagerClass parent_class; }; +#define VIRTUAL_OUTPUT_ID_BIT (((uint64_t) 1) << 63) + static void initable_iface_init (GInitableIface *initable_iface); @@ -224,6 +227,16 @@ apply_crtc_assignments (MetaMonitorManager *manager, to_configure_crtcs = g_list_concat (to_configure_crtcs, crtcs); } + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitor *virtual_monitor = l->data; + MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor); + MetaCrtc *crtc = meta_virtual_monitor_get_crtc (virtual_monitor); + + to_configure_outputs = g_list_append (to_configure_outputs, output); + to_configure_crtcs = g_list_append (to_configure_crtcs, crtc); + } + for (i = 0; i < n_crtcs; i++) { MetaCrtcAssignment *crtc_assignment = crtcs[i]; @@ -362,6 +375,8 @@ meta_monitor_manager_native_get_crtc_gamma (MetaMonitorManager *manager, MetaKmsCrtc *kms_crtc; const MetaKmsCrtcState *crtc_state; + g_return_if_fail (META_IS_CRTC_KMS (crtc)); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); crtc_state = meta_kms_crtc_get_current_state (kms_crtc); @@ -455,12 +470,17 @@ meta_monitor_manager_native_set_crtc_gamma (MetaMonitorManager *manager, { MetaMonitorManagerNative *manager_native = META_MONITOR_MANAGER_NATIVE (manager); - MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); - MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); + MetaCrtcKms *crtc_kms; + MetaKmsCrtc *kms_crtc; g_autofree char *gamma_ramp_string = NULL; MetaBackend *backend = meta_monitor_manager_get_backend (manager); ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + g_return_if_fail (META_IS_CRTC_KMS (crtc)); + + crtc_kms = META_CRTC_KMS (crtc); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); + g_hash_table_replace (manager_native->crtc_gamma_cache, GUINT_TO_POINTER (meta_crtc_get_id (crtc)), meta_kms_crtc_gamma_new (kms_crtc, size, @@ -602,6 +622,55 @@ meta_monitor_manager_native_get_default_layout_mode (MetaMonitorManager *manager return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; } +static MetaVirtualMonitorNative * +find_virtual_monitor (MetaMonitorManagerNative *manager_native, + uint64_t id) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); + GList *l; + + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitorNative *virtual_monitor_native = l->data; + + if (meta_virtual_monitor_native_get_id (virtual_monitor_native) == id) + return virtual_monitor_native; + } + + return NULL; +} + +static uint64_t +allocate_virtual_monitor_id (MetaMonitorManagerNative *manager_native) +{ + uint64_t id; + + id = 0; + + while (TRUE) + { + if (!find_virtual_monitor (manager_native, id)) + return id; + + id++; + } +} + +static MetaVirtualMonitor * +meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error) +{ + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (manager); + MetaVirtualMonitorNative *virtual_monitor_native; + uint64_t id; + + id = allocate_virtual_monitor_id (manager_native); + virtual_monitor_native = meta_virtual_monitor_native_new (id, info); + return META_VIRTUAL_MONITOR (virtual_monitor_native); +} + static void meta_monitor_manager_native_set_property (GObject *object, guint prop_id, @@ -722,6 +791,8 @@ meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) meta_monitor_manager_native_get_max_screen_size; manager_class->get_default_layout_mode = meta_monitor_manager_native_get_default_layout_mode; + manager_class->create_virtual_monitor = + meta_monitor_manager_native_create_virtual_monitor; obj_props[PROP_NEED_OUTPUTS] = g_param_spec_boolean ("needs-outputs", diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index 8fcf91ab807..024344a3cc3 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -270,6 +270,8 @@ init_output_modes (MetaOutputInfo *output_info, static MetaConnectorType meta_kms_connector_type_from_drm (uint32_t drm_connector_type) { + g_warn_if_fail (drm_connector_type < META_CONNECTOR_TYPE_META); + return (MetaConnectorType) drm_connector_type; } diff --git a/src/backends/native/meta-output-virtual.c b/src/backends/native/meta-output-virtual.c new file mode 100644 index 00000000000..12efb333881 --- /dev/null +++ b/src/backends/native/meta-output-virtual.c @@ -0,0 +1,80 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-output-virtual.h" + +#include "backends/native/meta-crtc-mode-virtual.h" +#include "backends/native/meta-crtc-virtual.h" +#include "backends/meta-virtual-monitor.h" + +struct _MetaOutputVirtual +{ + MetaOutputNative parent; +}; + +#define META_OUTPUT_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaOutputVirtual, meta_output_virtual, META_TYPE_OUTPUT_NATIVE) + +MetaOutputVirtual * +meta_output_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info, + MetaCrtcVirtual *crtc_virtual, + MetaCrtcModeVirtual *crtc_mode_virtual) +{ + g_autoptr (MetaOutputInfo) output_info = NULL; + + output_info = meta_output_info_new (); + output_info->name = g_strdup_printf ("Meta-%" G_GUINT64_FORMAT, id); + + output_info->n_possible_crtcs = 1; + output_info->possible_crtcs = g_new0 (MetaCrtc *, 1); + output_info->possible_crtcs[0] = META_CRTC (crtc_virtual); + + output_info->hotplug_mode_update = FALSE; + output_info->suggested_x = -1; + output_info->suggested_y = -1; + + output_info->connector_type = META_CONNECTOR_TYPE_META; + output_info->vendor = g_strdup (info->vendor); + output_info->product = g_strdup (info->product); + output_info->serial = g_strdup (info->serial); + + output_info->n_modes = 1; + output_info->modes = g_new0 (MetaCrtcMode *, 1); + output_info->modes[0] = META_CRTC_MODE (crtc_mode_virtual); + output_info->preferred_mode = output_info->modes[0]; + + return g_object_new (META_TYPE_OUTPUT_VIRTUAL, + "id", META_OUTPUT_VIRTUAL_ID_BIT | id, + "info", output_info, + NULL); +} + +static void +meta_output_virtual_init (MetaOutputVirtual *output_virtual) +{ +} + +static void +meta_output_virtual_class_init (MetaOutputVirtualClass *klass) +{ +} diff --git a/src/backends/native/meta-output-virtual.h b/src/backends/native/meta-output-virtual.h new file mode 100644 index 00000000000..b04579f0dec --- /dev/null +++ b/src/backends/native/meta-output-virtual.h @@ -0,0 +1,36 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_OUTPUT_VIRTUAL_H +#define META_OUTPUT_VIRTUAL_H + +#include "backends/native/meta-backend-native-types.h" +#include "backends/native/meta-output-native.h" + +#define META_TYPE_OUTPUT_VIRTUAL (meta_output_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaOutputVirtual, meta_output_virtual, + META, OUTPUT_VIRTUAL, + MetaOutputNative) + +MetaOutputVirtual * meta_output_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info, + MetaCrtcVirtual *crtc_virtual, + MetaCrtcModeVirtual *crtc_mode_virtual); + +#endif /* META_OUTPUT_VIRTUAL_H */ diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index bacf0f96e30..95d2ffd7715 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -50,6 +50,7 @@ #include "backends/meta-logical-monitor.h" #include "backends/native/meta-cogl-utils.h" #include "backends/native/meta-crtc-kms.h" +#include "backends/native/meta-crtc-virtual.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms.h" #include "backends/native/meta-onscreen-native.h" @@ -1021,13 +1022,11 @@ meta_renderer_native_create_view (MetaRenderer *renderer, CoglContext *cogl_context = cogl_context_from_renderer_native (renderer_native); CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); - CoglDisplayEGL *cogl_display_egl; - CoglOnscreenEgl *onscreen_egl; const MetaCrtcConfig *crtc_config; const MetaCrtcModeInfo *crtc_mode_info; MetaMonitorTransform view_transform; - MetaOnscreenNative *onscreen_native; - CoglOffscreen *offscreen = NULL; + g_autoptr (CoglFramebuffer) framebuffer = NULL; + g_autoptr (CoglOffscreen) offscreen = NULL; gboolean use_shadowfb; float scale; int onscreen_width; @@ -1042,16 +1041,41 @@ meta_renderer_native_create_view (MetaRenderer *renderer, onscreen_width = crtc_mode_info->width; onscreen_height = crtc_mode_info->height; - onscreen_native = meta_onscreen_native_new (renderer_native, - renderer_native->primary_gpu_kms, - output, - crtc, - cogl_context, - onscreen_width, - onscreen_height); + if (META_IS_CRTC_KMS (crtc)) + { + MetaOnscreenNative *onscreen_native; + + onscreen_native = meta_onscreen_native_new (renderer_native, + renderer_native->primary_gpu_kms, + output, + crtc, + cogl_context, + onscreen_width, + onscreen_height); + + if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) + g_error ("Failed to allocate onscreen framebuffer: %s", error->message); + + use_shadowfb = should_force_shadow_fb (renderer_native, + renderer_native->primary_gpu_kms); + framebuffer = COGL_FRAMEBUFFER (onscreen_native); + } + else + { + CoglOffscreen *virtual_onscreen; - if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) - g_error ("Failed to allocate onscreen framebuffer: %s", error->message); + g_assert (META_IS_CRTC_VIRTUAL (crtc)); + + virtual_onscreen = meta_renderer_native_create_offscreen (renderer_native, + cogl_context, + onscreen_width, + onscreen_height, + &error); + if (!virtual_onscreen) + g_error ("Failed to allocate back buffer texture: %s", error->message); + use_shadowfb = FALSE; + framebuffer = COGL_FRAMEBUFFER (virtual_onscreen); + } view_transform = calculate_view_transform (monitor_manager, logical_monitor, @@ -1082,9 +1106,6 @@ meta_renderer_native_create_view (MetaRenderer *renderer, g_error ("Failed to allocate back buffer texture: %s", error->message); } - use_shadowfb = should_force_shadow_fb (renderer_native, - renderer_native->primary_gpu_kms); - if (meta_is_stage_views_scaled ()) scale = meta_logical_monitor_get_scale (logical_monitor); else @@ -1099,25 +1120,29 @@ meta_renderer_native_create_view (MetaRenderer *renderer, "layout", &view_layout, "crtc", crtc, "scale", scale, - "framebuffer", onscreen_native, + "framebuffer", framebuffer, "offscreen", offscreen, "use-shadowfb", use_shadowfb, "transform", view_transform, "refresh-rate", crtc_mode_info->refresh_rate, NULL); - g_clear_object (&offscreen); - g_object_unref (onscreen_native); - - meta_onscreen_native_set_view (COGL_ONSCREEN (onscreen_native), view); - /* Ensure we don't point to stale surfaces when creating the offscreen */ - cogl_display_egl = cogl_display->winsys; - onscreen_egl = COGL_ONSCREEN_EGL (onscreen_native); - egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl); - _cogl_winsys_egl_make_current (cogl_display, - egl_surface, - egl_surface, - cogl_display_egl->egl_context); + if (META_IS_ONSCREEN_NATIVE (framebuffer)) + { + CoglDisplayEGL *cogl_display_egl; + CoglOnscreenEgl *onscreen_egl; + + meta_onscreen_native_set_view (COGL_ONSCREEN (framebuffer), view); + + /* Ensure we don't point to stale surfaces when creating the offscreen */ + cogl_display_egl = cogl_display->winsys; + onscreen_egl = COGL_ONSCREEN_EGL (framebuffer); + egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl); + _cogl_winsys_egl_make_current (cogl_display, + egl_surface, + egl_surface, + cogl_display_egl->egl_context); + } return view; } @@ -1165,9 +1190,16 @@ meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native, ClutterFrame *frame) { MetaCrtc *crtc = meta_renderer_view_get_crtc (view); - MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); - MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); - MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);; + MetaCrtcKms *crtc_kms; + MetaKmsCrtc *kms_crtc; + MetaKmsDevice *kms_device; + + if (!META_IS_CRTC_KMS (crtc)) + return; + + crtc_kms = META_CRTC_KMS (crtc); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); + kms_device = meta_kms_crtc_get_device (kms_crtc); meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device); } @@ -1181,9 +1213,13 @@ meta_renderer_native_finish_frame (MetaRendererNative *renderer_native, { CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view)); - CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); - meta_onscreen_native_finish_frame (onscreen, frame); + if (COGL_IS_ONSCREEN (framebuffer)) + { + CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); + + meta_onscreen_native_finish_frame (onscreen, frame); + } } } diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c index efc45c3eee4..b56acd9d465 100644 --- a/src/backends/native/meta-stage-native.c +++ b/src/backends/native/meta-stage-native.c @@ -27,6 +27,7 @@ #include "backends/native/meta-stage-native.h" #include "backends/meta-backend-private.h" +#include "backends/native/meta-crtc-virtual.h" #include "backends/native/meta-cursor-renderer-native.h" #include "backends/native/meta-renderer-native.h" #include "meta/meta-backend.h" @@ -45,6 +46,8 @@ struct _MetaStageNative int64_t presented_frame_counter_complete; }; +static ClutterStageWindowInterface *clutter_stage_window_parent_iface = NULL; + static void clutter_stage_window_iface_init (ClutterStageWindowInterface *iface); @@ -126,6 +129,24 @@ meta_stage_native_prepare_frame (ClutterStageWindow *stage_window, META_RENDERER_VIEW (stage_view)); } +static void +meta_stage_native_redraw_view (ClutterStageWindow *stage_window, + ClutterStageView *view, + ClutterFrame *frame) +{ + MetaCrtc *crtc; + + clutter_stage_window_parent_iface->redraw_view (stage_window, view, frame); + + crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (view)); + if (META_IS_CRTC_VIRTUAL (crtc)) + { + g_warn_if_fail (!clutter_frame_has_result (frame)); + + clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED); + } +} + static void meta_stage_native_finish_frame (ClutterStageWindow *stage_window, ClutterStageView *stage_view, @@ -137,6 +158,9 @@ meta_stage_native_finish_frame (ClutterStageWindow *stage_window, meta_renderer_native_finish_frame (META_RENDERER_NATIVE (renderer), META_RENDERER_VIEW (stage_view), frame); + + if (!clutter_frame_has_result (frame)) + clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); } static void @@ -156,9 +180,12 @@ meta_stage_native_class_init (MetaStageNativeClass *klass) static void clutter_stage_window_iface_init (ClutterStageWindowInterface *iface) { + clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface); + iface->can_clip_redraws = meta_stage_native_can_clip_redraws; iface->get_geometry = meta_stage_native_get_geometry; iface->get_views = meta_stage_native_get_views; iface->prepare_frame = meta_stage_native_prepare_frame; + iface->redraw_view = meta_stage_native_redraw_view; iface->finish_frame = meta_stage_native_finish_frame; } diff --git a/src/backends/native/meta-virtual-monitor-native.c b/src/backends/native/meta-virtual-monitor-native.c new file mode 100644 index 00000000000..3f81f4180e1 --- /dev/null +++ b/src/backends/native/meta-virtual-monitor-native.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 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-virtual-monitor-native.h" + +#include "backends/native/meta-crtc-mode-virtual.h" +#include "backends/native/meta-crtc-virtual.h" +#include "backends/native/meta-output-virtual.h" + +struct _MetaVirtualMonitorNative +{ + MetaVirtualMonitor parent; + + uint64_t id; +}; + +#define VIRTUAL_OUTPUT_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaVirtualMonitorNative, meta_virtual_monitor_native, + META_TYPE_VIRTUAL_MONITOR) + +uint64_t +meta_virtual_monitor_native_get_id (MetaVirtualMonitorNative *virtual_monitor_native) +{ + return virtual_monitor_native->id; +} + +MetaVirtualMonitorNative * +meta_virtual_monitor_native_new (uint64_t id, + const MetaVirtualMonitorInfo *info) +{ + MetaVirtualMonitorNative *virtual_monitor_native; + MetaCrtcVirtual *crtc_virtual; + MetaCrtcModeVirtual *crtc_mode_virtual; + MetaOutputVirtual *output_virtual; + + crtc_virtual = meta_crtc_virtual_new (id); + crtc_mode_virtual = meta_crtc_mode_virtual_new (id, info); + output_virtual = meta_output_virtual_new (id, info, + crtc_virtual, + crtc_mode_virtual); + + virtual_monitor_native = g_object_new (META_TYPE_VIRTUAL_MONITOR_NATIVE, + "crtc", crtc_virtual, + "crtc-mode", crtc_mode_virtual, + "output", output_virtual, + NULL); + virtual_monitor_native->id = id; + + return virtual_monitor_native; +} + +static void +meta_virtual_monitor_native_init (MetaVirtualMonitorNative *virtual_monitor_native) +{ +} + +static void +meta_virtual_monitor_native_class_init (MetaVirtualMonitorNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-virtual-monitor-native.h b/src/backends/native/meta-virtual-monitor-native.h new file mode 100644 index 00000000000..d1a0ced6401 --- /dev/null +++ b/src/backends/native/meta-virtual-monitor-native.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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. + * + */ + +#ifndef META_VIRTUAL_MONITOR_NATIVE_H +#define META_VIRTUAL_MONITOR_NATIVE_H + +#include + +#include "backends/meta-virtual-monitor.h" +#include "backends/meta-backend-types.h" + +#define META_TYPE_VIRTUAL_MONITOR_NATIVE (meta_virtual_monitor_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaVirtualMonitorNative, meta_virtual_monitor_native, + META, VIRTUAL_MONITOR_NATIVE, + MetaVirtualMonitor) + +uint64_t meta_virtual_monitor_native_get_id (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaCrtcMode * meta_virtual_monitor_native_get_crtc_mode (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaCrtc * meta_virtual_monitor_native_get_crtc (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaOutput * meta_virtual_monitor_native_get_output (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaVirtualMonitorNative * meta_virtual_monitor_native_new (uint64_t id, + const MetaVirtualMonitorInfo *info); + +#endif /* META_VIRTUAL_MONITOR_NATIVE_H */ diff --git a/src/meson.build b/src/meson.build index 6f52ab71412..fe3d1ccaf0b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -236,6 +236,8 @@ mutter_sources = [ 'backends/meta-stage-private.h', 'backends/meta-viewport-info.c', 'backends/meta-viewport-info.h', + 'backends/meta-virtual-monitor.c', + 'backends/meta-virtual-monitor.h', 'backends/x11/cm/meta-backend-x11-cm.c', 'backends/x11/cm/meta-backend-x11-cm.h', 'backends/x11/cm/meta-cursor-sprite-xfixes.c', @@ -649,6 +651,10 @@ if have_native_backend 'backends/native/meta-crtc-native.h', 'backends/native/meta-crtc-mode-kms.c', 'backends/native/meta-crtc-mode-kms.h', + 'backends/native/meta-crtc-mode-virtual.c', + 'backends/native/meta-crtc-mode-virtual.h', + 'backends/native/meta-crtc-virtual.c', + 'backends/native/meta-crtc-virtual.h', 'backends/native/meta-cursor-renderer-native.c', 'backends/native/meta-cursor-renderer-native.h', 'backends/native/meta-drm-buffer-dumb.c', @@ -678,6 +684,8 @@ if have_native_backend 'backends/native/meta-output-kms.h', 'backends/native/meta-output-native.c', 'backends/native/meta-output-native.h', + 'backends/native/meta-output-virtual.c', + 'backends/native/meta-output-virtual.h', 'backends/native/meta-kms-connector-private.h', 'backends/native/meta-kms-connector.c', 'backends/native/meta-kms-connector.h', @@ -732,6 +740,8 @@ if have_native_backend 'backends/native/meta-udev.h', 'backends/native/meta-virtual-input-device-native.c', 'backends/native/meta-virtual-input-device-native.h', + 'backends/native/meta-virtual-monitor-native.c', + 'backends/native/meta-virtual-monitor-native.h', 'backends/native/meta-xkb-utils.c', 'backends/native/meta-xkb-utils.h', 'compositor/meta-compositor-native.c', -- GitLab From d7ce6a47f89884d9aa381a6ab7cd85002135f5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 17:07:09 +0100 Subject: [PATCH 25/38] tests: Add reference test framework This adds a test framework that makes it possible to compare the result of painting a view against a reference image. Test reference as PNG images are stored in src/tests/ref-tests/. Reference images needs to be created for testing to be able to succeed. Adding a test reference image is done using the `MUTTER_REF_TEST_UPDATE` environment variable. See meta-ref-test.c for details. The image comparison code is largely based on the reference image test framework in weston; see meta-ref-test.c for details. Part-of: --- clutter/clutter/clutter-stage-view-private.h | 2 + src/backends/meta-monitor-manager-private.h | 1 + src/backends/meta-stage-private.h | 3 + src/backends/meta-virtual-monitor.h | 2 + src/tests/meson.build | 26 + src/tests/meta-ref-test.c | 610 ++++++++++++++++++ src/tests/meta-ref-test.h | 39 ++ src/tests/ref-test-sanity.c | 169 +++++ .../ref-tests/tests_ref-test_sanity_0.ref.png | Bin 0 -> 6749 bytes .../ref-tests/tests_ref-test_sanity_1.ref.png | Bin 0 -> 5402 bytes 10 files changed, 852 insertions(+) create mode 100644 src/tests/meta-ref-test.c create mode 100644 src/tests/meta-ref-test.h create mode 100644 src/tests/ref-test-sanity.c create mode 100644 src/tests/ref-tests/tests_ref-test_sanity_0.ref.png create mode 100644 src/tests/ref-tests/tests_ref-test_sanity_1.ref.png diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index feee44e9e5a..345b595644b 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -44,6 +44,7 @@ void clutter_stage_view_invalidate_projection (ClutterStageView *view); void clutter_stage_view_set_projection (ClutterStageView *view, const graphene_matrix_t *matrix); +CLUTTER_EXPORT void clutter_stage_view_add_redraw_clip (ClutterStageView *view, const cairo_rectangle_int_t *clip); @@ -63,6 +64,7 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView int dst_height, cairo_rectangle_int_t *dst_rect); +CLUTTER_EXPORT void clutter_stage_view_schedule_update (ClutterStageView *view); void clutter_stage_view_notify_presented (ClutterStageView *view, diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index fd30ebb58ee..61bfead0f35 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -392,6 +392,7 @@ gboolean meta_monitor_manager_get_max_screen_size (MetaMonitorManager MetaLogicalMonitorLayoutMode meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager); +META_EXPORT_TEST MetaVirtualMonitor * meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager, const MetaVirtualMonitorInfo *info, GError **error); diff --git a/src/backends/meta-stage-private.h b/src/backends/meta-stage-private.h index 03214218fdc..07534f6e39a 100644 --- a/src/backends/meta-stage-private.h +++ b/src/backends/meta-stage-private.h @@ -21,6 +21,7 @@ #define META_STAGE_PRIVATE_H #include "backends/meta-cursor.h" +#include "core/util-private.h" #include "meta/boxes.h" #include "meta/meta-stage.h" #include "meta/types.h" @@ -62,12 +63,14 @@ gboolean meta_overlay_is_visible (MetaOverlay *overlay); void meta_stage_set_active (MetaStage *stage, gboolean is_active); +META_EXPORT_TEST MetaStageWatch * meta_stage_watch_view (MetaStage *stage, ClutterStageView *view, MetaStageWatchPhase watch_mode, MetaStageWatchFunc callback, gpointer user_data); +META_EXPORT_TEST void meta_stage_remove_watch (MetaStage *stage, MetaStageWatch *watch); diff --git a/src/backends/meta-virtual-monitor.h b/src/backends/meta-virtual-monitor.h index f2d102f00e5..d1fd43356f6 100644 --- a/src/backends/meta-virtual-monitor.h +++ b/src/backends/meta-virtual-monitor.h @@ -47,6 +47,7 @@ struct _MetaVirtualMonitorClass GObjectClass parent_class; }; +META_EXPORT_TEST MetaVirtualMonitorInfo * meta_virtual_monitor_info_new (int width, int height, float refresh_rate, @@ -54,6 +55,7 @@ MetaVirtualMonitorInfo * meta_virtual_monitor_info_new (int width, const char *product, const char *serial); +META_EXPORT_TEST void meta_virtual_monitor_info_free (MetaVirtualMonitorInfo *info); MetaCrtc * meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor); diff --git a/src/tests/meson.build b/src/tests/meson.build index fbdca617c4c..816ae98109a 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -157,6 +157,11 @@ anonymous_file_test = executable('anonymous-file-tests', install_dir: mutter_installed_tests_libexecdir, ) +ref_test_sources = [ + 'meta-ref-test.c', + 'meta-ref-test.h', +] + if have_native_tests native_headless_tests = executable('mutter-native-headless-tests', sources: [ @@ -170,6 +175,20 @@ if have_native_tests install: have_installed_tests, install_dir: mutter_installed_tests_libexecdir, ) + + ref_test_sanity = executable('mutter-ref-test-sanity', + sources: [ + 'ref-test-sanity.c', + 'test-utils.c', + 'test-utils.h', + ref_test_sources, + ], + include_directories: tests_includepath, + c_args: tests_c_args, + dependencies: [tests_deps], + install: have_installed_tests, + install_dir: mutter_installed_tests_libexecdir, + ) endif stacking_tests = [ @@ -246,4 +265,11 @@ if have_native_tests is_parallel: false, timeout: 60, ) + + test('ref-test-sanity', ref_test_sanity, + suite: ['core', 'mutter/ref-test/sanity'], + env: test_env, + is_parallel: false, + timeout: 60, + ) endif diff --git a/src/tests/meta-ref-test.c b/src/tests/meta-ref-test.c new file mode 100644 index 00000000000..84ac8876d73 --- /dev/null +++ b/src/tests/meta-ref-test.c @@ -0,0 +1,610 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +/* + * The image difference code is originally a reformatted and simplified + * copy of weston-test-client-helper.c from the weston repository, with + * the following copyright and license note: + * + * Copyright © 2012 Intel Corporation + * Copyright © 2015 Samsung Electronics Co., Ltd + * Copyright 2016, 2017 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * To update or initialize reference images for tests, set the + * MUTTER_REF_TEST_UPDATE environment variable. + * + * The MUTTER_REF_TEST_UPDATE is interpreted as a comma seperated list of + * regular expressions. If the test path matches any of the regular + * expressions, the test reference image will be updated, unless the + * existing reference image is pixel identical to the newly created one. + * + * Updating test reference images also requires using a software OpenGL + * renderer, which can be achieved using LIBGL_ALWAYS_SOFTWARE=1 + * + * For example, for the test case '/path/to/test/case', run the test + * inside + * + * ``` + * env LIBGL_ALWAYS_SOFTWARE=1 MUTTER_REF_TEST_UPDATE='/path/to/test/case` + * ``` + * + */ + +#include "config.h" + +#include "tests/meta-ref-test.h" + +#include +#include + +#include "backends/meta-backend-private.h" +#include "backends/meta-stage-private.h" +#include "clutter/clutter/clutter-stage-view-private.h" + +typedef struct _Range +{ + int a; + int b; +} Range; + +typedef struct _ImageIterator +{ + uint8_t *data; + int stride; +} ImageIterator; + +typedef struct _PixelDiffStat +{ + /* Pixel diff stat channel */ + struct { + int min_diff; + int max_diff; + } ch[4]; +} PixelDiffStat; + +/** + * range_get: + * @range: Range to validate or NULL. + * + * Validate and get range. + * + * Returns the given range, or {0, 0} for NULL. + * + * Will abort if range is invalid, that is a > b. + */ +static Range +range_get (const Range *range) +{ + if (!range) + return (Range) { 0, 0 }; + + g_assert_cmpint (range->a, <=, range->b); + return *range; +} + +static void +image_iterator_init (ImageIterator *it, + cairo_surface_t *image) +{ + it->stride = cairo_image_surface_get_stride (image); + it->data = cairo_image_surface_get_data (image); + + g_assert_cmpint (cairo_image_surface_get_format (image), ==, + CAIRO_FORMAT_ARGB32); +} + +static uint32_t * +image_iterator_get_row (ImageIterator *it, + int y) +{ + return (uint32_t *) (it->data + y * it->stride); +} + +static gboolean +fuzzy_match_pixels (uint32_t pix_a, + uint32_t pix_b, + const Range *fuzz, + PixelDiffStat *diff_stat) +{ + gboolean ret = TRUE; + int shift; + int i; + + for (shift = 0, i = 0; i < 4; shift += 8, i++) + { + int val_a = (pix_a >> shift) & 0xffu; + int val_b = (pix_b >> shift) & 0xffu; + int d = val_b - val_a; + + if (diff_stat) + { + diff_stat->ch[i].min_diff = MIN (diff_stat->ch[i].min_diff, d); + diff_stat->ch[i].max_diff = MAX (diff_stat->ch[i].max_diff, d); + } + + if (d < fuzz->a || d > fuzz->b) + ret = FALSE; + } + + return ret; +} + +static gboolean +compare_images (cairo_surface_t *ref_image, + cairo_surface_t *result_image, + const Range *precision, + PixelDiffStat *diff_stat) +{ + Range fuzz = range_get (precision); + ImageIterator it_ref; + ImageIterator it_result; + int x, y; + uint32_t *pix_ref; + uint32_t *pix_result; + + g_assert_cmpint (cairo_image_surface_get_width (ref_image), ==, + cairo_image_surface_get_width (result_image)); + g_assert_cmpint (cairo_image_surface_get_height (ref_image), ==, + cairo_image_surface_get_height (result_image)); + + image_iterator_init (&it_ref, ref_image); + image_iterator_init (&it_result, result_image); + + for (y = 0; y < cairo_image_surface_get_height (ref_image); y++) + { + pix_ref = image_iterator_get_row (&it_ref, y); + pix_result = image_iterator_get_row (&it_result, y); + + for (x = 0; x < cairo_image_surface_get_width (ref_image); x++) + { + if (!fuzzy_match_pixels (*pix_ref, *pix_result, + &fuzz, diff_stat)) + return FALSE; + + pix_ref++; + pix_result++; + } + } + + return TRUE; +} + +static void +assert_software_rendered (void) +{ + MetaBackend *backend = meta_get_backend (); + + g_assert_false (meta_backend_is_rendering_hardware_accelerated (backend)); +} + +static void +capture_view_into (ClutterStageView *view, + MetaRectangle *rect, + uint8_t *buffer, + int stride) +{ + CoglFramebuffer *framebuffer; + ClutterBackend *backend; + CoglContext *context; + CoglBitmap *bitmap; + cairo_rectangle_int_t view_layout; + float view_scale; + float texture_width; + float texture_height; + int x, y; + + framebuffer = clutter_stage_view_get_framebuffer (view); + + view_scale = clutter_stage_view_get_scale (view); + texture_width = roundf (rect->width * view_scale); + texture_height = roundf (rect->height * view_scale); + + backend = clutter_get_default_backend (); + context = clutter_backend_get_cogl_context (backend); + bitmap = cogl_bitmap_new_for_data (context, + texture_width, texture_height, + CLUTTER_CAIRO_FORMAT_ARGB32, + stride, + buffer); + + clutter_stage_view_get_layout (view, &view_layout); + + x = roundf ((rect->x - view_layout.x) * view_scale); + y = roundf ((rect->y - view_layout.y) * view_scale); + cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + x, y, + COGL_READ_PIXELS_COLOR_BUFFER, + bitmap); + + cogl_object_unref (bitmap); +} + +typedef struct +{ + MetaStageWatch *watch; + GMainLoop *loop; + + cairo_surface_t *out_image; +} CaptureViewData; + +static void +on_after_paint (MetaStage *stage, + ClutterStageView *view, + ClutterPaintContext *paint_context, + gpointer user_data) +{ + CaptureViewData *data = user_data; + MetaRectangle rect; + float view_scale; + int texture_width, texture_height; + cairo_surface_t *image; + uint8_t *buffer; + int stride; + + meta_stage_remove_watch (stage, data->watch); + data->watch = NULL; + + clutter_stage_view_get_layout (view, &rect); + view_scale = clutter_stage_view_get_scale (view); + texture_width = roundf (rect.width * view_scale); + texture_height = roundf (rect.height * view_scale); + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + texture_width, texture_height); + cairo_surface_set_device_scale (image, view_scale, view_scale); + + buffer = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + + capture_view_into (view, &rect, buffer, stride); + + data->out_image = image; + + cairo_surface_mark_dirty (data->out_image); + + g_main_loop_quit (data->loop); +} + +static cairo_surface_t * +capture_view (ClutterStageView *view) +{ + MetaBackend *backend = meta_get_backend (); + MetaStage *stage = META_STAGE (meta_backend_get_stage (backend)); + CaptureViewData data = { 0 }; + + data.loop = g_main_loop_new (NULL, FALSE); + data.watch = meta_stage_watch_view (stage, view, + META_STAGE_WATCH_AFTER_PAINT, + on_after_paint, + &data); + clutter_stage_view_add_redraw_clip (view, NULL); + clutter_stage_view_schedule_update (view); + + g_main_loop_run (data.loop); + g_main_loop_unref (data.loop); + + g_assert_null (data.watch); + g_assert_nonnull (data.out_image); + + return data.out_image; +} + +static void +depathify (char *path) +{ + int len = strlen (path); + int i; + + for (i = 0; i < len; i++) + { + if (path[i] == '/') + path[i] = '_'; + } +} + +static void +ensure_expected_format (cairo_surface_t **ref_image) +{ + int width, height; + cairo_surface_t *target; + cairo_t *cr; + + if (cairo_image_surface_get_format (*ref_image) == + CAIRO_FORMAT_ARGB32) + return; + + width = cairo_image_surface_get_width (*ref_image); + height = cairo_image_surface_get_height (*ref_image); + target = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + + cr = cairo_create (target); + cairo_set_source_surface (cr, *ref_image, 0.0, 0.0); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_surface_destroy (*ref_image); + *ref_image = target; +} + +/** + * Tint a color: + * @src Source pixel as x8r8g8b8. + * @add The tint as x8r8g8b8, x8 must be zero; r8, g8 and b8 must be + * no greater than 0xc0 to avoid overflow to another channel. + * Returns: The tinted pixel color as x8r8g8b8, x8 guaranteed to be 0xff. + * + * The source pixel RGB values are divided by 4, and then the tint is added. + * To achieve colors outside of the range of src, a tint color channel must be + * at least 0x40. (0xff / 4 = 0x3f, 0xff - 0x3f = 0xc0) + */ +static uint32_t +tint (uint32_t src, + uint32_t add) +{ + uint32_t v; + + v = ((src & 0xfcfcfcfc) >> 2) | 0xff000000; + + return v + add; +} + +static cairo_surface_t * +visualize_difference (cairo_surface_t *ref_image, + cairo_surface_t *result_image, + const Range *precision) +{ + Range fuzz = range_get (precision); + int width, height; + cairo_surface_t *diff_image; + cairo_t *cr; + ImageIterator it_ref; + ImageIterator it_result; + ImageIterator it_diff; + int y; + + width = cairo_image_surface_get_width (ref_image); + height = cairo_image_surface_get_height (ref_image); + + diff_image = cairo_surface_create_similar_image (ref_image, + CAIRO_FORMAT_ARGB32, + width, + height); + cr = cairo_create (diff_image); + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); + cairo_paint (cr); + cairo_set_source_surface (cr, ref_image, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY); + cairo_paint (cr); + cairo_destroy (cr); + + image_iterator_init (&it_ref, ref_image); + image_iterator_init (&it_result, result_image); + image_iterator_init (&it_diff, diff_image); + + for (y = 0; y < cairo_image_surface_get_height (ref_image); y++) + { + uint32_t *ref_pixel; + uint32_t *result_pixel; + uint32_t *diff_pixel; + int x; + + ref_pixel = image_iterator_get_row (&it_ref, y); + result_pixel = image_iterator_get_row (&it_result, y); + diff_pixel = image_iterator_get_row (&it_diff, y); + + for (x = 0; x < cairo_image_surface_get_width (ref_image); x++) + { + if (fuzzy_match_pixels (*ref_pixel, *result_pixel, + &fuzz, NULL)) + *diff_pixel = tint (*diff_pixel, 0x00008000); /* green */ + else + *diff_pixel = tint (*diff_pixel, 0x00c00000); /* red */ + + ref_pixel++; + result_pixel++; + diff_pixel++; + } + } + + return diff_image; +} + +void +meta_ref_test_verify_view (ClutterStageView *view, + const char *test_name_unescaped, + int test_seq_no, + MetaReftestFlag flags) +{ + cairo_surface_t *view_image; + const char *dist_dir; + g_autofree char *test_name = NULL; + g_autofree char *ref_image_path = NULL; + cairo_surface_t *ref_image; + cairo_status_t ref_status; + + if (flags & META_REFTEST_FLAG_UPDATE_REF) + assert_software_rendered (); + + view_image = capture_view (view); + + test_name = g_strdup (test_name_unescaped + 1); + depathify (test_name); + + dist_dir = g_test_get_dir (G_TEST_DIST); + ref_image_path = g_strdup_printf ("%s/tests/ref-tests/%s_%d.ref.png", + dist_dir, + test_name, test_seq_no); + + ref_image = cairo_image_surface_create_from_png (ref_image_path); + g_assert_nonnull (ref_image); + ref_status = cairo_surface_status (ref_image); + + if (flags & META_REFTEST_FLAG_UPDATE_REF) + { + g_assert (ref_status == CAIRO_STATUS_FILE_NOT_FOUND || + ref_status == CAIRO_STATUS_SUCCESS); + + if (ref_status == CAIRO_STATUS_SUCCESS) + ensure_expected_format (&ref_image); + + if (ref_status == CAIRO_STATUS_SUCCESS && + cairo_image_surface_get_width (ref_image) == + cairo_image_surface_get_width (view_image) && + cairo_image_surface_get_height (ref_image) == + cairo_image_surface_get_height (view_image) && + compare_images (ref_image, view_image, NULL, NULL)) + { + g_message ("Not updating '%s', it didn't change.", ref_image_path); + } + else + { + g_message ("Updating '%s'.", ref_image_path); + g_assert_cmpint (cairo_surface_write_to_png (view_image, ref_image_path), + ==, + CAIRO_STATUS_SUCCESS); + } + } + else + { + const Range gl_fuzz = { -3, 4 }; + PixelDiffStat diff_stat = {}; + + g_assert_cmpint (ref_status, ==, CAIRO_STATUS_SUCCESS); + ensure_expected_format (&ref_image); + + if (!compare_images (ref_image, view_image, &gl_fuzz, + &diff_stat)) + { + cairo_surface_t *diff_image; + const char *build_dir; + g_autofree char *ref_image_copy_path = NULL; + g_autofree char *result_image_path = NULL; + g_autofree char *diff_image_path = NULL; + + diff_image = visualize_difference (ref_image, view_image, + &gl_fuzz); + + build_dir = g_test_get_dir (G_TEST_BUILT); + ref_image_copy_path = + g_strdup_printf ("%s/meson-logs/tests/ref-tests/%s_%d.ref.png", + build_dir, + test_name, test_seq_no); + result_image_path = + g_strdup_printf ("%s/meson-logs/tests/ref-tests/%s_%d.result.png", + build_dir, + test_name, test_seq_no); + diff_image_path = + g_strdup_printf ("%s/meson-logs/tests/ref-tests/%s_%d.diff.png", + build_dir, + test_name, test_seq_no); + + g_mkdir_with_parents (g_path_get_dirname (ref_image_copy_path), + 0755); + + g_assert_cmpint (cairo_surface_write_to_png (ref_image, + ref_image_copy_path), + ==, + CAIRO_STATUS_SUCCESS); + g_assert_cmpint (cairo_surface_write_to_png (view_image, + result_image_path), + ==, + CAIRO_STATUS_SUCCESS); + g_assert_cmpint (cairo_surface_write_to_png (diff_image, + diff_image_path), + ==, + CAIRO_STATUS_SUCCESS); + + g_critical ("Pixel difference exceeds limits " + "(min: [%d, %d, %d, %d], " + "max: [%d, %d, %d, %d])\n" + "See %s, %s, and %s for details.", + diff_stat.ch[0].min_diff, + diff_stat.ch[1].min_diff, + diff_stat.ch[2].min_diff, + diff_stat.ch[3].min_diff, + diff_stat.ch[0].max_diff, + diff_stat.ch[1].max_diff, + diff_stat.ch[2].max_diff, + diff_stat.ch[3].max_diff, + ref_image_copy_path, + result_image_path, + diff_image_path); + } + } + + cairo_surface_destroy (view_image); + cairo_surface_destroy (ref_image); +} + +MetaReftestFlag +meta_ref_test_determine_ref_test_flag (void) +{ + const char *update_tests; + char **update_test_rules; + int n_update_test_rules; + MetaReftestFlag flags; + int i; + + update_tests = g_getenv ("MUTTER_REF_TEST_UPDATE"); + if (!update_tests) + return META_REFTEST_FLAG_NONE; + + if (strcmp (update_tests, "all") == 0) + return META_REFTEST_FLAG_UPDATE_REF; + + update_test_rules = g_strsplit (update_tests, ",", -1); + n_update_test_rules = g_strv_length (update_test_rules); + g_assert_cmpint (n_update_test_rules, >, 0); + + flags = META_REFTEST_FLAG_NONE; + for (i = 0; i < n_update_test_rules; i++) + { + char *rule = update_test_rules[i]; + + if (g_regex_match_simple (rule, g_test_get_path (), 0, 0)) + { + flags |= META_REFTEST_FLAG_UPDATE_REF; + break; + } + } + + g_strfreev (update_test_rules); + + return flags; +} diff --git a/src/tests/meta-ref-test.h b/src/tests/meta-ref-test.h new file mode 100644 index 00000000000..7a71e388f0b --- /dev/null +++ b/src/tests/meta-ref-test.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef META_REF_TEST_H +#define META_REF_TEST_H + +#include + +#include "clutter/clutter/clutter.h" +#include "meta/boxes.h" + +typedef enum _MetaReftestFlag +{ + META_REFTEST_FLAG_NONE = 0, + META_REFTEST_FLAG_UPDATE_REF = 1 << 0, +} MetaReftestFlag; + +void meta_ref_test_verify_view (ClutterStageView *view, + const char *test_name, + int test_seq_no, + MetaReftestFlag flags); + +MetaReftestFlag meta_ref_test_determine_ref_test_flag (void); + +#endif /* META_REF_TEST_H */ diff --git a/src/tests/ref-test-sanity.c b/src/tests/ref-test-sanity.c new file mode 100644 index 00000000000..91710feeb86 --- /dev/null +++ b/src/tests/ref-test-sanity.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "config.h" + +#include "backends/meta-virtual-monitor.h" +#include "backends/native/meta-renderer-native.h" +#include "compositor/meta-plugin-manager.h" +#include "core/main-private.h" +#include "meta/main.h" +#include "tests/meta-ref-test.h" +#include "tests/test-utils.h" + +static MetaVirtualMonitor *virtual_monitor; + +static void +setup_test_environment (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaSettings *settings = meta_backend_get_settings (backend); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + g_autoptr (MetaVirtualMonitorInfo) monitor_info = NULL; + GError *error = NULL; + GList *views; + + meta_settings_override_experimental_features (settings); + meta_settings_enable_experimental_feature ( + settings, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER); + + monitor_info = meta_virtual_monitor_info_new (100, 100, 60.0, + "MetaTestVendor", + "MetaVirtualMonitor", + "0x1234"); + virtual_monitor = meta_monitor_manager_create_virtual_monitor (monitor_manager, + monitor_info, + &error); + if (!virtual_monitor) + g_error ("Failed to create virtual monitor: %s", error->message); + + meta_monitor_manager_reload (monitor_manager); + + views = meta_renderer_get_views (renderer); + g_assert_cmpint (g_list_length (views), ==, 1); +} + +static void +tear_down_test_environment (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + + g_object_unref (virtual_monitor); + meta_monitor_manager_reload (monitor_manager); +} + +static gboolean +run_tests (gpointer data) +{ + int ret; + + setup_test_environment (); + + ret = g_test_run (); + + tear_down_test_environment (); + + meta_quit (ret != 0); + + return ret; +} + +static ClutterStageView * +get_view (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + + return CLUTTER_STAGE_VIEW (meta_renderer_get_views (renderer)->data); +} + +static void +meta_test_ref_test_sanity (void) +{ + MetaBackend *backend = meta_get_backend (); + ClutterActor *stage = meta_backend_get_stage (backend); + ClutterActor *actor1; + ClutterActor *actor2; + + meta_ref_test_verify_view (get_view (), + g_test_get_path (), 0, + meta_ref_test_determine_ref_test_flag ()); + + actor1 = clutter_actor_new (); + clutter_actor_set_position (actor1, 10, 10); + clutter_actor_set_size (actor1, 50, 50); + clutter_actor_set_background_color (actor1, CLUTTER_COLOR_Orange); + clutter_actor_add_child (stage, actor1); + + meta_ref_test_verify_view (get_view (), + g_test_get_path (), 1, + meta_ref_test_determine_ref_test_flag ()); + + actor2 = clutter_actor_new (); + clutter_actor_set_position (actor2, 20, 20); + clutter_actor_set_size (actor2, 50, 50); + clutter_actor_set_background_color (actor2, CLUTTER_COLOR_SkyBlue); + clutter_actor_add_child (stage, actor2); + + g_test_expect_message (G_LOG_DOMAIN, + G_LOG_LEVEL_CRITICAL, + "Pixel difference exceeds limits*"); + + meta_ref_test_verify_view (get_view (), + g_test_get_path (), 1, + meta_ref_test_determine_ref_test_flag ()); + + g_test_assert_expected_messages (); + + clutter_actor_destroy (actor2); + clutter_actor_destroy (actor1); +} + +static void +init_ref_test_sanity_tests (void) +{ + g_test_add_func ("/tests/ref-test/sanity", + meta_test_ref_test_sanity); +} + +int +main (int argc, + char **argv) +{ + test_init (&argc, &argv); + init_ref_test_sanity_tests (); + + meta_plugin_manager_load (test_get_plugin_name ()); + + meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, + META_TYPE_BACKEND_NATIVE, + "headless", TRUE, + NULL); + + meta_init (); + meta_register_with_session (); + + g_idle_add (run_tests, NULL); + + return meta_run (); +} diff --git a/src/tests/ref-tests/tests_ref-test_sanity_0.ref.png b/src/tests/ref-tests/tests_ref-test_sanity_0.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..f434827f89f9f708cbbf7c08873e72cbffb35938 GIT binary patch literal 6749 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 Ef_*!JbN~PV literal 0 HcmV?d00001 -- GitLab From 51ff51c854176ff52185774f44a1db9cdd75f251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 17:42:51 +0100 Subject: [PATCH 26/38] tests: Add virtual monitor tests The testing currently done is: * Creating a virtual monitor succeeds and gets the right configuration * Painting a few times results in the expected output * Changing the content of the stage also changes the painted content accordingly * Destroying the virtual monitor works as expected Part-of: --- src/backends/meta-monitor-manager-private.h | 1 + src/backends/meta-monitor.h | 1 + src/backends/meta-virtual-monitor.h | 1 + src/tests/meson.build | 3 + src/tests/native-headless.c | 2 + src/tests/native-virtual-monitor.c | 135 ++++++++++++++++++ src/tests/native-virtual-monitor.h | 26 ++++ ...ds_native_virtual-monitor_create_0.ref.png | Bin 0 -> 3509 bytes ...ds_native_virtual-monitor_create_1.ref.png | Bin 0 -> 2610 bytes 9 files changed, 169 insertions(+) create mode 100644 src/tests/native-virtual-monitor.c create mode 100644 src/tests/native-virtual-monitor.h create mode 100644 src/tests/ref-tests/backends_native_virtual-monitor_create_0.ref.png create mode 100644 src/tests/ref-tests/backends_native_virtual-monitor_create_1.ref.png diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 61bfead0f35..e191b50d0f6 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -397,6 +397,7 @@ MetaVirtualMonitor * meta_monitor_manager_create_virtual_monitor (MetaMonitorMan const MetaVirtualMonitorInfo *info, GError **error); +META_EXPORT_TEST MetaMonitorConfigManager * meta_monitor_manager_get_config_manager (MetaMonitorManager *manager); diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index eceb645c22f..341657ae3ce 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -65,6 +65,7 @@ typedef enum _MetaMonitorScalesConstraint } MetaMonitorScalesConstraint; #define META_TYPE_MONITOR (meta_monitor_get_type ()) +META_EXPORT_TEST G_DECLARE_DERIVABLE_TYPE (MetaMonitor, meta_monitor, META, MONITOR, GObject) struct _MetaMonitorClass diff --git a/src/backends/meta-virtual-monitor.h b/src/backends/meta-virtual-monitor.h index d1fd43356f6..2b733df9ccb 100644 --- a/src/backends/meta-virtual-monitor.h +++ b/src/backends/meta-virtual-monitor.h @@ -62,6 +62,7 @@ MetaCrtc * meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor); MetaCrtcMode * meta_virtual_monitor_get_crtc_mode (MetaVirtualMonitor *virtual_monitor); +META_EXPORT_TEST MetaOutput * meta_virtual_monitor_get_output (MetaVirtualMonitor *virtual_monitor); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaVirtualMonitorInfo, diff --git a/src/tests/meson.build b/src/tests/meson.build index 816ae98109a..e570db8c624 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -166,8 +166,11 @@ if have_native_tests native_headless_tests = executable('mutter-native-headless-tests', sources: [ 'native-headless.c', + 'native-virtual-monitor.c', + 'native-virtual-monitor.h', 'test-utils.c', 'test-utils.h', + ref_test_sources, ], include_directories: tests_includepath, c_args: tests_c_args, diff --git a/src/tests/native-headless.c b/src/tests/native-headless.c index 4929fa221cc..1b3d4a26c4d 100644 --- a/src/tests/native-headless.c +++ b/src/tests/native-headless.c @@ -26,11 +26,13 @@ #include "core/main-private.h" #include "meta/main.h" #include "meta/meta-backend.h" +#include "tests/native-virtual-monitor.h" #include "tests/test-utils.h" static void init_tests (void) { + init_virtual_monitor_tests (); } static gboolean diff --git a/src/tests/native-virtual-monitor.c b/src/tests/native-virtual-monitor.c new file mode 100644 index 00000000000..15fc78f8877 --- /dev/null +++ b/src/tests/native-virtual-monitor.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2021 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 "tests/native-virtual-monitor.h" + +#include "backends/meta-backend-private.h" +#include "backends/meta-logical-monitor.h" +#include "backends/meta-monitor-config-manager.h" +#include "backends/meta-virtual-monitor.h" +#include "backends/native/meta-renderer-native.h" +#include "tests/meta-ref-test.h" + +static void +meta_test_virtual_monitor_create (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); + MetaMonitorConfigManager *config_manager = + meta_monitor_manager_get_config_manager (monitor_manager); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaVirtualMonitor *virtual_monitor; + g_autoptr (MetaVirtualMonitorInfo) monitor_info = NULL; + GError *error = NULL; + GList *monitors; + MetaMonitor *monitor; + MetaMonitorsConfig *monitors_config; + GList *logical_monitors; + GList *logical_monitor_monitors; + GList *views; + int i; + ClutterActor *actor; + + g_assert_null (meta_monitor_config_manager_get_current (config_manager)); + g_assert_null (meta_monitor_manager_get_logical_monitors (monitor_manager)); + g_assert_null (meta_monitor_manager_get_monitors (monitor_manager)); + g_assert_null (meta_renderer_get_views (renderer)); + + monitor_info = meta_virtual_monitor_info_new (80, 60, 60.0, + "MetaTestVendor", + "MetaVirtualMonitor", + "0x1234"); + virtual_monitor = meta_monitor_manager_create_virtual_monitor (monitor_manager, + monitor_info, + &error); + if (!virtual_monitor) + g_error ("Failed to create virtual monitor: %s", error->message); + + meta_monitor_manager_reload (monitor_manager); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpint (g_list_length (monitors), ==, 1); + monitor = META_MONITOR (monitors->data); + g_assert_cmpstr (meta_monitor_get_vendor (monitor), ==, "MetaTestVendor"); + g_assert_cmpstr (meta_monitor_get_product (monitor), ==, "MetaVirtualMonitor"); + g_assert_cmpstr (meta_monitor_get_serial (monitor), ==, "0x1234"); + g_assert (meta_monitor_get_main_output (monitor) == + meta_virtual_monitor_get_output (virtual_monitor)); + + monitors_config = meta_monitor_manager_ensure_configured (monitor_manager); + g_assert_nonnull (monitors_config); + g_assert_cmpint (g_list_length (monitors_config->logical_monitor_configs), + ==, + 1); + + g_assert_cmpint (g_list_length (monitors_config->disabled_monitor_specs), + ==, + 0); + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpint (g_list_length (logical_monitors), ==, 1); + logical_monitor_monitors = + meta_logical_monitor_get_monitors (logical_monitors->data); + g_assert_cmpint (g_list_length (logical_monitor_monitors), ==, 1); + g_assert (logical_monitor_monitors->data == monitor); + + views = meta_renderer_get_views (renderer); + g_assert_cmpint (g_list_length (views), ==, 1); + + for (i = 0; i < 5; i++) + { + meta_ref_test_verify_view (CLUTTER_STAGE_VIEW (views->data), + g_test_get_path (), 0, + meta_ref_test_determine_ref_test_flag ()); + } + + actor = clutter_actor_new (); + clutter_actor_set_position (actor, 10, 10); + clutter_actor_set_size (actor, 40, 40); + clutter_actor_set_background_color (actor, CLUTTER_COLOR_LightSkyBlue); + clutter_actor_add_child (meta_backend_get_stage (backend), actor); + + for (i = 0; i < 5; i++) + { + meta_ref_test_verify_view (CLUTTER_STAGE_VIEW (views->data), + g_test_get_path (), 1, + meta_ref_test_determine_ref_test_flag ()); + } + + g_object_unref (virtual_monitor); + meta_monitor_manager_reload (monitor_manager); + + g_assert_null (meta_monitor_manager_ensure_configured (monitor_manager)); + g_assert_null (meta_monitor_manager_get_logical_monitors (monitor_manager)); + g_assert_null (meta_monitor_manager_get_monitors (monitor_manager)); + g_assert_null (meta_renderer_get_views (renderer)); + + clutter_actor_destroy (actor); +} + +void +init_virtual_monitor_tests (void) +{ + g_test_add_func ("/backends/native/virtual-monitor/create", + meta_test_virtual_monitor_create); +} diff --git a/src/tests/native-virtual-monitor.h b/src/tests/native-virtual-monitor.h new file mode 100644 index 00000000000..0c4c34f02c0 --- /dev/null +++ b/src/tests/native-virtual-monitor.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 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. + * + */ + +#ifndef NATIVE_VIRTUAL_MONITOR_H +#define NATIVE_VIRTUAL_MONITOR_H + +void init_virtual_monitor_tests (void); + +#endif /* NATIVE_VIRTUAL_MONITOR_H */ diff --git a/src/tests/ref-tests/backends_native_virtual-monitor_create_0.ref.png b/src/tests/ref-tests/backends_native_virtual-monitor_create_0.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..55ed4d9e0f6ba46531c0e3f21b020f21b7d73d9f GIT binary patch literal 3509 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 UBDE=yw*UYD07*qoM6N<$g6vKtKL7v# literal 0 HcmV?d00001 -- GitLab From 005c49063d65c6dc0d2db8a1c9fa01005ab9ac84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Jan 2021 23:04:37 +0100 Subject: [PATCH 27/38] main: Add --virtual-monitor argument Make it possible to create persintent virtual monitors using command line argument. This will not be the only way to create virtual monitors, the primary way will be using the screen cast API, but using command line argumenst is convenient for debugging purposes. Part-of: --- src/core/main.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/core/main.c b/src/core/main.c index e204b68ffe6..6b26990c6a8 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -76,6 +76,8 @@ #endif #include "backends/meta-backend-private.h" +#include "backends/meta-monitor-manager-private.h" +#include "backends/meta-virtual-monitor.h" #include "backends/x11/cm/meta-backend-x11-cm.h" #include "backends/x11/meta-backend-x11.h" #include "clutter/clutter.h" @@ -140,6 +142,10 @@ static GMainLoop *meta_main_loop = NULL; static void prefs_changed_callback (MetaPreference pref, gpointer data); +#ifdef HAVE_NATIVE_BACKEND +static void release_virtual_monitors (void); +#endif + /** * meta_print_compilation_info: * @@ -213,6 +219,13 @@ static gboolean opt_headless; #endif static gboolean opt_x11; +#ifdef HAVE_NATIVE_BACKEND +static gboolean opt_virtual_monitor_cb (const char *option_name, + const char *value, + gpointer data, + GError **error); +#endif + static GOptionEntry meta_options[] = { { "sm-disable", 0, 0, G_OPTION_ARG_NONE, @@ -286,6 +299,11 @@ static GOptionEntry meta_options[] = { &opt_headless, N_("Run as a headless display server") }, + { + "virtual-monitor", 0, 0, G_OPTION_ARG_CALLBACK, + &opt_virtual_monitor_cb, + N_("Add persistent virtual monitor (WxH or WxH@R)") + }, #endif { "x11", 0, 0, G_OPTION_ARG_NONE, @@ -358,6 +376,10 @@ meta_finalize (void) meta_wayland_finalize (); #endif +#ifdef HAVE_NATIVE_BACKEND + release_virtual_monitors (); +#endif + meta_release_backend (); } @@ -458,6 +480,92 @@ check_for_wayland_session_type (void) } #endif +#ifdef HAVE_NATIVE_BACKEND +static GList *opt_virtual_monitor_infos = NULL; + +static GList *persistent_virtual_monitors = NULL; + +static gboolean +opt_virtual_monitor_cb (const char *option_name, + const char *value, + gpointer data, + GError **error) +{ + int width, height; + float refresh_rate = 60.0; + + if (sscanf (value, "%dx%d@%f", + &width, &height, &refresh_rate) == 3 || + sscanf (value, "%dx%d", + &width, &height) == 2) + { + g_autofree char *serial = NULL; + MetaVirtualMonitorInfo *virtual_monitor; + + serial = g_strdup_printf ("0x%.2x", + g_list_length (opt_virtual_monitor_infos)); + virtual_monitor = meta_virtual_monitor_info_new (width, + height, + refresh_rate, + "MetaVendor", + "MetaVirtualMonitor", + serial); + opt_virtual_monitor_infos = g_list_append (opt_virtual_monitor_infos, + virtual_monitor); + return TRUE; + } + else + { + return FALSE; + } +} + +static void +release_virtual_monitors (void) +{ + g_list_free_full (persistent_virtual_monitors, g_object_unref); + persistent_virtual_monitors = NULL; +} + +static void +add_persistent_virtual_monitors (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + GList *l; + + for (l = opt_virtual_monitor_infos; l; l = l->next) + { + MetaVirtualMonitorInfo *info = l->data; + g_autoptr (GError) error = NULL; + MetaVirtualMonitor *virtual_monitor; + + virtual_monitor = + meta_monitor_manager_create_virtual_monitor (monitor_manager, + info, + &error); + if (!virtual_monitor) + { + g_warning ("Failed to add virtual monitor: %s", error->message); + meta_exit (META_EXIT_ERROR); + } + + persistent_virtual_monitors = g_list_append (persistent_virtual_monitors, + virtual_monitor); + } + + if (opt_virtual_monitor_infos) + { + g_list_free_full (opt_virtual_monitor_infos, + (GDestroyNotify) meta_virtual_monitor_info_free); + opt_virtual_monitor_infos = NULL; + + meta_monitor_manager_reload (monitor_manager); + } +} +#endif + /* * Determine the compositor configuration, i.e. whether to run as a Wayland * compositor, as well as what backend to use. @@ -751,6 +859,10 @@ meta_init (void) g_array_free (_backend_property_values, TRUE); } +#ifdef HAVE_NATIVE_BACKEND + add_persistent_virtual_monitors (); +#endif + meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); if (opt_replace_wm) -- GitLab From 9b1b4eb843aaababb797c57d91e8d2dd3bf7c72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 27 Jan 2021 23:14:29 +0100 Subject: [PATCH 28/38] clutter: Expose 'capture_view_into()` as API It'll be used to explicitly capture the content of a single view. Part-of: --- clutter/clutter/clutter-mutter.h | 7 +++++++ clutter/clutter/clutter-stage.c | 34 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index 8f4e2390a01..88dee26587f 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -54,6 +54,13 @@ void clutter_stage_capture_into (ClutterStage *stage, cairo_rectangle_int_t *rect, uint8_t *data); +CLUTTER_EXPORT +void clutter_stage_capture_view_into (ClutterStage *stage, + ClutterStageView *view, + cairo_rectangle_int_t *rect, + uint8_t *data, + int stride); + CLUTTER_EXPORT void clutter_stage_clear_stage_views (ClutterStage *stage); diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 6e46187c59c..5b574b5e15e 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -175,11 +175,6 @@ static const ClutterColor default_stage_color = { 255, 255, 255, 255 }; static void free_queue_redraw_entry (QueueRedrawEntry *entry); static void free_pointer_device_entry (PointerDeviceEntry *entry); -static void capture_view_into (ClutterStage *stage, - ClutterStageView *view, - cairo_rectangle_int_t *rect, - uint8_t *data, - int stride); static void clutter_stage_update_view_perspective (ClutterStage *stage); static void clutter_stage_set_viewport (ClutterStage *stage, float width, @@ -3227,12 +3222,12 @@ clutter_stage_paint_to_buffer (ClutterStage *stage, return TRUE; } -static void -capture_view_into (ClutterStage *stage, - ClutterStageView *view, - cairo_rectangle_int_t *rect, - uint8_t *data, - int stride) +void +clutter_stage_capture_view_into (ClutterStage *stage, + ClutterStageView *view, + cairo_rectangle_int_t *rect, + uint8_t *data, + int stride) { CoglFramebuffer *framebuffer; ClutterBackend *backend; @@ -3247,6 +3242,11 @@ capture_view_into (ClutterStage *stage, framebuffer = clutter_stage_view_get_framebuffer (view); + clutter_stage_view_get_layout (view, &view_layout); + + if (!rect) + rect = &view_layout; + view_scale = clutter_stage_view_get_scale (view); texture_width = roundf (rect->width * view_scale); texture_height = roundf (rect->height * view_scale); @@ -3259,8 +3259,6 @@ capture_view_into (ClutterStage *stage, stride, data); - clutter_stage_view_get_layout (view, &view_layout); - cogl_framebuffer_read_pixels_into_bitmap (framebuffer, roundf ((rect->x - view_layout.x) * view_scale), roundf ((rect->y - view_layout.y) * view_scale), @@ -3300,10 +3298,12 @@ clutter_stage_capture_into (ClutterStage *stage, x_offset = capture_rect.x - rect->x; y_offset = capture_rect.y - rect->y; - capture_view_into (stage, view, - &capture_rect, - data + (x_offset * bpp) + (y_offset * stride), - stride); + clutter_stage_capture_view_into (stage, view, + &capture_rect, + (data + + (x_offset * bpp) + + (y_offset * stride)), + stride); } } -- GitLab From 688280f82d69d2c2102ab0519098d9201d9a827b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 30 Jan 2021 23:52:00 +0100 Subject: [PATCH 29/38] remote-desktop/session: Handle unable to transform coordinate gracefully There may be a race between the ability to turn stream relative input coordinates and turning them into screen coordinates, due to the future scenario where the entity backing a stream is created and managed ad-hoc depending on PipeWire stream negotiations. When an input event is sent during this time, drop it. Part-of: --- src/backends/meta-remote-desktop-session.c | 52 +++++++++++++------ src/backends/meta-screen-cast-area-stream.c | 4 +- .../meta-screen-cast-monitor-stream.c | 4 +- src/backends/meta-screen-cast-stream.c | 10 ++-- src/backends/meta-screen-cast-stream.h | 20 +++---- src/backends/meta-screen-cast-window-stream.c | 3 +- 6 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c index 4429c356705..1f83ff709e7 100644 --- a/src/backends/meta-remote-desktop-session.c +++ b/src/backends/meta-remote-desktop-session.c @@ -678,11 +678,17 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_absolute_motion (session->virtual_pointer, - CLUTTER_CURRENT_TIME, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_absolute_motion (session->virtual_pointer, + CLUTTER_CURRENT_TIME, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early absolute pointer motion (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_pointer_motion_absolute (skeleton, invocation); @@ -731,12 +737,18 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_touch_down (session->virtual_touchscreen, - CLUTTER_CURRENT_TIME, - slot, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_touch_down (session->virtual_touchscreen, + CLUTTER_CURRENT_TIME, + slot, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early touch down (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_touch_down (skeleton, invocation); @@ -786,12 +798,18 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_touch_motion (session->virtual_touchscreen, - CLUTTER_CURRENT_TIME, - slot, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_touch_motion (session->virtual_touchscreen, + CLUTTER_CURRENT_TIME, + slot, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early touch motion (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_touch_motion (skeleton, invocation); diff --git a/src/backends/meta-screen-cast-area-stream.c b/src/backends/meta-screen-cast-area-stream.c index 9dd59fbfe6b..23d8c982800 100644 --- a/src/backends/meta-screen-cast-area-stream.c +++ b/src/backends/meta-screen-cast-area-stream.c @@ -148,7 +148,7 @@ meta_screen_cast_area_stream_set_parameters (MetaScreenCastStream *stream, area_stream->area.height)); } -static void +static gboolean meta_screen_cast_area_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -160,6 +160,8 @@ meta_screen_cast_area_stream_transform_position (MetaScreenCastStream *stream, *x = area_stream->area.x + (int) roundf (stream_x / area_stream->scale); *y = area_stream->area.y + (int) roundf (stream_y / area_stream->scale); + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index d3ad20b3c1e..c7123a19b04 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -184,7 +184,7 @@ meta_screen_cast_monitor_stream_set_parameters (MetaScreenCastStream *stream, logical_monitor_layout.height)); } -static void +static gboolean meta_screen_cast_monitor_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -200,6 +200,8 @@ meta_screen_cast_monitor_stream_transform_position (MetaScreenCastStream *stream *x = logical_monitor_layout.x + stream_x; *y = logical_monitor_layout.y + stream_y; + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c index fed1560fe4c..b8ab5abd576 100644 --- a/src/backends/meta-screen-cast-stream.c +++ b/src/backends/meta-screen-cast-stream.c @@ -177,18 +177,16 @@ meta_screen_cast_stream_get_src (MetaScreenCastStream *stream) return priv->src; } -void +gboolean meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, double *x, double *y) { - META_SCREEN_CAST_STREAM_GET_CLASS (stream)->transform_position (stream, - stream_x, - stream_y, - x, - y); + MetaScreenCastStreamClass *klass = META_SCREEN_CAST_STREAM_GET_CLASS (stream); + + return klass->transform_position (stream, stream_x, stream_y, x, y); } MetaScreenCastCursorMode diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h index d121c15c1e4..3424def20c9 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -43,11 +43,11 @@ struct _MetaScreenCastStreamClass GError **error); void (* set_parameters) (MetaScreenCastStream *stream, GVariantBuilder *parameters_builder); - void (* transform_position) (MetaScreenCastStream *stream, - double stream_x, - double stream_y, - double *x, - double *y); + gboolean (* transform_position) (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y); }; MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream); @@ -61,11 +61,11 @@ char * meta_screen_cast_stream_get_object_path (MetaScreenCastStream *stream); MetaScreenCastStreamSrc * meta_screen_cast_stream_get_src (MetaScreenCastStream *stream); -void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, - double stream_x, - double stream_y, - double *x, - double *y); +gboolean meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y); MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream); diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c index 4c235d150ed..6f42a446e8d 100644 --- a/src/backends/meta-screen-cast-window-stream.c +++ b/src/backends/meta-screen-cast-window-stream.c @@ -128,7 +128,7 @@ meta_screen_cast_window_stream_set_parameters (MetaScreenCastStream *stream, window_stream->logical_height)); } -static void +static gboolean meta_screen_cast_window_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -145,6 +145,7 @@ meta_screen_cast_window_stream_transform_position (MetaScreenCastStream *stream, stream_y, x, y); + return TRUE; } static void -- GitLab From cf5836a6ecdafbfe34a75eafb03ccb2cde383e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 1 Feb 2021 09:54:56 +0100 Subject: [PATCH 30/38] screen-cast/src: Add helper to close stream after dispatch This is needed to close the stream from non-abstract sources during PipeWire dispatch. Part-of: --- src/backends/meta-screen-cast-stream-src.c | 23 ++++++++++++---------- src/backends/meta-screen-cast-stream-src.h | 2 ++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c index 484a879b989..610679dcc7f 100644 --- a/src/backends/meta-screen-cast-stream-src.c +++ b/src/backends/meta-screen-cast-stream-src.c @@ -640,6 +640,17 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src) priv->is_enabled = FALSE; } +void +meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + + if (meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_disable (src); + priv->emit_closed_after_dispatch = TRUE; +} + static void on_stream_state_changed (void *data, enum pw_stream_state old, @@ -654,9 +665,7 @@ on_stream_state_changed (void *data, { case PW_STREAM_STATE_ERROR: g_warning ("pipewire stream error: %s", error_message); - if (meta_screen_cast_stream_src_is_enabled (src)) - meta_screen_cast_stream_src_disable (src); - priv->emit_closed_after_dispatch = TRUE; + meta_screen_cast_stream_src_close (src); break; case PW_STREAM_STATE_PAUSED: if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream) @@ -942,17 +951,11 @@ on_core_error (void *data, const char *message) { MetaScreenCastStreamSrc *src = data; - MetaScreenCastStreamSrcPrivate *priv = - meta_screen_cast_stream_src_get_instance_private (src); g_warning ("pipewire remote error: id:%u %s", id, message); if (id == PW_ID_CORE && res == -EPIPE) - { - if (meta_screen_cast_stream_src_is_enabled (src)) - meta_screen_cast_stream_src_disable (src); - priv->emit_closed_after_dispatch = TRUE; - } + meta_screen_cast_stream_src_close (src); } static gboolean diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h index 3eaebf62c5d..08c18153417 100644 --- a/src/backends/meta-screen-cast-stream-src.h +++ b/src/backends/meta-screen-cast-stream-src.h @@ -76,6 +76,8 @@ struct _MetaScreenCastStreamSrcClass struct spa_meta_cursor *spa_meta_cursor); }; +void meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src); + void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src, MetaScreenCastRecordFlag flags); -- GitLab From 2fbde287207d56215431e9ff78d211ee6c529e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 1 Feb 2021 10:41:57 +0100 Subject: [PATCH 31/38] screen-cast/src: Allow for source with adaptive stream size The area source, window source, and monitor source, currently set up the stream size up front, given the area, maximum allowed window size or monitor resolution, but for to be introduced sources, the size will be negotiated using PipeWire, instead of specified via the D-Bus API. This commit changes the internal source API to allow for this. There are currently no users of this new behaviour. Part-of: --- .../meta-screen-cast-area-stream-src.c | 4 +- .../meta-screen-cast-monitor-stream-src.c | 4 +- src/backends/meta-screen-cast-stream-src.c | 81 +++++++++++++------ src/backends/meta-screen-cast-stream-src.h | 11 ++- .../meta-screen-cast-window-stream-src.c | 4 +- 5 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/backends/meta-screen-cast-area-stream-src.c b/src/backends/meta-screen-cast-area-stream-src.c index b7de04d7b6a..91251cc63b1 100644 --- a/src/backends/meta-screen-cast-area-stream-src.c +++ b/src/backends/meta-screen-cast-area-stream-src.c @@ -83,7 +83,7 @@ get_backend (MetaScreenCastAreaStreamSrc *area_src) return meta_screen_cast_get_backend (screen_cast); } -static void +static gboolean meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -100,6 +100,8 @@ meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = (int) roundf (area->width * scale); *height = (int) roundf (area->height * scale); *frame_rate = 60.0; + + return TRUE; } static gboolean diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 6753f176a77..008cd6de702 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -87,7 +87,7 @@ get_monitor (MetaScreenCastMonitorStreamSrc *monitor_src) return meta_screen_cast_monitor_stream_get_monitor (monitor_stream); } -static void +static gboolean meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -112,6 +112,8 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = (int) roundf (logical_monitor->rect.width * scale); *height = (int) roundf (logical_monitor->rect.height * scale); *frame_rate = meta_monitor_mode_get_refresh_rate (mode); + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c index 610679dcc7f..c3ede8aea8e 100644 --- a/src/backends/meta-screen-cast-stream-src.c +++ b/src/backends/meta-screen-cast-stream-src.c @@ -47,6 +47,14 @@ (sizeof (struct spa_meta_cursor) + \ sizeof (struct spa_meta_bitmap) + width * height * 4) +#define DEFAULT_SIZE SPA_RECTANGLE (1280, 720) +#define MIN_SIZE SPA_RECTANGLE (1, 1) +#define MAX_SIZE SPA_RECTANGLE (16384, 16386) + +#define DEFAULT_FRAME_RATE SPA_FRACTION (60, 1) +#define MIN_FRAME_RATE SPA_FRACTION (1, 1) +#define MAX_FRAME_RATE SPA_FRACTION (1000, 1) + enum { PROP_0, @@ -107,7 +115,7 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastStreamSrc, meta_screen_cast_stream_src_init_initable_iface) G_ADD_PRIVATE (MetaScreenCastStreamSrc)) -static void +static gboolean meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -116,7 +124,7 @@ meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src, MetaScreenCastStreamSrcClass *klass = META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); - klass->get_specs (src, width, height, frame_rate); + return klass->get_specs (src, width, height, frame_rate); } static gboolean @@ -694,6 +702,8 @@ on_stream_param_changed (void *data, MetaScreenCastStreamSrc *src = data; MetaScreenCastStreamSrcPrivate *priv = meta_screen_cast_stream_src_get_instance_private (src); + MetaScreenCastStreamSrcClass *klass = + META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); uint8_t params_buffer[1024]; int32_t width, height, stride, size; struct spa_pod_builder pod_builder; @@ -737,6 +747,9 @@ on_stream_param_changed (void *data, SPA_PARAM_META_size, SPA_POD_Int (CURSOR_META_SIZE (384, 384))); pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params)); + + if (klass->notify_params_updated) + klass->notify_params_updated (src, &priv->video_format); } static void @@ -884,9 +897,6 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, int width; int height; float frame_rate; - MetaFraction frame_rate_fraction; - struct spa_fraction max_framerate; - struct spa_fraction min_framerate; const struct spa_pod *params[1]; int result; @@ -903,24 +913,49 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, return NULL; } - meta_screen_cast_stream_src_get_specs (src, &width, &height, &frame_rate); - frame_rate_fraction = meta_fraction_from_double (frame_rate); - - min_framerate = SPA_FRACTION (1, 1); - max_framerate = SPA_FRACTION (frame_rate_fraction.num, - frame_rate_fraction.denom); - - params[0] = spa_pod_builder_add_object ( - &pod_builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&SPA_RECTANGLE (width, height)), - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_CHOICE_RANGE_Fraction (&max_framerate, - &min_framerate, - &max_framerate)); + if (meta_screen_cast_stream_src_get_specs (src, &width, &height, &frame_rate)) + { + MetaFraction frame_rate_fraction; + struct spa_fraction max_framerate; + struct spa_fraction min_framerate; + + frame_rate_fraction = meta_fraction_from_double (frame_rate); + + min_framerate = SPA_FRACTION (1, 1); + max_framerate = SPA_FRACTION (frame_rate_fraction.num, + frame_rate_fraction.denom); + + params[0] = spa_pod_builder_add_object ( + &pod_builder, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&SPA_RECTANGLE (width, + height)), + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), + SPA_FORMAT_VIDEO_maxFramerate, + SPA_POD_CHOICE_RANGE_Fraction (&max_framerate, + &min_framerate, + &max_framerate)); + } + else + { + params[0] = spa_pod_builder_add_object ( + &pod_builder, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&DEFAULT_SIZE, + &MIN_SIZE, + &MAX_SIZE), + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), + SPA_FORMAT_VIDEO_maxFramerate, + SPA_POD_CHOICE_RANGE_Fraction (&DEFAULT_FRAME_RATE, + &MIN_FRAME_RATE, + &MAX_FRAME_RATE)); + } pw_stream_add_listener (pipewire_stream, &priv->pipewire_stream_listener, diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h index 08c18153417..456b5bd9780 100644 --- a/src/backends/meta-screen-cast-stream-src.h +++ b/src/backends/meta-screen-cast-stream-src.h @@ -53,10 +53,10 @@ struct _MetaScreenCastStreamSrcClass { GObjectClass parent_class; - void (* get_specs) (MetaScreenCastStreamSrc *src, - int *width, - int *height, - float *frame_rate); + gboolean (* get_specs) (MetaScreenCastStreamSrc *src, + int *width, + int *height, + float *frame_rate); void (* enable) (MetaScreenCastStreamSrc *src); void (* disable) (MetaScreenCastStreamSrc *src); gboolean (* record_to_buffer) (MetaScreenCastStreamSrc *src, @@ -74,6 +74,9 @@ struct _MetaScreenCastStreamSrcClass MetaRectangle *crop_rect); void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src, struct spa_meta_cursor *spa_meta_cursor); + + void (* notify_params_updated) (MetaScreenCastStreamSrc *src, + struct spa_video_info_raw *video_format); }; void meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src); diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c index 014a97c3247..3fa932b4b17 100644 --- a/src/backends/meta-screen-cast-window-stream-src.c +++ b/src/backends/meta-screen-cast-window-stream-src.c @@ -275,7 +275,7 @@ capture_into (MetaScreenCastWindowStreamSrc *window_src, return TRUE; } -static void +static gboolean meta_screen_cast_window_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -287,6 +287,8 @@ meta_screen_cast_window_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = get_stream_width (window_src); *height = get_stream_height (window_src); *frame_rate = 60.0f; + + return TRUE; } static gboolean -- GitLab From 74ab2120fa1c79eed0d2fb872430c0b1c774b5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 1 Feb 2021 10:57:35 +0100 Subject: [PATCH 32/38] screen-cast/session: Introduce RecordVirtual D-Bus API The new RecordVirtual API creates a virtual monitor, i.e. a region of the stage that isn't backed by real monitor hardware. It's intended to be used by e.g. network screens on active sessions, virtual remote desktop screens when running headless, and scenarios like that. A major difference between the current Record* API's is that RecordVirtual relies on PipeWire itself to negotiate the refresh rate and size, as it can't rely on any existing monitor, for those details. This also means that the virtual monitor is not created until the stream negotiation has finished and a virtual monitor resolution has been determined. Part-of: --- src/backends/meta-screen-cast-session.c | 79 +++ .../meta-screen-cast-virtual-stream-src.c | 612 ++++++++++++++++++ .../meta-screen-cast-virtual-stream-src.h | 38 ++ .../meta-screen-cast-virtual-stream.c | 121 ++++ .../meta-screen-cast-virtual-stream.h | 40 ++ src/backends/meta-screen-cast.h | 1 + src/meson.build | 4 + src/org.gnome.Mutter.ScreenCast.xml | 29 + 8 files changed, 924 insertions(+) create mode 100644 src/backends/meta-screen-cast-virtual-stream-src.c create mode 100644 src/backends/meta-screen-cast-virtual-stream-src.h create mode 100644 src/backends/meta-screen-cast-virtual-stream.c create mode 100644 src/backends/meta-screen-cast-virtual-stream.h diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 10c37ee886c..3925738d47c 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -30,6 +30,7 @@ #include "backends/meta-screen-cast-area-stream.h" #include "backends/meta-screen-cast-monitor-stream.h" #include "backends/meta-screen-cast-stream.h" +#include "backends/meta-screen-cast-virtual-stream.h" #include "backends/meta-screen-cast-window-stream.h" #include "core/display-private.h" @@ -600,6 +601,83 @@ handle_record_area (MetaDBusScreenCastSession *skeleton, return TRUE; } +static gboolean +handle_record_virtual (MetaDBusScreenCastSession *skeleton, + GDBusMethodInvocation *invocation, + GVariant *properties_variant) +{ + MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (skeleton); + GDBusInterfaceSkeleton *interface_skeleton; + GDBusConnection *connection; + MetaScreenCastCursorMode cursor_mode; + gboolean is_platform; + MetaScreenCastFlag flags; + g_autoptr (GError) error = NULL; + MetaScreenCastVirtualStream *virtual_stream; + MetaScreenCastStream *stream; + char *stream_path; + + if (!check_permission (session, invocation)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "Permission denied"); + return TRUE; + } + + if (!g_variant_lookup (properties_variant, "cursor-mode", "u", &cursor_mode)) + { + cursor_mode = META_SCREEN_CAST_CURSOR_MODE_HIDDEN; + } + else + { + if (!is_valid_cursor_mode (cursor_mode)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Unknown cursor mode"); + return TRUE; + } + } + + if (!g_variant_lookup (properties_variant, "is-platform", "b", &is_platform)) + is_platform = FALSE; + + interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton); + connection = g_dbus_interface_skeleton_get_connection (interface_skeleton); + + flags = META_SCREEN_CAST_FLAG_NONE; + if (is_platform) + flags |= META_SCREEN_CAST_FLAG_IS_PLATFORM; + + virtual_stream = meta_screen_cast_virtual_stream_new (session, + connection, + cursor_mode, + flags, + &error); + if (!virtual_stream) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Failed to record virtual: %s", + error->message); + return TRUE; + } + + stream = META_SCREEN_CAST_STREAM (virtual_stream); + stream_path = meta_screen_cast_stream_get_object_path (stream); + + session->streams = g_list_append (session->streams, stream); + + g_signal_connect (stream, "closed", G_CALLBACK (on_stream_closed), session); + + meta_dbus_screen_cast_session_complete_record_virtual (skeleton, + invocation, + stream_path); + + return TRUE; +} + static void meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface) { @@ -608,6 +686,7 @@ meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface) iface->handle_record_monitor = handle_record_monitor; iface->handle_record_window = handle_record_window; iface->handle_record_area = handle_record_area; + iface->handle_record_virtual = handle_record_virtual; } static void diff --git a/src/backends/meta-screen-cast-virtual-stream-src.c b/src/backends/meta-screen-cast-virtual-stream-src.c new file mode 100644 index 00000000000..47a917da980 --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream-src.c @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2021 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/meta-screen-cast-virtual-stream-src.h" + +#include "backends/meta-crtc-mode.h" +#include "backends/meta-cursor-tracker-private.h" +#include "backends/meta-screen-cast-session.h" +#include "backends/meta-stage-private.h" +#include "backends/meta-virtual-monitor.h" +#include "core/boxes-private.h" + +struct _MetaScreenCastVirtualStreamSrc +{ + MetaScreenCastStreamSrc parent; + + MetaVirtualMonitor *virtual_monitor; + + gboolean cursor_bitmap_invalid; + gboolean hw_cursor_inhibited; + + MetaStageWatch *watch; + + gulong position_invalidated_handler_id; + gulong cursor_changed_handler_id; + + gulong monitors_changed_handler_id; +}; + +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaScreenCastVirtualStreamSrc, + meta_screen_cast_virtual_stream_src, + META_TYPE_SCREEN_CAST_STREAM_SRC, + G_IMPLEMENT_INTERFACE (META_TYPE_HW_CURSOR_INHIBITOR, + hw_cursor_inhibitor_iface_init)) + +static gboolean +meta_screen_cast_virtual_stream_src_get_specs (MetaScreenCastStreamSrc *src, + int *width, + int *height, + float *frame_rate) +{ + return FALSE; +} + +static MetaBackend * +backend_from_src (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + + return meta_screen_cast_get_backend (screen_cast); +} + +static ClutterStageView * +view_from_src (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaVirtualMonitor *virtual_monitor = virtual_src->virtual_monitor; + MetaCrtc *crtc = meta_virtual_monitor_get_crtc (virtual_monitor); + MetaRenderer *renderer = meta_backend_get_renderer (backend_from_src (src)); + MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc); + + return CLUTTER_STAGE_VIEW (view); +} + +static ClutterStage * +stage_from_src (MetaScreenCastStreamSrc *src) +{ + return CLUTTER_STAGE (meta_backend_get_stage (backend_from_src (src))); +} + +static gboolean +is_redraw_queued (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + + return clutter_stage_is_redraw_queued_on_view (stage_from_src (src), + view_from_src (src)); +} + +ClutterStageView * +meta_screen_cast_virtual_stream_src_get_view (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + return view_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); +} + +static void +sync_cursor_state (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaScreenCastRecordFlag flags; + + if (is_redraw_queued (virtual_src)) + return; + + if (meta_screen_cast_stream_src_pending_follow_up_frame (src)) + return; + + flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY; + meta_screen_cast_stream_src_maybe_record_frame (src, flags); +} + +static void +pointer_position_invalidated (MetaCursorTracker *cursor_tracker, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + sync_cursor_state (virtual_src); +} + +static void +cursor_changed (MetaCursorTracker *cursor_tracker, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + virtual_src->cursor_bitmap_invalid = TRUE; + sync_cursor_state (virtual_src); +} + +static void +inhibit_hw_cursor (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; + + g_return_if_fail (!virtual_src->hw_cursor_inhibited); + + backend = backend_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); + inhibitor = META_HW_CURSOR_INHIBITOR (virtual_src); + meta_backend_add_hw_cursor_inhibitor (backend, inhibitor); + + virtual_src->hw_cursor_inhibited = TRUE; +} + +static void +uninhibit_hw_cursor (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; + + g_return_if_fail (virtual_src->hw_cursor_inhibited); + + backend = backend_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); + inhibitor = META_HW_CURSOR_INHIBITOR (virtual_src); + meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor); + + virtual_src->hw_cursor_inhibited = FALSE; +} + +static void +actors_painted (MetaStage *stage, + ClutterStageView *view, + ClutterPaintContext *paint_context, + gpointer user_data) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data); + MetaScreenCastRecordFlag flags; + + flags = META_SCREEN_CAST_RECORD_FLAG_NONE; + meta_screen_cast_stream_src_maybe_record_frame (src, flags); +} + +static void +add_watch (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaStage *meta_stage = META_STAGE (stage_from_src (src)); + + g_return_if_fail (!virtual_src->watch); + + virtual_src->watch = meta_stage_watch_view (meta_stage, + view_from_src (src), + META_STAGE_WATCH_AFTER_PAINT, + actors_painted, + virtual_src); +} + +static void +on_monitors_changed (MetaMonitorManager *monitor_manager, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaStage *stage = META_STAGE (stage_from_src (src)); + + meta_stage_remove_watch (stage, virtual_src->watch); + virtual_src->watch = NULL; + add_watch (virtual_src); +} + +static void +init_record_callbacks (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + virtual_src->position_invalidated_handler_id = + g_signal_connect_after (cursor_tracker, "position-invalidated", + G_CALLBACK (pointer_position_invalidated), + virtual_src); + virtual_src->cursor_changed_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-changed", + G_CALLBACK (cursor_changed), + virtual_src); + G_GNUC_FALLTHROUGH; + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + add_watch (virtual_src); + break; + } + + if (meta_screen_cast_stream_get_cursor_mode (stream) == + META_SCREEN_CAST_CURSOR_MODE_EMBEDDED) + inhibit_hw_cursor (virtual_src); + + virtual_src->monitors_changed_handler_id = + g_signal_connect (monitor_manager, "monitors-changed-internal", + G_CALLBACK (on_monitors_changed), + virtual_src); +} + +static void +meta_screen_cast_virtual_stream_src_enable (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + meta_cursor_tracker_track_position (cursor_tracker); + break; + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } + + init_record_callbacks (virtual_src); + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage_from_src (src)), + NULL); + clutter_stage_schedule_update (stage_from_src (src)); +} + +static void +meta_screen_cast_virtual_stream_src_disable (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + + if (virtual_src->hw_cursor_inhibited) + uninhibit_hw_cursor (virtual_src); + + if (virtual_src->watch) + { + meta_stage_remove_watch (META_STAGE (stage_from_src (src)), + virtual_src->watch); + virtual_src->watch = NULL; + } + + g_clear_signal_handler (&virtual_src->position_invalidated_handler_id, + cursor_tracker); + g_clear_signal_handler (&virtual_src->cursor_changed_handler_id, + cursor_tracker); + + g_clear_signal_handler (&virtual_src->monitors_changed_handler_id, + monitor_manager); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + meta_cursor_tracker_untrack_position (cursor_tracker); + break; + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } + + g_clear_object (&virtual_src->virtual_monitor); +} + +static gboolean +meta_screen_cast_virtual_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src, + int width, + int height, + int stride, + uint8_t *data, + GError **error) +{ + clutter_stage_capture_view_into (stage_from_src (src), + view_from_src (src), + NULL, + data, + stride); + + return TRUE; +} + +static gboolean +meta_screen_cast_virtual_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src, + CoglFramebuffer *framebuffer, + GError **error) +{ + ClutterStageView *view; + CoglFramebuffer *view_framebuffer; + + view = view_from_src (src); + view_framebuffer = clutter_stage_view_get_framebuffer (view); + if (!cogl_blit_framebuffer (view_framebuffer, + framebuffer, + 0, 0, + 0, 0, + cogl_framebuffer_get_width (view_framebuffer), + cogl_framebuffer_get_height (view_framebuffer), + error)) + return FALSE; + + cogl_framebuffer_flush (framebuffer); + return TRUE; +} + +static void +meta_screen_cast_virtual_stream_record_follow_up (MetaScreenCastStreamSrc *src) +{ + MetaRectangle damage; + + clutter_stage_view_get_layout (view_from_src (src), &damage); + damage.width = 1; + damage.height = 1; + + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage_from_src (src)), + &damage); +} + +static gboolean +is_cursor_in_stream (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + ClutterStageView *stage_view = view_from_src (src); + MetaRectangle view_layout; + graphene_rect_t view_rect; + MetaCursorSprite *cursor_sprite; + + clutter_stage_view_get_layout (stage_view, &view_layout); + view_rect = meta_rectangle_to_graphene_rect (&view_layout); + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (cursor_sprite) + { + graphene_rect_t cursor_rect; + + cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, + cursor_sprite); + return graphene_rect_intersection (&cursor_rect, &view_rect, NULL); + } + else + { + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + graphene_point_t cursor_position; + + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); + return graphene_rect_contains_point (&view_rect, + &cursor_position); + } +} + +static void +meta_screen_cast_virtual_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + MetaCursorSprite *cursor_sprite; + ClutterStageView *stage_view; + MetaRectangle view_layout; + float view_scale; + graphene_rect_t view_rect; + graphene_point_t cursor_position; + int x, y; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + + if (!meta_cursor_tracker_get_pointer_visible (cursor_tracker) || + !is_cursor_in_stream (virtual_src)) + { + meta_screen_cast_stream_src_unset_cursor_metadata (src, + spa_meta_cursor); + return; + } + + stage_view = view_from_src (src); + clutter_stage_view_get_layout (stage_view, &view_layout); + view_rect = meta_rectangle_to_graphene_rect (&view_layout); + view_scale = clutter_stage_view_get_scale (stage_view); + + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); + cursor_position.x -= view_rect.origin.x; + cursor_position.y -= view_rect.origin.y; + cursor_position.x *= view_scale; + cursor_position.y *= view_scale; + + x = (int) roundf (cursor_position.x); + y = (int) roundf (cursor_position.y); + + if (virtual_src->cursor_bitmap_invalid) + { + if (cursor_sprite) + { + float cursor_scale; + float scale; + + cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); + scale = view_scale * cursor_scale; + meta_screen_cast_stream_src_set_cursor_sprite_metadata (src, + spa_meta_cursor, + cursor_sprite, + x, y, + scale); + } + else + { + meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src, + spa_meta_cursor, + x, y); + } + + virtual_src->cursor_bitmap_invalid = FALSE; + } + else + { + meta_screen_cast_stream_src_set_cursor_position_metadata (src, + spa_meta_cursor, + x, y); + } +} + +static MetaVirtualMonitor * +create_virtual_monitor (MetaScreenCastVirtualStreamSrc *virtual_src, + struct spa_video_info_raw *video_format, + GError **error) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + static int virtual_monitor_src_seq = 0; + int width, height; + float refresh_rate; + g_autofree char *serial = NULL; + g_autoptr (MetaVirtualMonitorInfo) info = NULL; + + width = video_format->size.width; + height = video_format->size.height; + refresh_rate = ((float) video_format->max_framerate.num / + video_format->max_framerate.denom); + serial = g_strdup_printf ("0x%.6x", ++virtual_monitor_src_seq); + info = meta_virtual_monitor_info_new (width, height, refresh_rate, + "MetaVendor", + "Virtual remote monitor", + serial); + return meta_monitor_manager_create_virtual_monitor (monitor_manager, + info, + error); +} + +static void +ensure_virtual_monitor (MetaScreenCastVirtualStreamSrc *virtual_src, + struct spa_video_info_raw *video_format) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + g_autoptr (GError) error = NULL; + MetaVirtualMonitor *virtual_monitor; + + virtual_monitor = virtual_src->virtual_monitor; + if (virtual_monitor) + { + MetaCrtcMode *crtc_mode = + meta_virtual_monitor_get_crtc_mode (virtual_monitor); + const MetaCrtcModeInfo *mode_info = meta_crtc_mode_get_info (crtc_mode); + + if (mode_info->width == video_format->size.width && + mode_info->height == video_format->size.height) + return; + + g_clear_object (&virtual_src->virtual_monitor); + } + + virtual_monitor = create_virtual_monitor (virtual_src, video_format, &error); + if (!virtual_monitor) + { + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + + g_warning ("Failed to create virtual monitor with size %dx%d: %s", + video_format->size.width, video_format->size.height, + error->message); + meta_screen_cast_stream_src_close (src); + return; + } + virtual_src->virtual_monitor = virtual_monitor; + + meta_monitor_manager_reload (monitor_manager); +} + +static void +meta_screen_cast_virtual_stream_src_notify_params_updated (MetaScreenCastStreamSrc *src, + struct spa_video_info_raw *video_format) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + + ensure_virtual_monitor (virtual_src, video_format); +} + +MetaScreenCastVirtualStreamSrc * +meta_screen_cast_virtual_stream_src_new (MetaScreenCastVirtualStream *virtual_stream, + GError **error) +{ + return g_initable_new (META_TYPE_SCREEN_CAST_VIRTUAL_STREAM_SRC, NULL, error, + "stream", virtual_stream, + NULL); +} + +static gboolean +meta_screen_cast_virtual_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (inhibitor); + + return is_cursor_in_stream (virtual_src); +} + +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface) +{ + iface->is_cursor_inhibited = + meta_screen_cast_virtual_stream_src_is_cursor_inhibited; +} + +static void +meta_screen_cast_virtual_stream_src_init (MetaScreenCastVirtualStreamSrc *virtual_src) +{ +} + +static void +meta_screen_cast_virtual_stream_src_class_init (MetaScreenCastVirtualStreamSrcClass *klass) +{ + MetaScreenCastStreamSrcClass *src_class = + META_SCREEN_CAST_STREAM_SRC_CLASS (klass); + + src_class->get_specs = meta_screen_cast_virtual_stream_src_get_specs; + src_class->enable = meta_screen_cast_virtual_stream_src_enable; + src_class->disable = meta_screen_cast_virtual_stream_src_disable; + src_class->record_to_buffer = + meta_screen_cast_virtual_stream_src_record_to_buffer; + src_class->record_to_framebuffer = + meta_screen_cast_virtual_stream_src_record_to_framebuffer; + src_class->record_follow_up = + meta_screen_cast_virtual_stream_record_follow_up; + src_class->set_cursor_metadata = + meta_screen_cast_virtual_stream_src_set_cursor_metadata; + src_class->notify_params_updated = + meta_screen_cast_virtual_stream_src_notify_params_updated; +} diff --git a/src/backends/meta-screen-cast-virtual-stream-src.h b/src/backends/meta-screen-cast-virtual-stream-src.h new file mode 100644 index 00000000000..a891166bd75 --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream-src.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 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. + * + */ + +#ifndef META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H +#define META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H + +#include "backends/meta-screen-cast-stream-src.h" +#include "backends/meta-screen-cast-virtual-stream.h" + +#define META_TYPE_SCREEN_CAST_VIRTUAL_STREAM_SRC (meta_screen_cast_virtual_stream_src_get_type ()) +G_DECLARE_FINAL_TYPE (MetaScreenCastVirtualStreamSrc, + meta_screen_cast_virtual_stream_src, + META, SCREEN_CAST_VIRTUAL_STREAM_SRC, + MetaScreenCastStreamSrc) + +MetaScreenCastVirtualStreamSrc * meta_screen_cast_virtual_stream_src_new (MetaScreenCastVirtualStream *virtual_stream, + GError **error); + +ClutterStageView * meta_screen_cast_virtual_stream_src_get_view (MetaScreenCastVirtualStreamSrc *virtual_src); + +#endif /* META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H */ diff --git a/src/backends/meta-screen-cast-virtual-stream.c b/src/backends/meta-screen-cast-virtual-stream.c new file mode 100644 index 00000000000..34dd2a00ccc --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 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/meta-screen-cast-virtual-stream.h" + +#include "backends/meta-screen-cast-virtual-stream-src.h" +#include "backends/meta-virtual-monitor.h" + + +struct _MetaScreenCastVirtualStream +{ + MetaScreenCastStream parent; +}; + +G_DEFINE_TYPE (MetaScreenCastVirtualStream, + meta_screen_cast_virtual_stream, + META_TYPE_SCREEN_CAST_STREAM) + +MetaScreenCastVirtualStream * +meta_screen_cast_virtual_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaScreenCastCursorMode cursor_mode, + MetaScreenCastFlag flags, + GError **error) +{ + MetaScreenCastVirtualStream *virtual_stream; + + virtual_stream = g_initable_new (META_TYPE_SCREEN_CAST_VIRTUAL_STREAM, + NULL, + error, + "session", session, + "connection", connection, + "cursor-mode", cursor_mode, + "flags", flags, + NULL); + if (!virtual_stream) + return NULL; + + return virtual_stream; +} + +static MetaScreenCastStreamSrc * +meta_screen_cast_virtual_stream_create_src (MetaScreenCastStream *stream, + GError **error) +{ + MetaScreenCastVirtualStream *virtual_stream = + META_SCREEN_CAST_VIRTUAL_STREAM (stream); + MetaScreenCastVirtualStreamSrc *virtual_stream_src; + + virtual_stream_src = meta_screen_cast_virtual_stream_src_new (virtual_stream, + error); + if (!virtual_stream_src) + return NULL; + + return META_SCREEN_CAST_STREAM_SRC (virtual_stream_src); +} + +static void +meta_screen_cast_virtual_stream_set_parameters (MetaScreenCastStream *stream, + GVariantBuilder *parameters_builder) +{ +} + +static gboolean +meta_screen_cast_virtual_stream_transform_position (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y) +{ + MetaScreenCastStreamSrc *src = meta_screen_cast_stream_get_src (stream); + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + ClutterStageView *view; + MetaRectangle view_layout; + + view = meta_screen_cast_virtual_stream_src_get_view (virtual_src); + if (!view) + return FALSE; + + clutter_stage_view_get_layout (view, &view_layout); + *x = stream_x + view_layout.x; + *y = stream_y + view_layout.y; + + return TRUE; +} + +static void +meta_screen_cast_virtual_stream_init (MetaScreenCastVirtualStream *virtual_stream) +{ +} + +static void +meta_screen_cast_virtual_stream_class_init (MetaScreenCastVirtualStreamClass *klass) +{ + MetaScreenCastStreamClass *stream_class = + META_SCREEN_CAST_STREAM_CLASS (klass); + + stream_class->create_src = meta_screen_cast_virtual_stream_create_src; + stream_class->set_parameters = meta_screen_cast_virtual_stream_set_parameters; + stream_class->transform_position = meta_screen_cast_virtual_stream_transform_position; +} diff --git a/src/backends/meta-screen-cast-virtual-stream.h b/src/backends/meta-screen-cast-virtual-stream.h new file mode 100644 index 00000000000..422db5e26bc --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + * + */ + +#ifndef META_SCREEN_CAST_VIRTUAL_STREAM_H +#define META_SCREEN_CAST_VIRTUAL_STREAM_H + +#include "backends/meta-screen-cast-stream.h" + +#define META_TYPE_SCREEN_CAST_VIRTUAL_STREAM (meta_screen_cast_virtual_stream_get_type ()) +G_DECLARE_FINAL_TYPE (MetaScreenCastVirtualStream, + meta_screen_cast_virtual_stream, + META, SCREEN_CAST_VIRTUAL_STREAM, + MetaScreenCastStream) + +MetaScreenCastVirtualStream * meta_screen_cast_virtual_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaScreenCastCursorMode cursor_mode, + MetaScreenCastFlag flags, + GError **error); + +MetaVirtualMonitor * meta_screen_cast_virtual_stream_get_virtual_monitor (MetaScreenCastVirtualStream *virtual_stream); + +#endif /* META_SCREEN_CAST_VIRTUAL_STREAM_H */ diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h index e2ea5a5e460..be297e28da5 100644 --- a/src/backends/meta-screen-cast.h +++ b/src/backends/meta-screen-cast.h @@ -41,6 +41,7 @@ typedef enum _MetaScreenCastFlag { META_SCREEN_CAST_FLAG_NONE = 0, META_SCREEN_CAST_FLAG_IS_RECORDING = 1 << 0, + META_SCREEN_CAST_FLAG_IS_PLATFORM = 1 << 1, } MetaScreenCastFlag; #define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ()) diff --git a/src/meson.build b/src/meson.build index fe3d1ccaf0b..459a563152a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -480,6 +480,10 @@ if have_remote_desktop 'backends/meta-screen-cast-monitor-stream.h', 'backends/meta-screen-cast-monitor-stream-src.c', 'backends/meta-screen-cast-monitor-stream-src.h', + 'backends/meta-screen-cast-virtual-stream-src.c', + 'backends/meta-screen-cast-virtual-stream-src.h', + 'backends/meta-screen-cast-virtual-stream.c', + 'backends/meta-screen-cast-virtual-stream.h', 'backends/meta-screen-cast-window-stream-src.c', 'backends/meta-screen-cast-window-stream-src.h', 'backends/meta-screen-cast-window-stream.c', diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml index 07ab402eb45..d9f1f4435d9 100644 --- a/src/org.gnome.Mutter.ScreenCast.xml +++ b/src/org.gnome.Mutter.ScreenCast.xml @@ -153,6 +153,35 @@ + + + + + +