diff --git a/SOURCES/0001-Add-support-for-quad-buffer-stereo.patch b/SOURCES/0001-Add-support-for-quad-buffer-stereo.patch index 397dc41..38a1213 100644 --- a/SOURCES/0001-Add-support-for-quad-buffer-stereo.patch +++ b/SOURCES/0001-Add-support-for-quad-buffer-stereo.patch @@ -1,4 +1,4 @@ -From d0ad5ea18bb02112837bcdf7270d58d8ad235a4d Mon Sep 17 00:00:00 2001 +From 8d7356fd7439f94f163438d55f2b2d3d918de96d Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Thu, 8 May 2014 18:44:15 -0400 Subject: [PATCH] Add support for quad-buffer stereo @@ -265,10 +265,10 @@ index a86a2bff0..d0efdd4dc 100644 gboolean is_y_inverted); void meta_shaped_texture_set_snippet (MetaShapedTexture *stex, diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c -index ea8daa03d..9a00ccd6d 100644 +index d64e214e5..e77a32109 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c -@@ -102,8 +102,10 @@ struct _MetaShapedTexture +@@ -88,8 +88,10 @@ struct _MetaShapedTexture ClutterActor parent; MetaTextureTower *paint_tower; @@ -279,15 +279,15 @@ index ea8daa03d..9a00ccd6d 100644 CoglTexture *mask_texture; CoglSnippet *snippet; -@@ -192,6 +194,7 @@ meta_shaped_texture_init (MetaShapedTexture *stex) - clutter_backend_get_cogl_context (clutter_backend); - +@@ -160,6 +162,7 @@ static void + meta_shaped_texture_init (MetaShapedTexture *stex) + { stex->paint_tower = meta_texture_tower_new (); + stex->paint_tower_right = NULL; /* demand create */ stex->texture = NULL; stex->mask_texture = NULL; -@@ -335,6 +338,9 @@ meta_shaped_texture_dispose (GObject *object) +@@ -297,6 +300,9 @@ meta_shaped_texture_dispose (GObject *object) meta_texture_tower_free (stex->paint_tower); stex->paint_tower = NULL; @@ -297,7 +297,7 @@ index ea8daa03d..9a00ccd6d 100644 g_clear_pointer (&stex->texture, cogl_object_unref); g_clear_pointer (&stex->opaque_region, cairo_region_destroy); -@@ -611,8 +617,9 @@ paint_clipped_rectangle (MetaShapedTexture *stex, +@@ -507,8 +513,9 @@ paint_clipped_rectangle (MetaShapedTexture *stex, } static void @@ -309,21 +309,19 @@ index ea8daa03d..9a00ccd6d 100644 { int width, height; -@@ -620,10 +627,13 @@ set_cogl_texture (MetaShapedTexture *stex, +@@ -516,8 +523,11 @@ set_cogl_texture (MetaShapedTexture *stex, if (stex->texture) cogl_object_unref (stex->texture); + if (stex->texture_right) + cogl_object_unref (stex->texture_right); - g_clear_pointer (&stex->saved_base_surface, cairo_surface_destroy); - stex->texture = cogl_tex; + stex->texture_right = cogl_tex_right; if (cogl_tex != NULL) { -@@ -637,6 +647,9 @@ set_cogl_texture (MetaShapedTexture *stex, +@@ -531,6 +541,9 @@ set_cogl_texture (MetaShapedTexture *stex, height = 0; } @@ -333,7 +331,7 @@ index ea8daa03d..9a00ccd6d 100644 if (stex->tex_width != width || stex->tex_height != height) { -@@ -650,8 +663,23 @@ set_cogl_texture (MetaShapedTexture *stex, +@@ -544,8 +557,23 @@ set_cogl_texture (MetaShapedTexture *stex, * previous buffer. We only queue a redraw in response to surface * damage. */ @@ -358,7 +356,7 @@ index ea8daa03d..9a00ccd6d 100644 } static gboolean -@@ -927,7 +955,9 @@ meta_shaped_texture_paint (ClutterActor *actor) +@@ -779,7 +807,9 @@ meta_shaped_texture_paint (ClutterActor *actor) { MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor); CoglTexture *paint_tex; @@ -368,7 +366,7 @@ index ea8daa03d..9a00ccd6d 100644 if (!stex->texture) return; -@@ -989,7 +1019,32 @@ meta_shaped_texture_paint (ClutterActor *actor) +@@ -841,7 +871,32 @@ meta_shaped_texture_paint (ClutterActor *actor) return; fb = cogl_get_draw_framebuffer (); @@ -402,7 +400,7 @@ index ea8daa03d..9a00ccd6d 100644 } static void -@@ -1063,6 +1118,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, +@@ -915,6 +970,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, stex->create_mipmaps = create_mipmaps; base_texture = create_mipmaps ? stex->texture : NULL; meta_texture_tower_set_base_texture (stex->paint_tower, base_texture); @@ -415,7 +413,7 @@ index ea8daa03d..9a00ccd6d 100644 } } -@@ -1256,6 +1317,12 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, +@@ -1046,6 +1107,12 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, clip.y, clip.width, clip.height); @@ -428,7 +426,7 @@ index ea8daa03d..9a00ccd6d 100644 stex->prev_invalidation = stex->last_invalidation; stex->last_invalidation = g_get_monotonic_time (); -@@ -1302,17 +1369,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, +@@ -1092,17 +1159,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } /** @@ -903,5 +901,5 @@ index da0acfcbb..ddad1a45c 100644 meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted); g_clear_pointer (&snippet, cogl_object_unref); -- -2.23.0 +2.25.1 diff --git a/SOURCES/0001-Create-explicit-WacomDevices-for-tablet-touchpad-dev.patch b/SOURCES/0001-Create-explicit-WacomDevices-for-tablet-touchpad-dev.patch new file mode 100644 index 0000000..732b754 --- /dev/null +++ b/SOURCES/0001-Create-explicit-WacomDevices-for-tablet-touchpad-dev.patch @@ -0,0 +1,55 @@ +From 38d88d4e4286c3ada041561426873e44fdba3c40 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Fri, 17 Jan 2020 14:45:00 +0100 +Subject: [PATCH] Create explicit WacomDevices for tablet "touchpad" devices + +--- + src/backends/meta-input-settings.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c +index 28dc387ef9..820a3b201e 100644 +--- a/src/backends/meta-input-settings.c ++++ b/src/backends/meta-input-settings.c +@@ -521,27 +521,34 @@ static gboolean + device_is_tablet_touchpad (MetaInputSettings *input_settings, + ClutterInputDevice *device) + { ++ gboolean is_tablet = FALSE; + #ifdef HAVE_LIBWACOM ++ MetaInputSettingsPrivate *priv; + WacomIntegrationFlags flags = 0; + WacomDevice *wacom_device; + ++ priv = meta_input_settings_get_instance_private (input_settings); ++ + if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE) + return FALSE; + + wacom_device = +- meta_input_settings_get_tablet_wacom_device (input_settings, +- device); ++ libwacom_new_from_path (priv->wacom_db, ++ clutter_input_device_get_device_node (device), ++ WFALLBACK_NONE, NULL); + if (wacom_device) + { + flags = libwacom_get_integration_flags (wacom_device); + + if ((flags & (WACOM_DEVICE_INTEGRATED_SYSTEM | + WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0) +- return TRUE; ++ is_tablet = TRUE; ++ ++ libwacom_destroy (wacom_device); + } + #endif + +- return FALSE; ++ return is_tablet; + } + + static void +-- +2.25.0.rc2 + diff --git a/SOURCES/0001-Revert-MetaMonitorManager-ignore-hotplug_mode_update.patch b/SOURCES/0001-Revert-MetaMonitorManager-ignore-hotplug_mode_update.patch new file mode 100644 index 0000000..f61ecf6 --- /dev/null +++ b/SOURCES/0001-Revert-MetaMonitorManager-ignore-hotplug_mode_update.patch @@ -0,0 +1,28 @@ +From d9d355bfd8ecfb7dcf65a3810ec30e12f12673ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 24 Feb 2020 16:09:59 +0100 +Subject: [PATCH] Revert "MetaMonitorManager: ignore hotplug_mode_update at + startup" + +This reverts commit 183f4b0c13f3dc9565bf5f693f2e5d61ca0199c9. +--- + src/backends/meta-monitor-manager.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c +index 076dca8cb..0adf2100d 100644 +--- a/src/backends/meta-monitor-manager.c ++++ b/src/backends/meta-monitor-manager.c +@@ -527,8 +527,7 @@ meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager) + static gboolean + should_use_stored_config (MetaMonitorManager *manager) + { +- return (manager->in_init || +- !meta_monitor_manager_has_hotplug_mode_update (manager)); ++ return !meta_monitor_manager_has_hotplug_mode_update (manager); + } + + static gboolean +-- +2.24.1 + diff --git a/SOURCES/0001-Skip-wacom-touchpads-when-updating-setting.patch b/SOURCES/0001-Skip-wacom-touchpads-when-updating-setting.patch new file mode 100644 index 0000000..ba10e5e --- /dev/null +++ b/SOURCES/0001-Skip-wacom-touchpads-when-updating-setting.patch @@ -0,0 +1,94 @@ +From dafc9cb414fd47112b972d34c205e73797a3c1c1 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Fri, 21 Feb 2020 16:45:35 +0100 +Subject: [PATCH] Skip wacom touchpads when updating setting + +--- + src/backends/meta-input-settings.c | 46 +++++++++++++++++++++++------- + 1 file changed, 36 insertions(+), 10 deletions(-) + +diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c +index cdff7b346..7d866594a 100644 +--- a/src/backends/meta-input-settings.c ++++ b/src/backends/meta-input-settings.c +@@ -569,20 +569,33 @@ update_touchpad_tap_enabled (MetaInputSettings *input_settings, + + priv = meta_input_settings_get_instance_private (input_settings); + input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings); +- enabled = device_is_tablet_touchpad (input_settings, device) || +- g_settings_get_boolean (priv->touchpad_settings, "tap-to-click"); + + if (device) + { ++ enabled = device_is_tablet_touchpad (input_settings, device) || ++ g_settings_get_boolean (priv->touchpad_settings, "tap-to-click"); + settings_device_set_bool_setting (input_settings, device, + input_settings_class->set_tap_enabled, + enabled); + } + else + { +- settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, +- input_settings_class->set_tap_enabled, +- enabled); ++ const GSList *devices, *l; ++ ++ devices = clutter_device_manager_peek_devices (priv->device_manager); ++ for (l = devices; l; l = l->next) ++ { ++ device = l->data; ++ ++ if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE) ++ continue; ++ ++ enabled = device_is_tablet_touchpad (input_settings, device) || ++ g_settings_get_boolean (priv->touchpad_settings, "tap-to-click"); ++ settings_device_set_bool_setting (input_settings, device, ++ input_settings_class->set_tap_enabled, ++ enabled); ++ } + } + } + +@@ -600,20 +613,33 @@ update_touchpad_tap_and_drag_enabled (MetaInputSettings *input_settings, + + priv = meta_input_settings_get_instance_private (input_settings); + input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings); +- enabled = device_is_tablet_touchpad (input_settings, device) || +- g_settings_get_boolean (priv->touchpad_settings, "tap-and-drag"); + + if (device) + { ++ enabled = device_is_tablet_touchpad (input_settings, device) || ++ g_settings_get_boolean (priv->touchpad_settings, "tap-and-drag"); + settings_device_set_bool_setting (input_settings, device, + input_settings_class->set_tap_and_drag_enabled, + enabled); + } + else + { +- settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, +- input_settings_class->set_tap_and_drag_enabled, +- enabled); ++ const GSList *devices, *l; ++ ++ devices = clutter_device_manager_peek_devices (priv->device_manager); ++ for (l = devices; l; l = l->next) ++ { ++ device = l->data; ++ ++ if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE) ++ continue; ++ ++ enabled = device_is_tablet_touchpad (input_settings, device) || ++ g_settings_get_boolean (priv->touchpad_settings, "tap-and-drag"); ++ settings_device_set_bool_setting (input_settings, device, ++ input_settings_class->set_tap_and_drag_enabled, ++ enabled); ++ } + } + } + +-- +2.24.1 + diff --git a/SOURCES/0001-backend-Add-getter-for-MetaScreenCast.patch b/SOURCES/0001-backend-Add-getter-for-MetaScreenCast.patch new file mode 100644 index 0000000..d50b11b --- /dev/null +++ b/SOURCES/0001-backend-Add-getter-for-MetaScreenCast.patch @@ -0,0 +1,49 @@ +From 967d8236d81c8689f2fe60621ec7e66d88b43dea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 17 Jun 2020 17:46:25 +0200 +Subject: [PATCH 1/4] backend: Add getter for MetaScreenCast + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1318 +--- + src/backends/meta-backend-private.h | 2 ++ + src/backends/meta-backend.c | 11 +++++++++++ + 2 files changed, 13 insertions(+) + +diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h +index 81ec81e5f1..77f4da77c4 100644 +--- a/src/backends/meta-backend-private.h ++++ b/src/backends/meta-backend-private.h +@@ -138,6 +138,8 @@ MetaEgl * meta_backend_get_egl (MetaBackend *backend); + + #ifdef HAVE_REMOTE_DESKTOP + MetaRemoteDesktop * meta_backend_get_remote_desktop (MetaBackend *backend); ++ ++MetaScreenCast * meta_backend_get_screen_cast (MetaBackend *backend); + #endif + + gboolean meta_backend_grab_device (MetaBackend *backend, +diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c +index 750a9248a8..b498b7aa44 100644 +--- a/src/backends/meta-backend.c ++++ b/src/backends/meta-backend.c +@@ -965,6 +965,17 @@ meta_backend_get_remote_desktop (MetaBackend *backend) + + return priv->remote_desktop; + } ++ ++/** ++ * meta_backend_get_screen_cast: (skip) ++ */ ++MetaScreenCast * ++meta_backend_get_screen_cast (MetaBackend *backend) ++{ ++ MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); ++ ++ return priv->screen_cast; ++} + #endif /* HAVE_REMOTE_DESKTOP */ + + /** +-- +2.26.2 + diff --git a/SOURCES/0001-backends-Check-both-input-settings-and-mapper-for-ta.patch b/SOURCES/0001-backends-Check-both-input-settings-and-mapper-for-ta.patch index 1aa7725..9880a83 100644 --- a/SOURCES/0001-backends-Check-both-input-settings-and-mapper-for-ta.patch +++ b/SOURCES/0001-backends-Check-both-input-settings-and-mapper-for-ta.patch @@ -1,7 +1,61 @@ -From f14730e7307679cb979aa521b20f246dfc5082da Mon Sep 17 00:00:00 2001 +From 20fcc3e045287c1ca591f3e795b19e120479a89a Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Wed, 12 Feb 2020 20:26:56 +0100 +Subject: [PATCH 1/2] backends/x11: Implement is_grouped for X11 + +If the devices have a wacom description, compare those. Otherwise, +look up the devices' VID:PID, if they match they should also be +grouped. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/971 +--- + .../clutter/x11/clutter-input-device-xi2.c | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c +index ae2fa27..9eca34d 100644 +--- a/clutter/clutter/x11/clutter-input-device-xi2.c ++++ b/clutter/clutter/x11/clutter-input-device-xi2.c +@@ -98,6 +98,31 @@ static gboolean + clutter_input_device_xi2_is_grouped (ClutterInputDevice *device, + ClutterInputDevice *other_device) + { ++#ifdef HAVE_LIBWACOM ++ ClutterInputDeviceXI2 *device_x11 = CLUTTER_INPUT_DEVICE_XI2 (device); ++ ClutterInputDeviceXI2 *other_device_x11 = CLUTTER_INPUT_DEVICE_XI2 (other_device); ++ ++ if (device_x11->wacom_device && ++ other_device_x11->wacom_device && ++ libwacom_compare (device_x11->wacom_device, ++ other_device_x11->wacom_device, ++ WCOMPARE_NORMAL) == 0) ++ return TRUE; ++#endif ++ ++ /* Devices with the same VID:PID get grouped together */ ++ if (clutter_input_device_get_vendor_id (device) && ++ clutter_input_device_get_product_id (device) && ++ clutter_input_device_get_vendor_id (other_device) && ++ clutter_input_device_get_product_id (other_device)) ++ { ++ if (strcmp (clutter_input_device_get_vendor_id (device), ++ clutter_input_device_get_vendor_id (other_device)) == 0 && ++ strcmp (clutter_input_device_get_product_id (device), ++ clutter_input_device_get_product_id (other_device)) == 0) ++ return TRUE; ++ } ++ + return FALSE; + } + +-- +2.24.1 + + +From 5914ab9ac79ce42da054036c4a8f118a3a868cc0 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 13 Dec 2019 15:26:05 +0100 -Subject: [PATCH] backends: Check both input settings and mapper for tablet +Subject: [PATCH 2/2] backends: Check both input settings and mapper for tablet monitors The upper layers (OSDs basically) want to know the monitor that a @@ -17,13 +71,13 @@ again in the right place. https://gitlab.gnome.org/GNOME/mutter/merge_requests/971 --- - src/backends/meta-input-mapper-private.h | 3 +++ - src/backends/meta-input-mapper.c | 26 ++++++++++++++++++++++++ - src/backends/meta-input-settings.c | 11 ++++++++-- - 3 files changed, 38 insertions(+), 2 deletions(-) + src/backends/meta-input-mapper-private.h | 3 ++ + src/backends/meta-input-mapper.c | 26 ++++++++++++ + src/backends/meta-input-settings.c | 54 +++++++++++++++++++++++- + 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/backends/meta-input-mapper-private.h b/src/backends/meta-input-mapper-private.h -index 34314577f..cdfdccde9 100644 +index 3431457..cdfdccd 100644 --- a/src/backends/meta-input-mapper-private.h +++ b/src/backends/meta-input-mapper-private.h @@ -42,5 +42,8 @@ ClutterInputDevice * @@ -36,10 +90,10 @@ index 34314577f..cdfdccde9 100644 #endif /* META_INPUT_MAPPER_H */ diff --git a/src/backends/meta-input-mapper.c b/src/backends/meta-input-mapper.c -index acc9b1618..571b3983c 100644 +index fc4f3bd..fe02ab8 100644 --- a/src/backends/meta-input-mapper.c +++ b/src/backends/meta-input-mapper.c -@@ -684,3 +684,29 @@ meta_input_mapper_get_logical_monitor_device (MetaInputMapper *mapper, +@@ -675,3 +675,29 @@ meta_input_mapper_get_logical_monitor_device (MetaInputMapper *mapper, return NULL; } @@ -70,10 +124,65 @@ index acc9b1618..571b3983c 100644 + return NULL; +} diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c -index b7aec8d6d..a923aa971 100644 +index b84595e..ab80bee 100644 --- a/src/backends/meta-input-settings.c +++ b/src/backends/meta-input-settings.c -@@ -1922,8 +1922,15 @@ meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings, +@@ -1937,6 +1937,42 @@ meta_input_settings_get_tablet_settings (MetaInputSettings *settings, + return info ? g_object_ref (info->settings) : NULL; + } + ++static ClutterInputDevice * ++find_grouped_pen (MetaInputSettings *settings, ++ ClutterInputDevice *device) ++{ ++ MetaInputSettingsPrivate *priv; ++ GSList *l, *devices; ++ ClutterInputDeviceType device_type; ++ ClutterInputDevice *pen = NULL; ++ ++ device_type = clutter_input_device_get_device_type (device); ++ ++ if (device_type == CLUTTER_TABLET_DEVICE || ++ device_type == CLUTTER_PEN_DEVICE) ++ return device; ++ ++ priv = meta_input_settings_get_instance_private (settings); ++ devices = clutter_device_manager_peek_devices (priv->device_manager); ++ ++ for (l = devices; l; l = l->next) ++ { ++ ClutterInputDevice *device = l->data; ++ ++ device_type = clutter_input_device_get_device_type (l->data); ++ ++ if ((device_type == CLUTTER_TABLET_DEVICE || ++ device_type == CLUTTER_PEN_DEVICE) && ++ clutter_input_device_is_grouped (device, l->data)) ++ { ++ pen = l->data; ++ break; ++ } ++ } ++ ++ return pen; ++} ++ + MetaLogicalMonitor * + meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings, + ClutterInputDevice *device) +@@ -1948,13 +1984,27 @@ meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings, + g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); + ++ if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) ++ { ++ device = find_grouped_pen (settings, device); ++ if (!device) ++ return NULL; ++ } ++ + priv = meta_input_settings_get_instance_private (settings); + info = g_hash_table_lookup (priv->mappable_devices, device); if (!info) return NULL; @@ -92,5 +201,5 @@ index b7aec8d6d..a923aa971 100644 } -- -2.23.0 +2.24.1 diff --git a/SOURCES/0001-backends-x11-Observe-multiple-pad-mode-switch-button.patch b/SOURCES/0001-backends-x11-Observe-multiple-pad-mode-switch-button.patch index 3735f0d..ac6986f 100644 --- a/SOURCES/0001-backends-x11-Observe-multiple-pad-mode-switch-button.patch +++ b/SOURCES/0001-backends-x11-Observe-multiple-pad-mode-switch-button.patch @@ -42,7 +42,7 @@ index 1254aca3a..c33adffc2 100644 + { + button_group = clutter_input_device_xi2_get_button_group (device, i); + if (button_group == group) -+ switch_buttons = g_list_prepend (switch_buttons, GINT_TO_POINTER (button)); ++ switch_buttons = g_list_prepend (switch_buttons, GINT_TO_POINTER (i)); + } + + switch_buttons = g_list_reverse (switch_buttons); @@ -53,7 +53,7 @@ index 1254aca3a..c33adffc2 100644 + /* If there's multiple switch buttons, we don't toggle but assign a mode + * to each of those buttons. + */ -+ next_mode = g_list_position (switch_buttons, GINT_TO_POINTER (button)); ++ next_mode = g_list_index (switch_buttons, GINT_TO_POINTER (button)); + } + else if (switch_buttons) + { diff --git a/SOURCES/0001-background-Reload-when-GPU-memory-is-invalidated.patch b/SOURCES/0001-background-Reload-when-GPU-memory-is-invalidated.patch new file mode 100644 index 0000000..fae4a7e --- /dev/null +++ b/SOURCES/0001-background-Reload-when-GPU-memory-is-invalidated.patch @@ -0,0 +1,118 @@ +From 5a486f5b6bf5f838db5dc2bfc5819a0cba5d2d19 Mon Sep 17 00:00:00 2001 +From: Daniel van Vugt +Date: Thu, 23 May 2019 18:15:28 +0800 +Subject: [PATCH] background: Reload when GPU memory is invalidated + +Fixes corrupt background wallpaper when resuming from suspend on the +Nvidia driver. + +https://gitlab.gnome.org/GNOME/gnome-shell/issues/1084 + +(cherry picked from commit a5265365dd268e15a461a58000a10b122d0bccba) + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/777 +--- + src/compositor/meta-background.c | 46 +++++++++++++++++++++++++------- + 1 file changed, 36 insertions(+), 10 deletions(-) + +diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c +index c033395fe..387ce5dd3 100644 +--- a/src/compositor/meta-background.c ++++ b/src/compositor/meta-background.c +@@ -252,12 +252,11 @@ static void + set_file (MetaBackground *self, + GFile **filep, + MetaBackgroundImage **imagep, +- GFile *file) ++ GFile *file, ++ gboolean force_reload) + { +- if (!file_equal0 (*filep, file)) ++ if (force_reload || !file_equal0 (*filep, file)) + { +- g_clear_object (filep); +- + if (*imagep) + { + g_signal_handlers_disconnect_by_func (*imagep, +@@ -267,11 +266,12 @@ set_file (MetaBackground *self, + *imagep = NULL; + } + ++ g_set_object (filep, file); ++ + if (file) + { + MetaBackgroundImageCache *cache = meta_background_image_cache_get_default (); + +- *filep = g_object_ref (file); + *imagep = meta_background_image_cache_load (cache, file); + g_signal_connect (*imagep, "loaded", + G_CALLBACK (on_background_loaded), self); +@@ -279,6 +279,32 @@ set_file (MetaBackground *self, + } + } + ++static void ++on_gl_video_memory_purged (MetaBackground *self) ++{ ++ MetaBackgroundImageCache *cache = meta_background_image_cache_get_default (); ++ ++ /* The GPU memory that just got invalidated is the texture inside ++ * self->background_image1,2 and/or its mipmaps. However, to save memory the ++ * original pixbuf isn't kept in RAM so we can't do a simple re-upload. The ++ * only copy of the image was the one in texture memory that got invalidated. ++ * So we need to do a full reload from disk. ++ */ ++ if (self->file1) ++ { ++ meta_background_image_cache_purge (cache, self->file1); ++ set_file (self, &self->file1, &self->background_image1, self->file1, TRUE); ++ } ++ ++ if (self->file2) ++ { ++ meta_background_image_cache_purge (cache, self->file2); ++ set_file (self, &self->file2, &self->background_image2, self->file2, TRUE); ++ } ++ ++ mark_changed (self); ++} ++ + static void + meta_background_dispose (GObject *object) + { +@@ -287,8 +313,8 @@ meta_background_dispose (GObject *object) + free_color_texture (self); + free_wallpaper_texture (self); + +- set_file (self, &self->file1, &self->background_image1, NULL); +- set_file (self, &self->file2, &self->background_image2, NULL); ++ set_file (self, &self->file1, &self->background_image1, NULL, FALSE); ++ set_file (self, &self->file2, &self->background_image2, NULL, FALSE); + + set_display (self, NULL); + +@@ -312,7 +338,7 @@ meta_background_constructed (GObject *object) + G_OBJECT_CLASS (meta_background_parent_class)->constructed (object); + + g_signal_connect_object (self->display, "gl-video-memory-purged", +- G_CALLBACK (mark_changed), object, G_CONNECT_SWAPPED); ++ G_CALLBACK (on_gl_video_memory_purged), object, G_CONNECT_SWAPPED); + + g_signal_connect_object (monitor_manager, "monitors-changed", + G_CALLBACK (on_monitors_changed), self, +@@ -937,8 +963,8 @@ meta_background_set_blend (MetaBackground *self, + g_return_if_fail (META_IS_BACKGROUND (self)); + g_return_if_fail (blend_factor >= 0.0 && blend_factor <= 1.0); + +- set_file (self, &self->file1, &self->background_image1, file1); +- set_file (self, &self->file2, &self->background_image2, file2); ++ set_file (self, &self->file1, &self->background_image1, file1, FALSE); ++ set_file (self, &self->file2, &self->background_image2, file2, FALSE); + + self->blend_factor = blend_factor; + self->style = style; +-- +2.26.2 + diff --git a/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch b/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch new file mode 100644 index 0000000..028c8bd --- /dev/null +++ b/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch @@ -0,0 +1,53 @@ +From 4c1c3541efa37acf3a03822289a8ab8705cbbc4e Mon Sep 17 00:00:00 2001 +From: Christian Hergert +Date: Sun, 23 Feb 2020 17:27:08 -0800 +Subject: [PATCH 1/3] clutter: avoid redundant _clutter_paint_node_init_types() + +This only needs to be initialized once but is in the hot path of creating +new paint nodes (for which we create many). Instead, do this as part of +the clutter_init() workflow to keep it out of the hot path. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1087 +--- + clutter/clutter/clutter-main.c | 4 ++++ + clutter/clutter/clutter-paint-node.c | 2 -- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c +index 71ec0d80c..645c8bceb 100644 +--- a/clutter/clutter/clutter-main.c ++++ b/clutter/clutter/clutter-main.c +@@ -61,6 +61,7 @@ + #include "clutter-main.h" + #include "clutter-master-clock.h" + #include "clutter-mutter.h" ++#include "clutter-paint-node-private.h" + #include "clutter-private.h" + #include "clutter-settings-private.h" + #include "clutter-stage-manager.h" +@@ -1366,6 +1367,9 @@ clutter_init_real (GError **error) + if (clutter_enable_accessibility) + cally_accessibility_init (); + ++ /* Initialize types required for paint nodes */ ++ _clutter_paint_node_init_types (); ++ + return CLUTTER_INIT_SUCCESS; + } + +diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c +index e731ca60a..73765a4e9 100644 +--- a/clutter/clutter/clutter-paint-node.c ++++ b/clutter/clutter/clutter-paint-node.c +@@ -1177,8 +1177,6 @@ _clutter_paint_node_create (GType gtype) + { + g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL); + +- _clutter_paint_node_init_types (); +- + return (gpointer) g_type_create_instance (gtype); + } + +-- +2.26.0 + diff --git a/SOURCES/0001-cogl-add-new-UNSTABLE_TEXTURES-feature.patch b/SOURCES/0001-cogl-add-new-UNSTABLE_TEXTURES-feature.patch deleted file mode 100644 index 673608d..0000000 --- a/SOURCES/0001-cogl-add-new-UNSTABLE_TEXTURES-feature.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 78bb1fff1155462638b0d6037ccddf1328482842 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Jan 2019 11:01:38 -0500 -Subject: [PATCH 1/9] cogl: add new UNSTABLE_TEXTURES feature - -The proprietary nvidia driver garbles texture memory on suspend. - -Before we can address that, we need to be able to detect it. - -This commit adds a new UNSTABLE_TEXTURES feature that gets set if -the proprietary nvidia driver is in use. ---- - cogl/cogl/cogl-context.h | 1 + - cogl/cogl/cogl-types.h | 5 ++++- - cogl/cogl/winsys/cogl-winsys-egl.c | 11 +++++++++++ - cogl/cogl/winsys/cogl-winsys-glx.c | 13 +++++++++++-- - 4 files changed, 27 insertions(+), 3 deletions(-) - -diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h -index d4104625e..a20c54549 100644 ---- a/cogl/cogl/cogl-context.h -+++ b/cogl/cogl/cogl-context.h -@@ -261,6 +261,7 @@ typedef enum _CoglFeatureID - COGL_FEATURE_ID_TEXTURE_RG, - COGL_FEATURE_ID_BUFFER_AGE, - COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, -+ COGL_FEATURE_ID_UNSTABLE_TEXTURES, - - /*< private >*/ - _COGL_N_FEATURE_IDS /*< skip >*/ -diff --git a/cogl/cogl/cogl-types.h b/cogl/cogl/cogl-types.h -index 690daa16a..5b980a43c 100644 ---- a/cogl/cogl/cogl-types.h -+++ b/cogl/cogl/cogl-types.h -@@ -354,6 +354,8 @@ typedef enum /*< prefix=COGL_PIXEL_FORMAT >*/ - * supported with CoglBufferAccess including write support. - * @COGL_FEATURE_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering the - * depth buffer to a texture. -+ * @COGL_FEATURE_UNSTABLE_TEXTURES: Whether textures require redrawing on -+ * resume or not. - * - * Flags for the supported features. - * -@@ -383,7 +385,8 @@ typedef enum - COGL_FEATURE_MAP_BUFFER_FOR_READ = (1 << 21), - COGL_FEATURE_MAP_BUFFER_FOR_WRITE = (1 << 22), - COGL_FEATURE_ONSCREEN_MULTIPLE = (1 << 23), -- COGL_FEATURE_DEPTH_TEXTURE = (1 << 24) -+ COGL_FEATURE_DEPTH_TEXTURE = (1 << 24), -+ COGL_FEATURE_UNSTABLE_TEXTURES = (1 << 25) - } CoglFeatureFlags; - - /** -diff --git a/cogl/cogl/winsys/cogl-winsys-egl.c b/cogl/cogl/winsys/cogl-winsys-egl.c -index 903c6492d..dd450d4f3 100644 ---- a/cogl/cogl/winsys/cogl-winsys-egl.c -+++ b/cogl/cogl/winsys/cogl-winsys-egl.c -@@ -499,6 +499,7 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error) - CoglRenderer *renderer = context->display->renderer; - CoglDisplayEGL *egl_display = context->display->winsys; - CoglRendererEGL *egl_renderer = renderer->winsys; -+ CoglGpuInfo *info; - - context->winsys = g_new0 (CoglContextEGL, 1); - -@@ -511,6 +512,16 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error) - if (!_cogl_context_update_features (context, error)) - return FALSE; - -+ info = &context->gpu; -+ -+ if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) -+ { -+ context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES; -+ COGL_FLAGS_SET (context->features, -+ COGL_FEATURE_ID_UNSTABLE_TEXTURES, -+ TRUE); -+ } -+ - if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION) - { - COGL_FLAGS_SET (context->winsys_features, -diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c -index 235cfe81f..7e87dc15f 100644 ---- a/cogl/cogl/winsys/cogl-winsys-glx.c -+++ b/cogl/cogl/winsys/cogl-winsys-glx.c -@@ -830,12 +830,15 @@ update_winsys_features (CoglContext *context, CoglError **error) - { - CoglGLXDisplay *glx_display = context->display->winsys; - CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; -+ CoglGpuInfo *info; - - _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE); - - if (!_cogl_context_update_features (context, error)) - return FALSE; - -+ info = &context->gpu; -+ - memcpy (context->winsys_features, - glx_renderer->base_winsys_features, - sizeof (context->winsys_features)); -@@ -848,7 +851,6 @@ update_winsys_features (CoglContext *context, CoglError **error) - - if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer) - { -- CoglGpuInfo *info = &context->gpu; - CoglGpuInfoArchitecture arch = info->architecture; - - COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); -@@ -897,7 +899,6 @@ update_winsys_features (CoglContext *context, CoglError **error) - } - else - { -- CoglGpuInfo *info = &context->gpu; - if (glx_display->have_vblank_counter && - context->display->renderer->xlib_enable_threaded_swap_wait && - info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) -@@ -919,6 +920,14 @@ update_winsys_features (CoglContext *context, CoglError **error) - } - } - -+ if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) -+ { -+ context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES; -+ COGL_FLAGS_SET (context->features, -+ COGL_FEATURE_ID_UNSTABLE_TEXTURES, -+ TRUE); -+ } -+ - /* We'll manually handle queueing dirty events in response to - * Expose events from X */ - COGL_FLAGS_SET (context->private_features, --- -2.21.0 - diff --git a/SOURCES/0001-crtc-xrandr-Respect-configured-RANDR-panning.patch b/SOURCES/0001-crtc-xrandr-Respect-configured-RANDR-panning.patch new file mode 100644 index 0000000..29e6b88 --- /dev/null +++ b/SOURCES/0001-crtc-xrandr-Respect-configured-RANDR-panning.patch @@ -0,0 +1,73 @@ +From bac090f571e6f413ba2a362ed2d70146b7701d16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 24 Feb 2020 17:37:34 +0100 +Subject: [PATCH] crtc-xrandr: Respect configured RANDR panning + +A user may have configured an output to be panning, e.g. using xrandr +--output --mode --panning . Respect this by making +the logical monitor use the panning size, instead of the mode. This +makes e.g. makes the background cover the whole panning size, and panels +etc will cover the whole top of the panned area, instead of just the top +left part covering the monitor if having panned to (0, 0). + +No support is added to configuring panning, i.e. a panned monitor +configuration cannot be stored in monitors.xml. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1085 +--- + src/backends/x11/meta-crtc-xrandr.c | 31 +++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/src/backends/x11/meta-crtc-xrandr.c b/src/backends/x11/meta-crtc-xrandr.c +index d201b8581..dc3f931e3 100644 +--- a/src/backends/x11/meta-crtc-xrandr.c ++++ b/src/backends/x11/meta-crtc-xrandr.c +@@ -177,7 +177,14 @@ meta_create_xrandr_crtc (MetaGpuXrandr *gpu_xrandr, + RRCrtc crtc_id, + XRRScreenResources *resources) + { ++ MetaGpu *gpu = META_GPU (gpu_xrandr); ++ MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu); ++ MetaMonitorManagerXrandr *monitor_manager_xrandr = ++ META_MONITOR_MANAGER_XRANDR (monitor_manager); ++ Display *xdisplay = ++ meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr); + MetaCrtc *crtc; ++ XRRPanning *panning; + unsigned int i; + GList *modes; + +@@ -185,10 +192,26 @@ meta_create_xrandr_crtc (MetaGpuXrandr *gpu_xrandr, + + crtc->gpu = META_GPU (gpu_xrandr); + crtc->crtc_id = crtc_id; +- crtc->rect.x = xrandr_crtc->x; +- crtc->rect.y = xrandr_crtc->y; +- crtc->rect.width = xrandr_crtc->width; +- crtc->rect.height = xrandr_crtc->height; ++ ++ panning = XRRGetPanning (xdisplay, resources, crtc_id); ++ if (panning && panning->width > 0 && panning->height > 0) ++ { ++ crtc->rect = (MetaRectangle) { ++ .x = panning->left, ++ .y = panning->top, ++ .width = panning->width, ++ .height = panning->height, ++ }; ++ } ++ else ++ { ++ crtc->rect = (MetaRectangle) { ++ .x = xrandr_crtc->x, ++ .y = xrandr_crtc->y, ++ .width = xrandr_crtc->width, ++ .height = xrandr_crtc->height, ++ }; ++ } + crtc->is_dirty = FALSE; + crtc->transform = + meta_monitor_transform_from_xrandr (xrandr_crtc->rotation); +-- +2.24.1 + diff --git a/SOURCES/0001-renderer-Add-API-to-check-whether-renderer-is-hardwa.patch b/SOURCES/0001-renderer-Add-API-to-check-whether-renderer-is-hardwa.patch new file mode 100644 index 0000000..2be8b13 --- /dev/null +++ b/SOURCES/0001-renderer-Add-API-to-check-whether-renderer-is-hardwa.patch @@ -0,0 +1,108 @@ +From d107b52939ca0acb1f8dacf1275278edba64eebe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 1 Oct 2019 11:53:57 +0200 +Subject: [PATCH] renderer: Add API to check whether renderer is hardware + accelerated + +Also expose an introspected variant via the MetaBackend. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/838 +--- + src/backends/meta-backend.c | 15 +++++++++++++++ + src/backends/meta-renderer.c | 27 +++++++++++++++++++++++++++ + src/backends/meta-renderer.h | 2 ++ + src/meta/meta-backend.h | 3 +++ + 4 files changed, 47 insertions(+) + +diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c +index 72cfbdaf3..e61181f9a 100644 +--- a/src/backends/meta-backend.c ++++ b/src/backends/meta-backend.c +@@ -985,6 +985,21 @@ meta_backend_get_remote_access_controller (MetaBackend *backend) + #endif + } + ++/** ++ * meta_backend_is_rendering_hardware_accelerated: ++ * @backend: A #MetaBackend ++ * ++ * Returns: %TRUE if the rendering is hardware accelerated, otherwise ++ * %FALSE. ++ */ ++gboolean ++meta_backend_is_rendering_hardware_accelerated (MetaBackend *backend) ++{ ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ ++ return meta_renderer_is_hardware_accelerated (renderer); ++} ++ + /** + * meta_backend_grab_device: (skip) + */ +diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c +index 87ba9f9f0..470220fc8 100644 +--- a/src/backends/meta-renderer.c ++++ b/src/backends/meta-renderer.c +@@ -166,6 +166,33 @@ meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer, + return NULL; + } + ++gboolean ++meta_renderer_is_hardware_accelerated (MetaRenderer *renderer) ++{ ++ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); ++ MetaBackend *backend = meta_get_backend (); ++ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_backend); ++ CoglGpuInfo *info = &cogl_context->gpu; ++ ++ switch (info->architecture) ++ { ++ case COGL_GPU_INFO_ARCHITECTURE_UNKNOWN: ++ case COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE: ++ case COGL_GPU_INFO_ARCHITECTURE_SGX: ++ case COGL_GPU_INFO_ARCHITECTURE_MALI: ++ return TRUE; ++ case COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE: ++ case COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE: ++ case COGL_GPU_INFO_ARCHITECTURE_SWRAST: ++ return FALSE; ++ } ++ ++ g_assert_not_reached (); ++ return FALSE; ++} ++ + static void + meta_renderer_finalize (GObject *object) + { +diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h +index 478baee91..97bf36860 100644 +--- a/src/backends/meta-renderer.h ++++ b/src/backends/meta-renderer.h +@@ -59,4 +59,6 @@ GList * meta_renderer_get_views (MetaRenderer *renderer); + MetaRendererView * meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer, + MetaLogicalMonitor *logical_monitor); + ++gboolean meta_renderer_is_hardware_accelerated (MetaRenderer *renderer); ++ + #endif /* META_RENDERER_H */ +diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h +index aaa6aae97..8edc0bf2c 100644 +--- a/src/meta/meta-backend.h ++++ b/src/meta/meta-backend.h +@@ -64,6 +64,9 @@ MetaSettings *meta_backend_get_settings (MetaBackend *backend); + META_EXPORT + MetaRemoteAccessController * meta_backend_get_remote_access_controller (MetaBackend *backend); + ++META_EXPORT ++gboolean meta_backend_is_rendering_hardware_accelerated (MetaBackend *backend); ++ + META_EXPORT + void meta_clutter_init (void); + +-- +2.26.2 + diff --git a/SOURCES/0001-screen-cast-src-Destroy-hash-dmabuf-table-after-stre.patch b/SOURCES/0001-screen-cast-src-Destroy-hash-dmabuf-table-after-stre.patch new file mode 100644 index 0000000..a0f76ff --- /dev/null +++ b/SOURCES/0001-screen-cast-src-Destroy-hash-dmabuf-table-after-stre.patch @@ -0,0 +1,40 @@ +From b32ae04c122f4f76ffad296c15ba00a13800db57 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 2 Jun 2020 16:33:05 +0000 +Subject: [PATCH 1/2] screen-cast-src: Destroy hash dmabuf table after stream + +The stream will clean up the buffers, so let it do that before we +destroy them under its feet. Note that it'll only do this after the +following PipeWire commit: + + commit fbaa4ddedd84afdffca16f090dcc4b0db8ccfc29 + Author: Wim Taymans + Date: Mon Jun 1 15:36:09 2020 +0200 + + stream: allow NULL param and 0 buffers in disconnect + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283 + + +(cherry picked from commit 97175f8fa14171606ecb95d0bf107ef8b2d71b74) +--- + src/backends/meta-screen-cast-stream-src.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 0500bfec5..ff4af440c 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -988,8 +988,8 @@ meta_screen_cast_stream_src_finalize (GObject *object) + if (meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_disable (src); + +- g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy); + g_clear_pointer (&priv->pipewire_stream, pw_stream_destroy); ++ g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy); + g_clear_pointer (&priv->pipewire_core, pw_core_disconnect); + g_clear_pointer (&priv->pipewire_context, pw_context_destroy); + g_source_destroy (&priv->pipewire_source->base); +-- +2.26.2 + diff --git a/SOURCES/0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch b/SOURCES/0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch new file mode 100644 index 0000000..095e0d2 --- /dev/null +++ b/SOURCES/0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch @@ -0,0 +1,101 @@ +From 639b7ba7f2729a95593c0b85d4789f76152e6099 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 18 Jun 2020 21:17:29 +0200 +Subject: [PATCH] stage/x11: Check that message is WM_PROTOCOLS before assuming + so + +When a touch sequence was rejected, we'd update the event timestamps of +incoming touch events to help with implementing grabs. This was done by +sending a ClientMessage with a counter, and comparing the counter to +decide whether we're seing a replayed event or not. + +This had the unforseen consequence that we would potentially end up +destroying all actors including the stage, since, when mutter receives a +ClientMessage event, it would assume that it's a WM_PROTOCOLS event, and +handle it as such. The problem with this approach is that it would +ignore fact that there might be other ClientMessage types sent to it, +for example the touch synchronization one. What could happen is that the +touch count value would match up with the value of the WM_DELETE_WINDOW +atom, clutter would treat this as WM_PROTOCOLS:WM_DELETE_WINDOW, which +it'd translate to clutter_actor_destroy(stage). + +Destroying the stage in such a way is not expected, and caused wierd +crashes in different places depending on what was going on. + +This commit make sure we only treat WM_PROTOCOLS client messages as +WM_PROTOCOLS client messages effectively avoiding the issue. + +This fixes crashes such as: + + #0 meta_window_get_buffer_rect (window=0x0, rect=rect@entry=0x7ffd7fc62e40) at core/window.c:4396 + #1 0x00007f1e2634837f in get_top_visible_window_actor (compositor=0x297d700, compositor=0x297d700) at compositor/compositor.c:1059 + #2 meta_compositor_sync_stack (compositor=0x297d700, stack=, stack@entry=0x26e3140) at compositor/compositor.c:1176 + #3 0x00007f1e263757ac in meta_stack_tracker_sync_stack (tracker=0x297dbc0) at core/stack-tracker.c:871 + #4 0x00007f1e26375899 in stack_tracker_sync_stack_later (data=) at core/stack-tracker.c:881 + #5 0x00007f1e26376914 in run_repaint_laters (laters_list=0x7f1e2663b7d8 ) at core/util.c:809 + #6 run_all_repaint_laters (data=) at core/util.c:826 + #7 0x00007f1e26b18325 in _clutter_run_repaint_functions (flags=flags@entry=CLUTTER_REPAINT_FLAGS_PRE_PAINT) at clutter-main.c:3448 + #8 0x00007f1e26b18fc5 in master_clock_update_stages (master_clock=0x32d6a80, stages=0x4e5a740) at clutter-master-clock-default.c:437 + #9 clutter_clock_dispatch (source=, callback=, user_data=) at clutter-master-clock-default.c:567 + #10 0x00007f1e27e48049 in g_main_dispatch (context=0x225b8d0) at gmain.c:3175 + #11 g_main_context_dispatch (context=context@entry=0x225b8d0) at gmain.c:3828 + #12 0x00007f1e27e483a8 in g_main_context_iterate (context=0x225b8d0, block=block@entry=1, dispatch=dispatch@entry=1, self=) at gmain.c:3901 + #13 0x00007f1e27e4867a in g_main_loop_run (loop=0x24e29f0) at gmain.c:4097 + #14 0x00007f1e2636a3dc in meta_run () at core/main.c:666 + #15 0x000000000040219c in main (argc=1, argv=0x7ffd7fc63238) at ../src/main.c:534 + +and + + #0 0x00007f93943c1f25 in raise () at /usr/lib/libc.so.6 + #1 0x00007f93943ab897 in abort () at /usr/lib/libc.so.6 + #2 0x00007f9393e1e062 in g_assertion_message (domain=, file=, line=, func=0x7f93933e6860 <__func__.116322> "meta_x11_get_stage_window", + #3 0x00007f9393e4ab1d in g_assertion_message_expr () + #4 0x00007f939338ecd7 in meta_x11_get_stage_window (stage=) at ../mutter/src/backends/x11/meta-stage-x11.c:923 + #5 0x00007f939339e599 in meta_backend_x11_cm_translate_device_event (x11=, device_event=0x55bc8bcfd6b0) at ../mutter/src/backends/x11/cm/meta-backend-x11-cm.c:381 + #6 0x00007f939339f2e2 in meta_backend_x11_translate_device_event (device_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:179 + #7 0x00007f939339f2e2 in translate_device_event (device_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:208 + #8 0x00007f939339f2e2 in maybe_spoof_event_as_stage_event (input_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:284 + #9 0x00007f939339f2e2 in handle_input_event (event=0x7fff62d60490, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:309 + #10 0x00007f939339f2e2 in handle_host_xevent (event=0x7fff62d60490, backend=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:413 + #11 0x00007f939339f2e2 in x_event_source_dispatch (source=, callback=, user_data=) at ../mutter/src/backends/x11/meta-backend-x11.c:467 + #12 0x00007f9393e6c39e in g_main_dispatch (context=0x55bc89dd03e0) at ../glib/glib/gmain.c:3179 + #13 0x00007f9393e6c39e in g_main_context_dispatch (context=context@entry=0x55bc89dd03e0) at ../glib/glib/gmain.c:3844 + #14 0x00007f9393e6e1b1 in g_main_context_iterate (context=0x55bc89dd03e0, block=block@entry=1, dispatch=dispatch@entry=1, self=) at ../glib/glib/gmain.c:3917 + #15 0x00007f9393e6f0c3 in g_main_loop_run (loop=0x55bc8a042640) at ../glib/glib/gmain.c:4111 + #16 0x00007f9393369a0c in meta_run () at ../mutter/src/core/main.c:676 + #17 0x000055bc880f2426 in main (argc=, argv=) at ../gnome-shell/src/main.c:552 + +Related: https://gitlab.gnome.org/GNOME/mutter/-/issues/338 +Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/951 + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1317 +--- + clutter/clutter/x11/clutter-stage-x11.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/clutter/clutter/x11/clutter-stage-x11.c b/clutter/clutter/x11/clutter-stage-x11.c +index d043bcf31d..123078fc22 100644 +--- a/clutter/clutter/x11/clutter-stage-x11.c ++++ b/clutter/clutter/x11/clutter-stage-x11.c +@@ -1306,11 +1306,14 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator, + _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), + stage, + (unsigned int) stage_xwindow); +- if (handle_wm_protocols_event (backend_x11, stage_x11, xevent)) ++ if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS) + { +- event->any.type = CLUTTER_DELETE; +- event->any.stage = stage; +- res = CLUTTER_TRANSLATE_QUEUE; ++ if (handle_wm_protocols_event (backend_x11, stage_x11, xevent)) ++ { ++ event->any.type = CLUTTER_DELETE; ++ event->any.stage = stage; ++ res = CLUTTER_TRANSLATE_QUEUE; ++ } + } + break; + +-- +2.26.2 + diff --git a/SOURCES/0001-window-actor-Don-t-show-actor-until-meta_window_acto.patch b/SOURCES/0001-window-actor-Don-t-show-actor-until-meta_window_acto.patch new file mode 100644 index 0000000..df533eb --- /dev/null +++ b/SOURCES/0001-window-actor-Don-t-show-actor-until-meta_window_acto.patch @@ -0,0 +1,35 @@ +From 24ddf60768412fd3f5f7b432449b9ed2ea0d18b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 18 Feb 2020 23:01:28 +0100 +Subject: [PATCH] window-actor: Don't show actor until meta_window_actor_show() + +By default clutter will show an actor as it is added to a parent. This +means that after we create the window actor, when it's added to the +window group, we implicitly show it. What we really want is to not show +it until the window is supposed to be shown, which happens when +meta_window_actor_show() is called, as showing prior to that, could +cause issues. + +Avoid the implicit show by setting the "show-on-set-parent" property on +the window actor to `FALSE` on window actor construction. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1066 +--- + src/compositor/compositor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index a6ae55abb9..ce2c1b8a3b 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -810,6 +810,7 @@ meta_compositor_add_window (MetaCompositor *compositor, + + window_actor = g_object_new (window_actor_type, + "meta-window", window, ++ "show-on-set-parent", FALSE, + NULL); + + if (window->layer == META_LAYER_OVERRIDE_REDIRECT) +-- +2.26.2 + diff --git a/SOURCES/0002-backend-switch-to-using-generated-logind-proxy.patch b/SOURCES/0002-backend-switch-to-using-generated-logind-proxy.patch deleted file mode 100644 index 3cb0623..0000000 --- a/SOURCES/0002-backend-switch-to-using-generated-logind-proxy.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 063db6c9a7504a4d7baae28f7899bd661c459c41 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 14 Jan 2019 11:11:01 -0500 -Subject: [PATCH 2/9] backend: switch to using generated logind proxy - -Right now we listen to prepare-for-sleep using -raw gdbus calls. - -This commit switches it over to use a generated -proxy, which will become useful in a future commit, -for adding suspending inhibitors. ---- - src/backends/meta-backend.c | 60 ++++++++++++++++++++++------------ - src/org.freedesktop.login1.xml | 13 ++++++++ - 2 files changed, 52 insertions(+), 21 deletions(-) - -diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c -index 23ab2faec..5d71977c6 100644 ---- a/src/backends/meta-backend.c -+++ b/src/backends/meta-backend.c -@@ -65,6 +65,7 @@ - #include "meta/main.h" - #include "meta/meta-backend.h" - #include "meta/util.h" -+#include "meta-dbus-login1.h" - - #ifdef HAVE_REMOTE_DESKTOP - #include "backends/meta-dbus-session-watcher.h" -@@ -145,10 +146,12 @@ struct _MetaBackendPrivate - GDBusProxy *upower_proxy; - gboolean lid_is_closed; - -- guint sleep_signal_id; - GCancellable *cancellable; - GDBusConnection *system_bus; - -+ Login1Manager *logind_proxy; -+ int inhibit_sleep_fd; -+ - gboolean was_headless; - }; - typedef struct _MetaBackendPrivate MetaBackendPrivate; -@@ -156,6 +159,10 @@ typedef struct _MetaBackendPrivate MetaBackendPrivate; - static void - initable_iface_init (GInitableIface *initable_iface); - -+ -+static void prepare_for_sleep_cb (MetaBackend *backend, -+ gboolean suspending); -+ - G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaBackend, meta_backend, G_TYPE_OBJECT, - G_ADD_PRIVATE (MetaBackend) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, -@@ -177,8 +184,6 @@ meta_backend_finalize (GObject *object) - g_clear_object (&priv->remote_access_controller); - #endif - -- if (priv->sleep_signal_id) -- g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->sleep_signal_id); - if (priv->upower_watch_id) - g_bus_unwatch_name (priv->upower_watch_id); - g_cancellable_cancel (priv->cancellable); -@@ -764,13 +769,8 @@ meta_backend_create_renderer (MetaBackend *backend, - } - - static void --prepare_for_sleep_cb (GDBusConnection *connection, -- const gchar *sender_name, -- const gchar *object_path, -- const gchar *interface_name, -- const gchar *signal_name, -- GVariant *parameters, -- gpointer user_data) -+prepare_for_sleep_cb (MetaBackend *backend, -+ gboolean suspending) - { - gboolean suspending; - -@@ -780,12 +780,31 @@ prepare_for_sleep_cb (GDBusConnection *connection, - meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ()); - } - -+static Login1Manager * -+get_logind_proxy (GCancellable *cancellable, -+ GError **error) -+{ -+ Login1Manager *proxy; -+ -+ proxy = -+ login1_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, -+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, -+ "org.freedesktop.login1", -+ "/org/freedesktop/login1", -+ cancellable, error); -+ if (!proxy) -+ g_prefix_error (error, "Could not get logind proxy: "); -+ -+ return proxy; -+} -+ - static void - system_bus_gotten_cb (GObject *object, - GAsyncResult *res, - gpointer user_data) - { - MetaBackendPrivate *priv; -+ g_autoptr (GError) error = NULL; - GDBusConnection *bus; - - bus = g_bus_get_finish (res, NULL); -@@ -794,17 +813,16 @@ system_bus_gotten_cb (GObject *object, - - priv = meta_backend_get_instance_private (user_data); - priv->system_bus = bus; -- priv->sleep_signal_id = -- g_dbus_connection_signal_subscribe (priv->system_bus, -- "org.freedesktop.login1", -- "org.freedesktop.login1.Manager", -- "PrepareForSleep", -- "/org/freedesktop/login1", -- NULL, -- G_DBUS_SIGNAL_FLAGS_NONE, -- prepare_for_sleep_cb, -- NULL, -- NULL); -+ priv->logind_proxy = get_logind_proxy (priv->cancellable, &error); -+ -+ if (!priv->logind_proxy) -+ g_warning ("Failed to get logind proxy: %s", error->message); -+ -+ g_signal_connect_object (priv->logind_proxy, -+ "prepare-for-sleep", -+ G_CALLBACK (prepare_for_sleep_cb), -+ user_data, -+ G_CONNECT_SWAPPED); - } - - static gboolean -diff --git a/src/org.freedesktop.login1.xml b/src/org.freedesktop.login1.xml -index 765475132..1ecfd976f 100644 ---- a/src/org.freedesktop.login1.xml -+++ b/src/org.freedesktop.login1.xml -@@ -43,4 +43,17 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - --- -2.21.0 - diff --git a/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch b/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch new file mode 100644 index 0000000..d281b8b --- /dev/null +++ b/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch @@ -0,0 +1,192 @@ +From 6881aa5ca235ee0737c2a409ffab966a10e5971e Mon Sep 17 00:00:00 2001 +From: Christian Hergert +Date: Mon, 24 Feb 2020 22:36:27 +0000 +Subject: [PATCH 2/3] clutter: avoid g_signal_emit_by_name() from ClutterActor + +g_signal_emit_by_name() is used to emit signals on ClutterContainer when +actors are removed or added. It happens to do various interface lookups +which are a bit unneccessary and can allocate memory. + +Simply using emission wrappers makes all of that go away. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1083 +--- + clutter/clutter/cally/cally-actor.c | 5 +-- + clutter/clutter/clutter-actor.c | 17 ++++++++-- + clutter/clutter/clutter-actor.h | 5 ++- + clutter/clutter/clutter-container-private.h | 36 +++++++++++++++++++++ + clutter/clutter/clutter-container.c | 21 ++++++++++++ + 5 files changed, 78 insertions(+), 6 deletions(-) + create mode 100644 clutter/clutter/clutter-container-private.h + +diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c +index 548615f48..517969625 100644 +--- a/clutter/clutter/cally/cally-actor.c ++++ b/clutter/clutter/cally/cally-actor.c +@@ -604,10 +604,11 @@ cally_actor_real_remove_actor (ClutterActor *container, + g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0); + + atk_parent = ATK_OBJECT (data); +- atk_child = clutter_actor_get_accessible (actor); + +- if (atk_child) ++ if (clutter_actor_has_accessible (actor)) + { ++ atk_child = clutter_actor_get_accessible (actor); ++ + g_value_init (&values.old_value, G_TYPE_POINTER); + g_value_set_pointer (&values.old_value, atk_parent); + +diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c +index 803f76aae..93d0a93ef 100644 +--- a/clutter/clutter/clutter-actor.c ++++ b/clutter/clutter/clutter-actor.c +@@ -624,7 +624,7 @@ + #include "clutter-color-static.h" + #include "clutter-color.h" + #include "clutter-constraint-private.h" +-#include "clutter-container.h" ++#include "clutter-container-private.h" + #include "clutter-content-private.h" + #include "clutter-debug.h" + #include "clutter-easing.h" +@@ -4372,7 +4372,7 @@ clutter_actor_remove_child_internal (ClutterActor *self, + + /* we need to emit the signal before dropping the reference */ + if (emit_actor_removed) +- g_signal_emit_by_name (self, "actor-removed", child); ++ _clutter_container_emit_actor_removed (CLUTTER_CONTAINER (self), child); + + if (notify_first_last) + { +@@ -13060,7 +13060,7 @@ clutter_actor_add_child_internal (ClutterActor *self, + } + + if (emit_actor_added) +- g_signal_emit_by_name (self, "actor-added", child); ++ _clutter_container_emit_actor_added (CLUTTER_CONTAINER (self), child); + + if (notify_first_last) + { +@@ -21448,3 +21448,14 @@ clutter_actor_create_texture_paint_node (ClutterActor *self, + + return node; + } ++ ++gboolean ++clutter_actor_has_accessible (ClutterActor *actor) ++{ ++ g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); ++ ++ if (CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible) ++ return CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible (actor); ++ ++ return TRUE; ++} +diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h +index 7d2168af1..d286f2843 100644 +--- a/clutter/clutter/clutter-actor.h ++++ b/clutter/clutter/clutter-actor.h +@@ -296,10 +296,11 @@ struct _ClutterActorClass + + gboolean (* touch_event) (ClutterActor *self, + ClutterTouchEvent *event); ++ gboolean (* has_accessible) (ClutterActor *self); + + /*< private >*/ + /* padding for future expansion */ +- gpointer _padding_dummy[26]; ++ gpointer _padding_dummy[25]; + }; + + /** +@@ -369,6 +370,8 @@ CLUTTER_EXPORT + const gchar * clutter_actor_get_name (ClutterActor *self); + CLUTTER_EXPORT + AtkObject * clutter_actor_get_accessible (ClutterActor *self); ++CLUTTER_EXPORT ++gboolean clutter_actor_has_accessible (ClutterActor *self); + + CLUTTER_EXPORT + gboolean clutter_actor_is_visible (ClutterActor *self); +diff --git a/clutter/clutter/clutter-container-private.h b/clutter/clutter/clutter-container-private.h +new file mode 100644 +index 000000000..d619a6531 +--- /dev/null ++++ b/clutter/clutter/clutter-container-private.h +@@ -0,0 +1,36 @@ ++/* ++ * Clutter. ++ * ++ * An OpenGL based 'interactive canvas' library. ++ * ++ * Copyright 2020 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 __CLUTTER_CONTAINER_PRIVATE_H__ ++#define __CLUTTER_CONTAINER_PRIVATE_H__ ++ ++#include ++ ++G_BEGIN_DECLS ++ ++void _clutter_container_emit_actor_added (ClutterContainer *container, ++ ClutterActor *actor); ++void _clutter_container_emit_actor_removed (ClutterContainer *container, ++ ClutterActor *actor); ++ ++G_END_DECLS ++ ++#endif /* __CLUTTER_CONTAINER_PRIVATE_H__ */ +diff --git a/clutter/clutter/clutter-container.c b/clutter/clutter/clutter-container.c +index 0f611ae55..79abb5b4f 100644 +--- a/clutter/clutter/clutter-container.c ++++ b/clutter/clutter/clutter-container.c +@@ -37,6 +37,7 @@ + + #include "clutter-actor-private.h" + #include "clutter-child-meta.h" ++#include "clutter-container-private.h" + #include "clutter-debug.h" + #include "clutter-main.h" + #include "clutter-marshal.h" +@@ -1446,3 +1447,23 @@ clutter_container_child_notify (ClutterContainer *container, + child, + pspec); + } ++ ++void ++_clutter_container_emit_actor_added (ClutterContainer *container, ++ ClutterActor *actor) ++{ ++ g_return_if_fail (CLUTTER_IS_CONTAINER (container)); ++ g_return_if_fail (CLUTTER_IS_ACTOR (actor)); ++ ++ g_signal_emit (container, container_signals[ACTOR_ADDED], 0, actor); ++} ++ ++void ++_clutter_container_emit_actor_removed (ClutterContainer *container, ++ ClutterActor *actor) ++{ ++ g_return_if_fail (CLUTTER_IS_CONTAINER (container)); ++ g_return_if_fail (CLUTTER_IS_ACTOR (actor)); ++ ++ g_signal_emit (container, container_signals[ACTOR_REMOVED], 0, actor); ++} +-- +2.26.0 + diff --git a/SOURCES/0002-renderer-native-Add-API-to-get-primary-GPU.patch b/SOURCES/0002-renderer-native-Add-API-to-get-primary-GPU.patch new file mode 100644 index 0000000..bd9f592 --- /dev/null +++ b/SOURCES/0002-renderer-native-Add-API-to-get-primary-GPU.patch @@ -0,0 +1,46 @@ +From 63455680096e015eaf023760466593b6f42f9cf5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 12 Sep 2019 11:50:34 +0200 +Subject: [PATCH 2/4] renderer/native: Add API to get primary GPU + +Will be used when acquiring scanouts from Wayland buffers. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/798 +--- + src/backends/native/meta-renderer-native.c | 6 ++++++ + src/backends/native/meta-renderer-native.h | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index dbb88edb8e..25833b6cf6 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -317,6 +317,12 @@ meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms) + return renderer_gpu_data->gbm.device; + } + ++MetaGpuKms * ++meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native) ++{ ++ return renderer_native->primary_gpu_kms; ++} ++ + static MetaRendererNativeGpuData * + meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms) + { +diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h +index 9eecdead1c..b59366e267 100644 +--- a/src/backends/native/meta-renderer-native.h ++++ b/src/backends/native/meta-renderer-native.h +@@ -53,6 +53,8 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms); + + gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native); + ++MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native); ++ + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); + + int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); +-- +2.26.2 + diff --git a/SOURCES/0002-renderer-native-Don-t-leak-DMA-buffer-CoglFramebuffe.patch b/SOURCES/0002-renderer-native-Don-t-leak-DMA-buffer-CoglFramebuffe.patch new file mode 100644 index 0000000..4e383f2 --- /dev/null +++ b/SOURCES/0002-renderer-native-Don-t-leak-DMA-buffer-CoglFramebuffe.patch @@ -0,0 +1,44 @@ +From 2e4d3e22aff7cc8e41fa08d798c55a39a542476c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 2 Jun 2020 18:34:57 +0200 +Subject: [PATCH 2/2] renderer-native: Don't leak DMA buffer CoglFramebuffer + +When we created the DMA buffer backed CoglFramebuffer, we handed it over +to CoglDmaBufHandle which took its own reference. What we failed to do +was to release our own reference to it, effectively leaking it. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283 +(cherry picked from commit c823b5ddba18d30e1fdb74d6764cd40637dc4054) +--- + src/backends/native/meta-renderer-native.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index ba98de650..dbb88edb8 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -2633,6 +2633,7 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, + case META_RENDERER_NATIVE_MODE_GBM: + { + CoglFramebuffer *dmabuf_fb; ++ CoglDmaBufHandle *dmabuf_handle; + struct gbm_bo *new_bo; + int dmabuf_fd = -1; + +@@ -2669,8 +2670,11 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, + if (!dmabuf_fb) + return NULL; + +- return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo, +- (GDestroyNotify) gbm_bo_destroy); ++ dmabuf_handle = ++ cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo, ++ (GDestroyNotify) gbm_bo_destroy); ++ cogl_object_unref (dmabuf_fb); ++ return dmabuf_handle; + } + break; + #ifdef HAVE_EGL_DEVICE +-- +2.26.2 + diff --git a/SOURCES/0003-backend-add-signals-for-reporting-suspend-and-resume.patch b/SOURCES/0003-backend-add-signals-for-reporting-suspend-and-resume.patch deleted file mode 100644 index 03adc3a..0000000 --- a/SOURCES/0003-backend-add-signals-for-reporting-suspend-and-resume.patch +++ /dev/null @@ -1,181 +0,0 @@ -From c5020c3d303ab211a970d88638e7d723034688db Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 10 Jan 2019 10:47:19 -0500 -Subject: [PATCH 3/9] backend: add signals for reporting suspend and resume - -This commit adds "suspending" and "resuming" signals -to MetaBackend. - -It's preliminary work needed for tracking when to purge -and recreate all textures (needed by nvidia). ---- - src/backends/meta-backend.c | 98 ++++++++++++++++++++++++++++++---- - src/org.freedesktop.login1.xml | 1 + - 2 files changed, 88 insertions(+), 11 deletions(-) - -diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c -index 5d71977c6..f59b899b7 100644 ---- a/src/backends/meta-backend.c -+++ b/src/backends/meta-backend.c -@@ -53,6 +53,8 @@ - - #include - -+#include -+ - #include "backends/meta-cursor-tracker-private.h" - #include "backends/meta-idle-monitor-private.h" - #include "backends/meta-input-settings-private.h" -@@ -87,6 +89,8 @@ enum - LAST_DEVICE_CHANGED, - LID_IS_CLOSED_CHANGED, - -+ SUSPENDING, -+ RESUMING, - N_SIGNALS - }; - -@@ -745,6 +749,20 @@ meta_backend_class_init (MetaBackendClass *klass) - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); -+ signals[SUSPENDING] = -+ g_signal_new ("suspending", -+ G_TYPE_FROM_CLASS (object_class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, NULL, -+ G_TYPE_NONE, 0); -+ signals[RESUMING] = -+ g_signal_new ("resuming", -+ G_TYPE_FROM_CLASS (object_class), -+ 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; -@@ -768,15 +786,66 @@ meta_backend_create_renderer (MetaBackend *backend, - return META_BACKEND_GET_CLASS (backend)->create_renderer (backend, error); - } - -+static void -+inhibit_sleep (MetaBackend *backend) -+{ -+ MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); -+ g_autoptr (GVariant) fd_variant = NULL; -+ g_autoptr (GUnixFDList) fd_list = NULL; -+ g_autoptr (GError) error = NULL; -+ int handle, fd; -+ -+ if (priv->inhibit_sleep_fd >= 0) -+ return; -+ -+ if (!login1_manager_call_inhibit_sync (priv->logind_proxy, -+ "sleep", -+ "Display Server", -+ "Prepare for suspend", -+ "delay", -+ NULL, -+ &fd_variant, -+ &fd_list, -+ priv->cancellable, -+ &error)) -+ { -+ g_warning ("Failed to inhibit sleep: %s", error->message); -+ return; -+ } -+ -+ handle = g_variant_get_handle (fd_variant); -+ fd = g_unix_fd_list_get (fd_list, handle, &error); -+ -+ if (fd < 0) -+ { -+ g_warning ("Failed to fetch sleep inhibitor fd: %s", error->message); -+ return; -+ } -+ -+ priv->inhibit_sleep_fd = fd; -+} -+ -+static void -+uninhibit_sleep (MetaBackend *backend) -+{ -+ MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); -+ -+ close (priv->inhibit_sleep_fd); -+ priv->inhibit_sleep_fd = -1; -+} -+ - static void - prepare_for_sleep_cb (MetaBackend *backend, - gboolean suspending) - { -- gboolean suspending; -- -- g_variant_get (parameters, "(b)", &suspending); -- if (suspending) -+ if (suspending) { -+ g_signal_emit (backend, signals[SUSPENDING], 0); -+ uninhibit_sleep (backend); - return; -+ } -+ -+ inhibit_sleep (backend); -+ g_signal_emit (backend, signals[RESUMING], 0); - meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ()); - } - -@@ -803,6 +872,7 @@ system_bus_gotten_cb (GObject *object, - GAsyncResult *res, - gpointer user_data) - { -+ MetaBackend *backend = META_BACKEND (user_data); - MetaBackendPrivate *priv; - g_autoptr (GError) error = NULL; - GDBusConnection *bus; -@@ -814,15 +884,21 @@ system_bus_gotten_cb (GObject *object, - priv = meta_backend_get_instance_private (user_data); - priv->system_bus = bus; - priv->logind_proxy = get_logind_proxy (priv->cancellable, &error); -+ priv->inhibit_sleep_fd = -1; - - if (!priv->logind_proxy) -- g_warning ("Failed to get logind proxy: %s", error->message); -- -- g_signal_connect_object (priv->logind_proxy, -- "prepare-for-sleep", -- G_CALLBACK (prepare_for_sleep_cb), -- user_data, -- G_CONNECT_SWAPPED); -+ { -+ g_warning ("Failed to get logind proxy: %s", error->message); -+ } -+ else -+ { -+ inhibit_sleep (backend); -+ g_signal_connect_object (priv->logind_proxy, -+ "prepare-for-sleep", -+ G_CALLBACK (prepare_for_sleep_cb), -+ user_data, -+ G_CONNECT_SWAPPED); -+ } - } - - static gboolean -diff --git a/src/org.freedesktop.login1.xml b/src/org.freedesktop.login1.xml -index 1ecfd976f..7db8f373c 100644 ---- a/src/org.freedesktop.login1.xml -+++ b/src/org.freedesktop.login1.xml -@@ -46,6 +46,7 @@ - - - -+ - - - --- -2.21.0 - diff --git a/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch b/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch new file mode 100644 index 0000000..557f1ff --- /dev/null +++ b/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch @@ -0,0 +1,167 @@ +From df565fcb681a50aac5046981c5aba04073d14856 Mon Sep 17 00:00:00 2001 +From: Christian Hergert +Date: Fri, 21 Feb 2020 22:36:31 +0000 +Subject: [PATCH 3/3] clutter: fix hole in ClutterPaintNode + +Fixing the missalignment takes the structure from 80 bytes down to 72. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1081 +--- + clutter/clutter/clutter-actor.c | 8 +++---- + clutter/clutter/clutter-canvas.c | 2 +- + clutter/clutter/clutter-image.c | 2 +- + clutter/clutter/clutter-paint-node-private.h | 6 ++--- + clutter/clutter/clutter-paint-node.c | 23 +++++++++++++++----- + clutter/clutter/clutter-paint-node.h | 3 +++ + 6 files changed, 30 insertions(+), 14 deletions(-) + +diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c +index 93d0a93ef..ff5c4a69d 100644 +--- a/clutter/clutter/clutter-actor.c ++++ b/clutter/clutter/clutter-actor.c +@@ -3758,7 +3758,7 @@ clutter_actor_paint_node (ClutterActor *actor, + clear_flags |= COGL_BUFFER_BIT_COLOR; + + node = clutter_root_node_new (fb, &bg_color, clear_flags); +- clutter_paint_node_set_name (node, "stageClear"); ++ clutter_paint_node_set_static_name (node, "stageClear"); + clutter_paint_node_add_rectangle (node, &box); + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); +@@ -3773,7 +3773,7 @@ clutter_actor_paint_node (ClutterActor *actor, + / 255; + + node = clutter_color_node_new (&bg_color); +- clutter_paint_node_set_name (node, "backgroundColor"); ++ clutter_paint_node_set_static_name (node, "backgroundColor"); + clutter_paint_node_add_rectangle (node, &box); + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); +@@ -4069,7 +4069,7 @@ clutter_actor_continue_paint (ClutterActor *self) + * virtual function can then be called directly. + */ + dummy = _clutter_dummy_node_new (self); +- clutter_paint_node_set_name (dummy, "Root"); ++ clutter_paint_node_set_static_name (dummy, "Root"); + + /* XXX - for 1.12, we use the return value of paint_node() to + * decide whether we should emit the ::paint signal. +@@ -21427,7 +21427,7 @@ clutter_actor_create_texture_paint_node (ClutterActor *self, + color.alpha = clutter_actor_get_paint_opacity_internal (self); + + node = clutter_texture_node_new (texture, &color, priv->min_filter, priv->mag_filter); +- clutter_paint_node_set_name (node, "Texture"); ++ clutter_paint_node_set_static_name (node, "Texture"); + + if (priv->content_repeat == CLUTTER_REPEAT_NONE) + clutter_paint_node_add_rectangle (node, &box); +diff --git a/clutter/clutter/clutter-canvas.c b/clutter/clutter/clutter-canvas.c +index b0f1f080c..89c031be2 100644 +--- a/clutter/clutter/clutter-canvas.c ++++ b/clutter/clutter/clutter-canvas.c +@@ -351,7 +351,7 @@ clutter_canvas_paint_content (ClutterContent *content, + return; + + node = clutter_actor_create_texture_paint_node (actor, priv->texture); +- clutter_paint_node_set_name (node, "Canvas Content"); ++ clutter_paint_node_set_static_name (node, "Canvas Content"); + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); + +diff --git a/clutter/clutter/clutter-image.c b/clutter/clutter/clutter-image.c +index 266c68799..790e09521 100644 +--- a/clutter/clutter/clutter-image.c ++++ b/clutter/clutter/clutter-image.c +@@ -129,7 +129,7 @@ clutter_image_paint_content (ClutterContent *content, + return; + + node = clutter_actor_create_texture_paint_node (actor, priv->texture); +- clutter_paint_node_set_name (node, "Image Content"); ++ clutter_paint_node_set_static_name (node, "Image Content"); + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); + } +diff --git a/clutter/clutter/clutter-paint-node-private.h b/clutter/clutter/clutter-paint-node-private.h +index d61b89951..720df1458 100644 +--- a/clutter/clutter/clutter-paint-node-private.h ++++ b/clutter/clutter/clutter-paint-node-private.h +@@ -48,11 +48,11 @@ struct _ClutterPaintNode + ClutterPaintNode *next_sibling; + ClutterPaintNode *last_child; + +- guint n_children; +- + GArray *operations; + +- gchar *name; ++ const gchar *name; ++ ++ guint n_children; + + volatile int ref_count; + }; +diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c +index 73765a4e9..1f9451a43 100644 +--- a/clutter/clutter/clutter-paint-node.c ++++ b/clutter/clutter/clutter-paint-node.c +@@ -171,8 +171,6 @@ clutter_paint_node_real_finalize (ClutterPaintNode *node) + { + ClutterPaintNode *iter; + +- g_free (node->name); +- + if (node->operations != NULL) + { + guint i; +@@ -294,7 +292,8 @@ clutter_paint_node_get_type (void) + * + * The @name will be used for debugging purposes. + * +- * The @node will copy the passed string. ++ * The @node will intern @name using g_intern_string(). If you have access to a ++ * static string, use clutter_paint_node_set_static_name() instead. + * + * Since: 1.10 + */ +@@ -304,8 +303,22 @@ clutter_paint_node_set_name (ClutterPaintNode *node, + { + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + +- g_free (node->name); +- node->name = g_strdup (name); ++ node->name = g_intern_string (name); ++} ++ ++/** ++ * clutter_paint_node_set_static_name: (skip) ++ * ++ * Like clutter_paint_node_set_name() but uses a static or interned string ++ * containing the name. ++ */ ++void ++clutter_paint_node_set_static_name (ClutterPaintNode *node, ++ const char *name) ++{ ++ g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); ++ ++ node->name = name; + } + + /** +diff --git a/clutter/clutter/clutter-paint-node.h b/clutter/clutter/clutter-paint-node.h +index c42abbc3d..7d25f1681 100644 +--- a/clutter/clutter/clutter-paint-node.h ++++ b/clutter/clutter/clutter-paint-node.h +@@ -55,6 +55,9 @@ void clutter_paint_node_paint (Clutter + CLUTTER_EXPORT + void clutter_paint_node_set_name (ClutterPaintNode *node, + const char *name); ++CLUTTER_EXPORT ++void clutter_paint_node_set_static_name (ClutterPaintNode *node, ++ const char *name); + + CLUTTER_EXPORT + void clutter_paint_node_add_child (ClutterPaintNode *node, +-- +2.26.0 + diff --git a/SOURCES/0003-screen-cast-Move-DMA-buffer-allocation-to-MetaScreen.patch b/SOURCES/0003-screen-cast-Move-DMA-buffer-allocation-to-MetaScreen.patch new file mode 100644 index 0000000..8ef52a5 --- /dev/null +++ b/SOURCES/0003-screen-cast-Move-DMA-buffer-allocation-to-MetaScreen.patch @@ -0,0 +1,108 @@ +From 914fd2bec65c2e9928b03d5bc94930bc0151f998 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 17 Jun 2020 17:48:05 +0200 +Subject: [PATCH 3/4] screen-cast: Move DMA buffer allocation to MetaScreenCast + +The aim with centralizing it is to be able to apply global policy to DMA +buffer allocations, e.g. disabling due to various hueristics. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1318 +--- + src/backends/meta-screen-cast-stream-src.c | 18 ++++++-------- + src/backends/meta-screen-cast.c | 28 ++++++++++++++++++++++ + src/backends/meta-screen-cast.h | 4 ++++ + 3 files changed, 39 insertions(+), 11 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index ff4af440c1..b77186415f 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -649,10 +649,10 @@ on_stream_add_buffer (void *data, + MetaScreenCastStreamSrc *src = data; + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); +- CoglContext *context = +- clutter_backend_get_cogl_context (clutter_get_default_backend ()); +- CoglRenderer *renderer = cogl_context_get_renderer (context); +- g_autoptr (GError) error = NULL; ++ 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); + CoglDmaBufHandle *dmabuf_handle; + struct spa_buffer *spa_buffer = buffer->buffer; + struct spa_data *spa_data = spa_buffer->datas; +@@ -664,13 +664,9 @@ on_stream_add_buffer (void *data, + spa_data[0].mapoffset = 0; + spa_data[0].maxsize = stride * priv->video_format.size.height; + +- dmabuf_handle = cogl_renderer_create_dma_buf (renderer, +- priv->stream_width, +- priv->stream_height, +- &error); +- +- if (error) +- g_debug ("Error exporting DMA buffer handle: %s", error->message); ++ dmabuf_handle = meta_screen_cast_create_dma_buf_handle (screen_cast, ++ priv->stream_width, ++ priv->stream_height); + + if (dmabuf_handle) + { +diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c +index 46bc268389..5f1ca8b5ca 100644 +--- a/src/backends/meta-screen-cast.c ++++ b/src/backends/meta-screen-cast.c +@@ -94,6 +94,34 @@ meta_screen_cast_get_backend (MetaScreenCast *screen_cast) + return screen_cast->backend; + } + ++CoglDmaBufHandle * ++meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, ++ int width, ++ int height) ++{ ++ ClutterBackend *clutter_backend = ++ meta_backend_get_clutter_backend (screen_cast->backend); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_backend); ++ CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context); ++ g_autoptr (GError) error = NULL; ++ CoglDmaBufHandle *dmabuf_handle; ++ ++ dmabuf_handle = cogl_renderer_create_dma_buf (cogl_renderer, ++ width, height, ++ &error); ++ if (!dmabuf_handle) ++ { ++ g_warning ("Failed to allocate DMA buffer, " ++ "disabling DMA buffer based screen casting: %s", ++ error->message); ++ screen_cast->disable_dma_bufs = TRUE; ++ return NULL; ++ } ++ ++ return dmabuf_handle; ++} ++ + static gboolean + register_remote_desktop_screen_cast_session (MetaScreenCastSession *session, + const char *remote_desktop_session_id, +diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h +index a3b650cd80..fb5a38f34f 100644 +--- a/src/backends/meta-screen-cast.h ++++ b/src/backends/meta-screen-cast.h +@@ -50,6 +50,10 @@ GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast); + + MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast); + ++CoglDmaBufHandle * meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, ++ int width, ++ int height); ++ + MetaScreenCast * meta_screen_cast_new (MetaBackend *backend, + MetaDbusSessionWatcher *session_watcher); + +-- +2.26.2 + diff --git a/SOURCES/0004-screen-cast-Disable-DMA-buffer-based-screen-casting-.patch b/SOURCES/0004-screen-cast-Disable-DMA-buffer-based-screen-casting-.patch new file mode 100644 index 0000000..6963888 --- /dev/null +++ b/SOURCES/0004-screen-cast-Disable-DMA-buffer-based-screen-casting-.patch @@ -0,0 +1,209 @@ +From a239886e159e6609c3e298effbd0243af8d0e333 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 16 Jun 2020 11:30:11 +0200 +Subject: [PATCH 4/4] screen-cast: Disable DMA buffer based screen casting for + QXL + +QXL doesn't support mmap():ing a DMA buffer allocated in mutter inside +the PipeWire stream consumer process. To make screen casting work again +on QXL, disable DMA buffer based screen casting for QXL. + +Eventually, it should be the client that renegotiates the supported +buffer types, but until then we need this list. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1318 +--- + src/backends/meta-screen-cast.c | 11 ++++++ + src/backends/meta-screen-cast.h | 2 ++ + src/backends/native/meta-backend-native.c | 41 +++++++++++++++++++++++ + src/backends/native/meta-gpu-kms.c | 26 ++++++++++++++ + src/backends/native/meta-gpu-kms.h | 2 ++ + 5 files changed, 82 insertions(+) + +diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c +index 5f1ca8b5ca..268155e7b3 100644 +--- a/src/backends/meta-screen-cast.c ++++ b/src/backends/meta-screen-cast.c +@@ -46,6 +46,8 @@ struct _MetaScreenCast + + MetaDbusSessionWatcher *session_watcher; + MetaBackend *backend; ++ ++ gboolean disable_dma_bufs; + }; + + static void +@@ -94,6 +96,12 @@ meta_screen_cast_get_backend (MetaScreenCast *screen_cast) + return screen_cast->backend; + } + ++void ++meta_screen_cast_disable_dma_bufs (MetaScreenCast *screen_cast) ++{ ++ screen_cast->disable_dma_bufs = TRUE; ++} ++ + CoglDmaBufHandle * + meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, + int width, +@@ -107,6 +115,9 @@ meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, + g_autoptr (GError) error = NULL; + CoglDmaBufHandle *dmabuf_handle; + ++ if (screen_cast->disable_dma_bufs) ++ return NULL; ++ + dmabuf_handle = cogl_renderer_create_dma_buf (cogl_renderer, + width, height, + &error); +diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h +index fb5a38f34f..fa54be729f 100644 +--- a/src/backends/meta-screen-cast.h ++++ b/src/backends/meta-screen-cast.h +@@ -50,6 +50,8 @@ GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast); + + MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast); + ++void meta_screen_cast_disable_dma_bufs (MetaScreenCast *screen_cast); ++ + CoglDmaBufHandle * meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, + int width, + int height); +diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c +index c473681cb0..2bf7f5e7e2 100644 +--- a/src/backends/native/meta-backend-native.c ++++ b/src/backends/native/meta-backend-native.c +@@ -57,6 +57,10 @@ + #include "core/meta-border.h" + #include "meta/main.h" + ++#ifdef HAVE_REMOTE_DESKTOP ++#include "backends/meta-screen-cast.h" ++#endif ++ + struct _MetaBackendNative + { + MetaBackend parent; +@@ -327,6 +331,39 @@ meta_backend_native_create_clutter_backend (MetaBackend *backend) + return g_object_new (META_TYPE_CLUTTER_BACKEND_NATIVE, NULL); + } + ++#ifdef HAVE_REMOTE_DESKTOP ++static void ++maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native) ++{ ++ MetaBackend *backend = META_BACKEND (native); ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); ++ MetaGpuKms *primary_gpu; ++ const char *driver_name; ++ int i; ++ static const char *disable_dma_buf_drivers[] = { ++ "qxl", ++ }; ++ ++ primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native); ++ driver_name = meta_gpu_kms_get_driver_name (primary_gpu); ++ ++ for (i = 0; i < G_N_ELEMENTS (disable_dma_buf_drivers); i++) ++ { ++ if (g_strcmp0 (driver_name, disable_dma_buf_drivers[i]) == 0) ++ { ++ MetaScreenCast *screen_cast = meta_backend_get_screen_cast (backend); ++ ++ g_message ("The '%s' driver doesn't support DMA buffer screen sharing, disabling.", ++ driver_name); ++ ++ meta_screen_cast_disable_dma_bufs (screen_cast); ++ return; ++ } ++ } ++} ++#endif /* HAVE_REMOTE_DESKTOP */ ++ + static void + meta_backend_native_post_init (MetaBackend *backend) + { +@@ -338,6 +375,10 @@ meta_backend_native_post_init (MetaBackend *backend) + NULL, NULL); + clutter_evdev_set_relative_motion_filter (manager, relative_motion_filter, + meta_backend_get_monitor_manager (backend)); ++ ++#ifdef HAVE_REMOTE_DESKTOP ++ maybe_disable_screen_cast_dma_bufs (META_BACKEND_NATIVE (backend)); ++#endif + } + + static MetaMonitorManager * +diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c +index c569b948ef..93e509def5 100644 +--- a/src/backends/native/meta-gpu-kms.c ++++ b/src/backends/native/meta-gpu-kms.c +@@ -66,6 +66,8 @@ struct _MetaGpuKms + char *file_path; + GSource *source; + ++ char *driver_name; ++ + clockid_t clock_id; + + drmModeConnector **connectors; +@@ -790,6 +792,27 @@ init_outputs (MetaGpuKms *gpu_kms, + setup_output_clones (gpu); + } + ++static void ++init_info (MetaGpuKms *gpu_kms) ++{ ++ drmVersion *drm_version; ++ ++ drm_version = drmGetVersion (gpu_kms->fd); ++ if (!drm_version) ++ return; ++ ++ gpu_kms->driver_name = g_strndup (drm_version->name, ++ drm_version->name_len); ++ ++ drmFreeVersion (drm_version); ++} ++ ++const char * ++meta_gpu_kms_get_driver_name (MetaGpuKms *gpu_kms) ++{ ++ return gpu_kms->driver_name; ++} ++ + static gboolean + meta_kms_resources_init (MetaKmsResources *resources, + int fd, +@@ -865,6 +888,7 @@ meta_gpu_kms_read_current (MetaGpu *gpu, + init_crtcs (gpu_kms, &resources); + init_outputs (gpu_kms, &resources); + init_frame_clock (gpu_kms); ++ init_info (gpu_kms); + + meta_kms_resources_release (&resources); + +@@ -940,6 +964,8 @@ meta_gpu_kms_finalize (GObject *object) + + free_resources (gpu_kms); + ++ g_free (gpu_kms->driver_name); ++ + G_OBJECT_CLASS (meta_gpu_kms_parent_class)->finalize (object); + } + +diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h +index 1f7a939e27..6096e58341 100644 +--- a/src/backends/native/meta-gpu-kms.h ++++ b/src/backends/native/meta-gpu-kms.h +@@ -108,4 +108,6 @@ MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu + + void meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container); + ++const char * meta_gpu_kms_get_driver_name (MetaGpuKms *gpu_kms); ++ + #endif /* META_GPU_KMS_H */ +-- +2.26.2 + diff --git a/SOURCES/0004-wayland-force-X-clients-to-redraw-on-resume.patch b/SOURCES/0004-wayland-force-X-clients-to-redraw-on-resume.patch deleted file mode 100644 index d5a0e9f..0000000 --- a/SOURCES/0004-wayland-force-X-clients-to-redraw-on-resume.patch +++ /dev/null @@ -1,118 +0,0 @@ -From a4a703c75e208badf78c81558994a249797dbb0a Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sat, 12 Jan 2019 12:38:01 -0500 -Subject: [PATCH 4/9] wayland: force X clients to redraw on resume - -On nvidia, the textures backing Xwayland client window contents get -corrupted on suspend. Xwayland currently doesn't handle this situation -itself. - -For now, in order to work around this issue, send an empty output -change event to Xwayland. This will cause it to force Expose events -to get sent to all clients and get them to redraw. ---- - .../native/meta-monitor-manager-kms.c | 7 +++ - src/wayland/meta-wayland-outputs.c | 47 +++++++++++++++++++ - src/wayland/meta-wayland-outputs.h | 1 + - 3 files changed, 55 insertions(+) - -diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c -index 9a0364441..7bcceee97 100644 ---- a/src/backends/native/meta-monitor-manager-kms.c -+++ b/src/backends/native/meta-monitor-manager-kms.c -@@ -60,6 +60,7 @@ - #include "clutter/clutter.h" - #include "meta/main.h" - #include "meta/meta-x11-errors.h" -+#include "wayland/meta-wayland-outputs.h" - - #define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor" - -@@ -505,9 +506,15 @@ void - meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms) - { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); -+ ClutterBackend *clutter_backend = clutter_get_default_backend (); -+ CoglContext *cogl_context = -+ clutter_backend_get_cogl_context (clutter_backend); - - meta_monitor_manager_kms_connect_uevent_handler (manager_kms); - handle_hotplug_event (manager); -+ -+ if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES)) -+ meta_wayland_outputs_redraw (meta_wayland_compositor_get_default ()); - } - - static gboolean -diff --git a/src/wayland/meta-wayland-outputs.c b/src/wayland/meta-wayland-outputs.c -index 099e87ab9..bc69d699d 100644 ---- a/src/wayland/meta-wayland-outputs.c -+++ b/src/wayland/meta-wayland-outputs.c -@@ -496,6 +496,53 @@ meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor, - return new_table; - } - -+void -+meta_wayland_outputs_redraw (MetaWaylandCompositor *compositor) -+{ -+ MetaMonitorManager *monitor_manager; -+ GList *logical_monitors, *l; -+ -+ monitor_manager = meta_monitor_manager_get (); -+ -+ logical_monitors = -+ meta_monitor_manager_get_logical_monitors (monitor_manager); -+ -+ for (l = logical_monitors; l; l = l->next) -+ { -+ MetaLogicalMonitor *logical_monitor = l->data; -+ MetaWaylandOutput *wayland_output; -+ GList *iter; -+ -+ if (logical_monitor->winsys_id == 0) -+ continue; -+ -+ wayland_output = -+ g_hash_table_lookup (compositor->outputs, -+ GSIZE_TO_POINTER (logical_monitor->winsys_id)); -+ -+ if (wayland_output == NULL) -+ continue; -+ -+ /* Just output a "changes done" event for one of the outputs, with no actual changes. -+ * xwayland takes this as a cue to send expose events to all X clients. -+ */ -+ for (iter = wayland_output->resources; iter; iter = iter->next) -+ { -+ struct wl_resource *resource = iter->data; -+ if (wl_resource_get_version (resource) >= WL_OUTPUT_DONE_SINCE_VERSION) -+ wl_output_send_done (resource); -+ } -+ -+ for (iter = wayland_output->xdg_output_resources; iter; iter = iter->next) -+ { -+ struct wl_resource *xdg_output = iter->data; -+ zxdg_output_v1_send_done (xdg_output); -+ } -+ -+ break; -+ } -+} -+ - static void - on_monitors_changed (MetaMonitorManager *monitors, - MetaWaylandCompositor *compositor) -diff --git a/src/wayland/meta-wayland-outputs.h b/src/wayland/meta-wayland-outputs.h -index ff15a81bd..d649e0fa1 100644 ---- a/src/wayland/meta-wayland-outputs.h -+++ b/src/wayland/meta-wayland-outputs.h -@@ -49,5 +49,6 @@ struct _MetaWaylandOutput - }; - - void meta_wayland_outputs_init (MetaWaylandCompositor *compositor); -+void meta_wayland_outputs_redraw (MetaWaylandCompositor *compositor); - - #endif /* META_WAYLAND_OUTPUTS_H */ --- -2.21.0 - diff --git a/SOURCES/0005-backends-native-emit-gl-video-memory-purged-when-bec.patch b/SOURCES/0005-backends-native-emit-gl-video-memory-purged-when-bec.patch deleted file mode 100644 index 0567862..0000000 --- a/SOURCES/0005-backends-native-emit-gl-video-memory-purged-when-bec.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 122d7726e450712b8b2fc85db41e3c8ab7b6ad56 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Jan 2019 10:29:55 -0500 -Subject: [PATCH 5/9] backends/native: emit gl-video-memory-purged when - becoming active - -The proprietary NVIDIA driver garbles memory on suspend. In order -to work around that limitation, mutter needs to refresh all its -textures on resuem. - -This commit lays the way toward doing that by emitting the -"gl-video-memory-purged" signal when the compositor becomes active -by logind (which happens on VT switch and on resume). ---- - src/backends/native/meta-backend-native.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c -index c473681cb..f593197e7 100644 ---- a/src/backends/native/meta-backend-native.c -+++ b/src/backends/native/meta-backend-native.c -@@ -653,8 +653,15 @@ void meta_backend_native_resume (MetaBackendNative *native) - meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); -+ MetaDisplay *display = meta_get_display (); -+ ClutterBackend *clutter_backend = clutter_get_default_backend (); -+ CoglContext *cogl_context = -+ clutter_backend_get_cogl_context (clutter_backend); - MetaIdleMonitor *idle_monitor; - -+ if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES)) -+ g_signal_emit_by_name (display, "gl-video-memory-purged"); -+ - meta_monitor_manager_kms_resume (monitor_manager_kms); - - clutter_evdev_reclaim_devices (); --- -2.21.0 - diff --git a/SOURCES/0006-backends-native-update-glyph-cache-on-resume.patch b/SOURCES/0006-backends-native-update-glyph-cache-on-resume.patch deleted file mode 100644 index 3f4193b..0000000 --- a/SOURCES/0006-backends-native-update-glyph-cache-on-resume.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 762ffddfa6157fe50bfa394ecbe4ba707d15f368 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Jan 2019 10:29:55 -0500 -Subject: [PATCH 6/9] backends/native: update glyph cache on resume - -As mentioned in a previous commit, the proprietary NVIDIA -driver garbles memory on suspend. That behavior, means that -clutter's glyph cache (which is stored in GPU memory) gets -corrupted on suspend. - -This commit ensures the glyph cache is blown away when -the logind session becomes active (on VT switch and resume). ---- - src/backends/native/meta-backend-native.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c -index f593197e7..db9b63ac4 100644 ---- a/src/backends/native/meta-backend-native.c -+++ b/src/backends/native/meta-backend-native.c -@@ -660,7 +660,10 @@ void meta_backend_native_resume (MetaBackendNative *native) - MetaIdleMonitor *idle_monitor; - - if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES)) -- g_signal_emit_by_name (display, "gl-video-memory-purged"); -+ { -+ clutter_clear_glyph_cache (); -+ g_signal_emit_by_name (display, "gl-video-memory-purged"); -+ } - - meta_monitor_manager_kms_resume (monitor_manager_kms); - --- -2.21.0 - diff --git a/SOURCES/0007-backends-native-update-cursor-on-resume.patch b/SOURCES/0007-backends-native-update-cursor-on-resume.patch deleted file mode 100644 index 721996f..0000000 --- a/SOURCES/0007-backends-native-update-cursor-on-resume.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 59ba24c09e5d2a3210ca3d259789f7ba5ae6266a Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Jan 2019 10:29:55 -0500 -Subject: [PATCH 7/9] backends/native: update cursor on resume - -As mentioned in a previous commit, the proprietary NVIDIA -driver garbles memory on suspend. That behavior, means that -the cursor gets corrupted on suspend. - -This commit forces the cursor to redraw itself when the -logind session becomes active (on VT switch and resume). ---- - src/backends/native/meta-backend-native.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c -index db9b63ac4..479e9326b 100644 ---- a/src/backends/native/meta-backend-native.c -+++ b/src/backends/native/meta-backend-native.c -@@ -54,6 +54,7 @@ - #include "backends/native/meta-renderer-native.h" - #include "backends/native/meta-stage-native.h" - #include "clutter/evdev/clutter-evdev.h" -+#include "core/display-private.h" - #include "core/meta-border.h" - #include "meta/main.h" - -@@ -662,6 +663,7 @@ void meta_backend_native_resume (MetaBackendNative *native) - if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES)) - { - clutter_clear_glyph_cache (); -+ meta_display_update_cursor (display); - g_signal_emit_by_name (display, "gl-video-memory-purged"); - } - --- -2.21.0 - diff --git a/SOURCES/0008-background-purge-all-background-textures-on-suspend.patch b/SOURCES/0008-background-purge-all-background-textures-on-suspend.patch deleted file mode 100644 index 1034111..0000000 --- a/SOURCES/0008-background-purge-all-background-textures-on-suspend.patch +++ /dev/null @@ -1,110 +0,0 @@ -From c78a614b0d45a4bc8101a93c7138c9fb6102d13c Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 9 Jan 2019 16:57:05 -0500 -Subject: [PATCH 8/9] background: purge all background textures on suspend - -This commit makes sure all background textures get purged -on suspend, which is important for nvidia. ---- - src/compositor/meta-background-image.c | 28 ++++++++++++++++++++++++++ - src/compositor/meta-background.c | 17 +++++++++++++++- - src/meta/meta-background-image.h | 2 ++ - 3 files changed, 46 insertions(+), 1 deletion(-) - -diff --git a/src/compositor/meta-background-image.c b/src/compositor/meta-background-image.c -index 14d3baf57..98909cb53 100644 ---- a/src/compositor/meta-background-image.c -+++ b/src/compositor/meta-background-image.c -@@ -283,6 +283,34 @@ meta_background_image_cache_purge (MetaBackgroundImageCache *cache, - image->in_cache = FALSE; - } - -+/** -+ * meta_background_image_cache_unload_all: -+ * @cache: a #MetaBackgroundImageCache -+ * -+ * Remove all entries from the cache and unloads them; this would be used -+ * if textures in video memory have been invalidated. -+ */ -+void -+meta_background_image_cache_unload_all (MetaBackgroundImageCache *cache) -+{ -+ GHashTableIter iter; -+ gpointer key, value; -+ -+ g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache)); -+ -+ g_hash_table_iter_init (&iter, cache->images); -+ while (g_hash_table_iter_next (&iter, &key, &value)) -+ { -+ MetaBackgroundImage *image = value; -+ -+ g_clear_pointer (&image->texture, cogl_object_unref); -+ image->in_cache = FALSE; -+ image->loaded = FALSE; -+ } -+ -+ g_hash_table_remove_all (cache->images); -+} -+ - G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT); - - static void -diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c -index c033395fe..abdfcc7df 100644 ---- a/src/compositor/meta-background.c -+++ b/src/compositor/meta-background.c -@@ -303,6 +303,18 @@ meta_background_finalize (GObject *object) - G_OBJECT_CLASS (meta_background_parent_class)->finalize (object); - } - -+static void -+free_textures (MetaBackground *self) -+{ -+ free_color_texture (self); -+ free_wallpaper_texture (self); -+ -+ set_file (self, &self->file1, &self->background_image1, NULL); -+ set_file (self, &self->file2, &self->background_image2, NULL); -+ -+ mark_changed (self); -+} -+ - static void - meta_background_constructed (GObject *object) - { -@@ -312,7 +324,7 @@ meta_background_constructed (GObject *object) - G_OBJECT_CLASS (meta_background_parent_class)->constructed (object); - - g_signal_connect_object (self->display, "gl-video-memory-purged", -- G_CALLBACK (mark_changed), object, G_CONNECT_SWAPPED); -+ G_CALLBACK (free_textures), object, G_CONNECT_SWAPPED); - - g_signal_connect_object (monitor_manager, "monitors-changed", - G_CALLBACK (on_monitors_changed), self, -@@ -950,8 +962,11 @@ meta_background_set_blend (MetaBackground *self, - void - meta_background_refresh_all (void) - { -+ MetaBackgroundImageCache *cache = meta_background_image_cache_get_default (); - GSList *l; - -+ meta_background_image_cache_unload_all (cache); -+ - for (l = all_backgrounds; l; l = l->next) - mark_changed (l->data); - } -diff --git a/src/meta/meta-background-image.h b/src/meta/meta-background-image.h -index 137a6ff8e..87e40d251 100644 ---- a/src/meta/meta-background-image.h -+++ b/src/meta/meta-background-image.h -@@ -66,4 +66,6 @@ META_EXPORT - void meta_background_image_cache_purge (MetaBackgroundImageCache *cache, - GFile *file); - -+void meta_background_image_cache_unload_all (MetaBackgroundImageCache *cache); -+ - #endif /* __META_BACKGROUND_IMAGE_H__ */ --- -2.21.0 - diff --git a/SOURCES/0009-MetaShapedTexture-save-and-restore-textures-on-suspe.patch b/SOURCES/0009-MetaShapedTexture-save-and-restore-textures-on-suspe.patch deleted file mode 100644 index 4b38154..0000000 --- a/SOURCES/0009-MetaShapedTexture-save-and-restore-textures-on-suspe.patch +++ /dev/null @@ -1,712 +0,0 @@ -From d8cc418899276b45cb1a787493e0998e3b008fe5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 10 Jan 2019 10:48:02 -0500 -Subject: [PATCH 9/9] MetaShapedTexture: save and restore textures on suspend - -The proprietary nvidia driver garbles GPU memory on suspend. - -In order to workaround that limitation, this commit copies all -textures to host memory on suspend and restores them on resume. - -One complication comes from external textures (such as those -given to us by Xwayland for X clients). We can't just restore -those textures, since they aren't writable. - -This commit addresses that complication by keeping a local texture -around for those external textures, and using it instead for parts -of the window that haven't been redrawn since resume. ---- - src/compositor/meta-shaped-texture.c | 487 +++++++++++++++++++++++++-- - src/meta/meta-shaped-texture.h | 2 + - 2 files changed, 468 insertions(+), 21 deletions(-) - -diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c -index d64e214e5..ea8daa03d 100644 ---- a/src/compositor/meta-shaped-texture.c -+++ b/src/compositor/meta-shaped-texture.c -@@ -40,7 +40,9 @@ - #include "compositor/meta-texture-tower.h" - #include "compositor/region-utils.h" - #include "core/boxes-private.h" -+#include - #include "meta/meta-shaped-texture.h" -+#include "meta-texture-rectangle.h" - - /* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU - * performance, but higher than the refresh rate of commonly slow updating -@@ -72,8 +74,12 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self, - - static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume); - -+static void disable_backing_store (MetaShapedTexture *stex); -+ - static void cullable_iface_init (MetaCullableInterface *iface); - -+static gboolean meta_debug_show_backing_store = FALSE; -+ - enum - { - SIZE_CHANGED, -@@ -83,6 +89,14 @@ enum - - static guint signals[LAST_SIGNAL]; - -+typedef struct -+{ -+ CoglTexture *texture; -+ CoglTexture *mask_texture; -+ cairo_surface_t *mask_surface; -+ cairo_region_t *region; -+} MetaTextureBackingStore; -+ - struct _MetaShapedTexture - { - ClutterActor parent; -@@ -114,6 +128,16 @@ struct _MetaShapedTexture - int viewport_dst_width; - int viewport_dst_height; - -+ /* textures get corrupted on suspend, so save them */ -+ cairo_surface_t *saved_base_surface; -+ cairo_surface_t *saved_mask_surface; -+ -+ /* We can't just restore external textures, so we need to track -+ * which parts of the external texture are freshly drawn from -+ * the client after corruption, and fill in the rest from our -+ * saved snapshot */ -+ MetaTextureBackingStore *backing_store; -+ - int tex_width, tex_height; - int fallback_width, fallback_height; - int dst_width, dst_height; -@@ -148,6 +172,9 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass) - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -+ -+ if (g_getenv ("MUTTER_DEBUG_BACKING_STORE")) -+ meta_debug_show_backing_store = TRUE; - } - - static void -@@ -159,6 +186,11 @@ invalidate_size (MetaShapedTexture *stex) - static void - meta_shaped_texture_init (MetaShapedTexture *stex) - { -+ MetaBackend *backend = meta_get_backend (); -+ ClutterBackend *clutter_backend = clutter_get_default_backend (); -+ CoglContext *cogl_context = -+ clutter_backend_get_cogl_context (clutter_backend); -+ - stex->paint_tower = meta_texture_tower_new (); - - stex->texture = NULL; -@@ -171,6 +203,12 @@ meta_shaped_texture_init (MetaShapedTexture *stex) - "notify::scale-x", - G_CALLBACK (invalidate_size), - stex); -+ -+ if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES)) -+ { -+ g_signal_connect_object (backend, "suspending", G_CALLBACK (meta_shaped_texture_save), stex, G_CONNECT_SWAPPED); -+ g_signal_connect_object (backend, "resuming", G_CALLBACK (meta_shaped_texture_restore), stex, G_CONNECT_SWAPPED); -+ } - } - - static void -@@ -311,24 +349,72 @@ meta_shaped_texture_dispose (GObject *object) - G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object); - } - -+static int -+get_layer_indices (MetaShapedTexture *stex, -+ int *main_layer_index, -+ int *backing_mask_layer_index, -+ int *backing_layer_index, -+ int *mask_layer_index) -+{ -+ int next_layer_index = 0; -+ -+ if (main_layer_index) -+ *main_layer_index = next_layer_index; -+ -+ next_layer_index++; -+ -+ if (stex->backing_store) -+ { -+ if (backing_mask_layer_index) -+ *backing_mask_layer_index = next_layer_index; -+ next_layer_index++; -+ if (backing_layer_index) -+ *backing_layer_index = next_layer_index; -+ next_layer_index++; -+ } -+ else -+ { -+ if (backing_mask_layer_index) -+ *backing_mask_layer_index = -1; -+ if (backing_layer_index) -+ *backing_layer_index = -1; -+ } -+ -+ if (mask_layer_index) -+ *mask_layer_index = next_layer_index; -+ -+ return next_layer_index; -+} -+ - static CoglPipeline * - get_base_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) - { - CoglPipeline *pipeline; -+ int main_layer_index; -+ int backing_layer_index; -+ int backing_mask_layer_index; -+ int i, number_of_layers; - - if (stex->base_pipeline) - return stex->base_pipeline; - - pipeline = cogl_pipeline_new (ctx); -- cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0, -- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -- cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, -- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -- cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1, -- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -- cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1, -- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -+ -+ number_of_layers = get_layer_indices (stex, -+ &main_layer_index, -+ &backing_mask_layer_index, -+ &backing_layer_index, -+ NULL); -+ -+ for (i = 0; i < number_of_layers; i++) -+ { -+ cogl_pipeline_set_layer_wrap_mode_s (pipeline, i, -+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -+ cogl_pipeline_set_layer_wrap_mode_t (pipeline, i, -+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); -+ } -+ - if (!stex->is_y_inverted) - { - CoglMatrix matrix; -@@ -336,7 +422,22 @@ get_base_pipeline (MetaShapedTexture *stex, - cogl_matrix_init_identity (&matrix); - cogl_matrix_scale (&matrix, 1, -1, 1); - cogl_matrix_translate (&matrix, 0, -1, 0); -- cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); -+ cogl_pipeline_set_layer_matrix (pipeline, main_layer_index, &matrix); -+ } -+ -+ if (stex->backing_store) -+ { -+ g_autofree char *backing_description = NULL; -+ cogl_pipeline_set_layer_combine (pipeline, backing_mask_layer_index, -+ "RGBA = REPLACE(PREVIOUS)", -+ NULL); -+ backing_description = g_strdup_printf ("RGBA = INTERPOLATE(PREVIOUS, TEXTURE_%d, TEXTURE_%d[A])", -+ backing_layer_index, -+ backing_mask_layer_index); -+ cogl_pipeline_set_layer_combine (pipeline, -+ backing_layer_index, -+ backing_description, -+ NULL); - } - - if (stex->transform != META_MONITOR_TRANSFORM_NORMAL) -@@ -379,7 +480,7 @@ get_base_pipeline (MetaShapedTexture *stex, - } - - if (stex->snippet) -- cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet); -+ cogl_pipeline_add_layer_snippet (pipeline, main_layer_index, stex->snippet); - - stex->base_pipeline = pipeline; - -@@ -398,12 +499,15 @@ get_masked_pipeline (MetaShapedTexture *stex, - CoglContext *ctx) - { - CoglPipeline *pipeline; -+ int mask_layer_index; - - if (stex->masked_pipeline) - return stex->masked_pipeline; - -+ get_layer_indices (stex, NULL, NULL, NULL, &mask_layer_index); -+ - pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx)); -- cogl_pipeline_set_layer_combine (pipeline, 1, -+ cogl_pipeline_set_layer_combine (pipeline, mask_layer_index, - "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", - NULL); - -@@ -517,6 +621,8 @@ set_cogl_texture (MetaShapedTexture *stex, - if (stex->texture) - cogl_object_unref (stex->texture); - -+ g_clear_pointer (&stex->saved_base_surface, cairo_surface_destroy); -+ - stex->texture = cogl_tex; - - if (cogl_tex != NULL) -@@ -579,6 +685,10 @@ do_paint (MetaShapedTexture *stex, - CoglContext *ctx; - ClutterActorBox alloc; - CoglPipelineFilter filter; -+ int main_layer_index; -+ int backing_mask_layer_index; -+ int backing_layer_index; -+ int mask_layer_index; - - clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); - ensure_size_valid (stex); -@@ -665,6 +775,12 @@ do_paint (MetaShapedTexture *stex, - } - } - -+ get_layer_indices (stex, -+ &main_layer_index, -+ &backing_mask_layer_index, -+ &backing_layer_index, -+ &mask_layer_index); -+ - /* First, paint the unblended parts, which are part of the opaque region. */ - if (use_opaque_region) - { -@@ -686,8 +802,24 @@ do_paint (MetaShapedTexture *stex, - if (!cairo_region_is_empty (region)) - { - opaque_pipeline = get_unblended_pipeline (stex, ctx); -- cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); -- cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); -+ cogl_pipeline_set_layer_texture (opaque_pipeline, main_layer_index, paint_tex); -+ cogl_pipeline_set_layer_filters (opaque_pipeline, main_layer_index, filter, filter); -+ -+ if (stex->backing_store) -+ { -+ cogl_pipeline_set_layer_texture (opaque_pipeline, -+ backing_mask_layer_index, -+ stex->backing_store->mask_texture); -+ cogl_pipeline_set_layer_filters (opaque_pipeline, -+ backing_mask_layer_index, -+ filter, filter); -+ cogl_pipeline_set_layer_texture (opaque_pipeline, -+ backing_layer_index, -+ stex->backing_store->texture); -+ cogl_pipeline_set_layer_filters (opaque_pipeline, -+ backing_layer_index, -+ filter, filter); -+ } - - n_rects = cairo_region_num_rectangles (region); - for (i = 0; i < n_rects; i++) -@@ -726,12 +858,28 @@ do_paint (MetaShapedTexture *stex, - else - { - blended_pipeline = get_masked_pipeline (stex, ctx); -- cogl_pipeline_set_layer_texture (blended_pipeline, 1, stex->mask_texture); -- cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter); -+ cogl_pipeline_set_layer_texture (blended_pipeline, mask_layer_index, stex->mask_texture); -+ cogl_pipeline_set_layer_filters (blended_pipeline, mask_layer_index, filter, filter); - } - -- cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex); -- cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter); -+ cogl_pipeline_set_layer_texture (blended_pipeline, main_layer_index, paint_tex); -+ cogl_pipeline_set_layer_filters (blended_pipeline, main_layer_index, filter, filter); -+ -+ if (stex->backing_store) -+ { -+ cogl_pipeline_set_layer_texture (blended_pipeline, -+ backing_mask_layer_index, -+ stex->backing_store->mask_texture); -+ cogl_pipeline_set_layer_filters (blended_pipeline, -+ backing_mask_layer_index, -+ filter, filter); -+ cogl_pipeline_set_layer_texture (blended_pipeline, -+ backing_layer_index, -+ stex->backing_store->texture); -+ cogl_pipeline_set_layer_filters (blended_pipeline, -+ backing_layer_index, -+ filter, filter); -+ } - - CoglColor color; - cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); -@@ -925,6 +1073,7 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - g_clear_pointer (&stex->mask_texture, cogl_object_unref); -+ g_clear_pointer (&stex->saved_mask_surface, cairo_surface_destroy); - - if (mask_texture != NULL) - { -@@ -946,6 +1095,65 @@ meta_shaped_texture_is_obscured (MetaShapedTexture *stex) - return FALSE; - } - -+static void -+meta_texture_backing_store_redraw_mask (MetaTextureBackingStore *backing_store) -+{ -+ CoglError *error = NULL; -+ -+ if (!cogl_texture_set_data (backing_store->mask_texture, COGL_PIXEL_FORMAT_A_8, -+ cairo_image_surface_get_stride (backing_store->mask_surface), -+ cairo_image_surface_get_data (backing_store->mask_surface), 0, -+ &error)) -+ { -+ -+ g_warning ("Failed to update backing mask texture"); -+ g_clear_pointer (&error, cogl_error_free); -+ } -+} -+ -+static gboolean -+meta_texture_backing_store_shrink (MetaTextureBackingStore *backing_store, -+ const cairo_rectangle_int_t *area) -+{ -+ cairo_t *cr; -+ -+ cairo_region_subtract_rectangle (backing_store->region, area); -+ -+ /* If the client has finally redrawn the entire surface, we can -+ * ditch our snapshot -+ */ -+ if (cairo_region_is_empty (backing_store->region)) -+ return FALSE; -+ -+ cr = cairo_create (backing_store->mask_surface); -+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); -+ cairo_paint (cr); -+ gdk_cairo_region (cr, backing_store->region); -+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); -+ cairo_fill (cr); -+ cairo_destroy (cr); -+ -+ meta_texture_backing_store_redraw_mask (backing_store); -+ -+ return TRUE; -+} -+ -+static void -+shrink_backing_region (MetaShapedTexture *stex, -+ const cairo_rectangle_int_t *area) -+{ -+ gboolean still_backing_texture; -+ -+ if (!stex->backing_store) -+ return; -+ -+ still_backing_texture = -+ meta_texture_backing_store_shrink (stex->backing_store, area); -+ -+ if (!still_backing_texture) -+ disable_backing_store (stex); -+} -+ - /** - * meta_shaped_texture_update_area: - * @stex: #MetaShapedTexture -@@ -1041,6 +1249,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, - &clip); - } - -+ shrink_backing_region (stex, &clip); -+ - meta_texture_tower_update_area (stex->paint_tower, - clip.x, - clip.y, -@@ -1268,8 +1478,9 @@ should_get_via_offscreen (MetaShapedTexture *stex) - } - - static cairo_surface_t * --get_image_via_offscreen (MetaShapedTexture *stex, -- cairo_rectangle_int_t *clip) -+get_image_via_offscreen (MetaShapedTexture *stex, -+ cairo_rectangle_int_t *clip, -+ CoglTexture **texture) - { - ClutterBackend *clutter_backend = clutter_get_default_backend (); - CoglContext *cogl_context = -@@ -1340,9 +1551,29 @@ get_image_via_offscreen (MetaShapedTexture *stex, - clip->width, clip->height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_data (surface)); -+ cairo_surface_mark_dirty (surface); -+ -+ if (texture) -+ { -+ *texture = cogl_object_ref (image_texture); -+ -+ if (G_UNLIKELY (meta_debug_show_backing_store)) -+ { -+ cairo_t *cr; -+ -+ cr = cairo_create (surface); -+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.75); -+ cairo_paint (cr); -+ cairo_destroy (cr); -+ } -+ -+ cogl_texture_set_data (*texture, CLUTTER_CAIRO_FORMAT_ARGB32, -+ cairo_image_surface_get_stride (surface), -+ cairo_image_surface_get_data (surface), 0, NULL); -+ } -+ - cogl_object_unref (fb); - -- cairo_surface_mark_dirty (surface); - - return surface; - } -@@ -1404,7 +1635,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, - } - - if (should_get_via_offscreen (stex)) -- return get_image_via_offscreen (stex, transformed_clip); -+ return get_image_via_offscreen (stex, transformed_clip, NULL); - - if (transformed_clip) - texture = cogl_texture_new_from_sub_texture (texture, -@@ -1465,6 +1696,220 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, - return surface; - } - -+static void -+meta_texture_backing_store_free (MetaTextureBackingStore *backing_store) -+{ -+ g_clear_pointer (&backing_store->texture, cogl_object_unref); -+ g_clear_pointer (&backing_store->mask_texture, cogl_object_unref); -+ g_clear_pointer (&backing_store->mask_surface, cairo_surface_destroy); -+ g_clear_pointer (&backing_store->region, cairo_region_destroy); -+ -+ g_slice_free (MetaTextureBackingStore, backing_store); -+} -+ -+static MetaTextureBackingStore * -+meta_texture_backing_store_new (CoglTexture *texture) -+{ -+ MetaTextureBackingStore *backing_store = NULL; -+ ClutterBackend *backend = clutter_get_default_backend (); -+ CoglContext *context = clutter_backend_get_cogl_context (backend); -+ CoglTexture *mask_texture = NULL; -+ guchar *mask_data; -+ int width, height, stride; -+ cairo_surface_t *surface; -+ cairo_region_t *region; -+ cairo_rectangle_int_t backing_rectangle; -+ -+ width = cogl_texture_get_width (texture); -+ height = cogl_texture_get_height (texture); -+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, width); -+ -+ /* we start off by only letting the backing texture through, and none of the real texture */ -+ backing_rectangle.x = 0; -+ backing_rectangle.y = 0; -+ backing_rectangle.width = width; -+ backing_rectangle.height = height; -+ -+ region = cairo_region_create_rectangle (&backing_rectangle); -+ -+ /* initialize mask to transparent, so the entire backing store shows through -+ * up front -+ */ -+ mask_data = g_malloc0 (stride * height); -+ surface = cairo_image_surface_create_for_data (mask_data, -+ CAIRO_FORMAT_A8, -+ width, -+ height, -+ stride); -+ -+ if (meta_texture_rectangle_check (texture)) -+ { -+ mask_texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (context, -+ width, -+ height)); -+ cogl_texture_set_components (mask_texture, COGL_TEXTURE_COMPONENTS_A); -+ cogl_texture_set_region (mask_texture, -+ 0, 0, -+ 0, 0, -+ width, height, -+ width, height, -+ COGL_PIXEL_FORMAT_A_8, -+ stride, mask_data); -+ } -+ else -+ { -+ CoglError *error = NULL; -+ -+ mask_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (context, width, height, -+ COGL_PIXEL_FORMAT_A_8, -+ stride, mask_data, &error)); -+ -+ if (error) -+ { -+ g_warning ("Failed to allocate mask texture: %s", error->message); -+ cogl_error_free (error); -+ } -+ } -+ -+ if (mask_texture) -+ { -+ backing_store = g_slice_new0 (MetaTextureBackingStore); -+ backing_store->texture = cogl_object_ref (texture); -+ backing_store->mask_texture = mask_texture; -+ backing_store->mask_surface = surface; -+ backing_store->region = region; -+ } -+ -+ return backing_store; -+} -+ -+static void -+enable_backing_store (MetaShapedTexture *stex, -+ CoglTexture *texture) -+{ -+ g_clear_pointer (&stex->backing_store, meta_texture_backing_store_free); -+ -+ stex->backing_store = meta_texture_backing_store_new (texture); -+ -+ meta_shaped_texture_reset_pipelines (stex); -+} -+ -+static void -+disable_backing_store (MetaShapedTexture *stex) -+{ -+ g_clear_pointer (&stex->backing_store, meta_texture_backing_store_free); -+ -+ meta_shaped_texture_reset_pipelines (stex); -+} -+ -+void -+meta_shaped_texture_save (MetaShapedTexture *stex) -+{ -+ -+ CoglTexture *texture, *mask_texture; -+ cairo_surface_t *surface; -+ -+ g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); -+ -+ texture = COGL_TEXTURE (stex->texture); -+ -+ if (texture == NULL) -+ return; -+ -+ g_clear_pointer (&stex->saved_base_surface, cairo_surface_destroy); -+ g_clear_pointer (&stex->saved_mask_surface, cairo_surface_destroy); -+ g_clear_pointer (&stex->backing_store, meta_texture_backing_store_free); -+ -+ if (should_get_via_offscreen (stex)) -+ { -+ CoglTexture *backing_texture; -+ -+ meta_shaped_texture_reset_pipelines (stex); -+ -+ surface = get_image_via_offscreen (stex, NULL, &backing_texture); -+ -+ enable_backing_store (stex, backing_texture); -+ cogl_object_unref (backing_texture); -+ } -+ else -+ { -+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -+ cogl_texture_get_width (texture), -+ cogl_texture_get_height (texture)); -+ -+ cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, -+ cairo_image_surface_get_stride (surface), -+ cairo_image_surface_get_data (surface)); -+ } -+ -+ stex->saved_base_surface = surface; -+ -+ mask_texture = stex->mask_texture; -+ if (mask_texture != NULL) -+ { -+ cairo_surface_t *mask_surface; -+ -+ mask_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -+ cogl_texture_get_width (mask_texture), -+ cogl_texture_get_height (mask_texture)); -+ -+ cogl_texture_get_data (mask_texture, CLUTTER_CAIRO_FORMAT_ARGB32, -+ cairo_image_surface_get_stride (mask_surface), -+ cairo_image_surface_get_data (mask_surface)); -+ -+ cairo_surface_mark_dirty (mask_surface); -+ -+ stex->saved_mask_surface = mask_surface; -+ } -+} -+ -+void -+meta_shaped_texture_restore (MetaShapedTexture *stex) -+{ -+ CoglTexture *texture; -+ CoglError *error = NULL; -+ -+ texture = meta_shaped_texture_get_texture (stex); -+ -+ if (texture == NULL) -+ return; -+ -+ if (stex->mask_texture) -+ { -+ if (!cogl_texture_set_data (stex->mask_texture, CLUTTER_CAIRO_FORMAT_ARGB32, -+ cairo_image_surface_get_stride (stex->saved_mask_surface), -+ cairo_image_surface_get_data (stex->saved_mask_surface), 0, -+ &error)) -+ { -+ g_warning ("Failed to restore mask texture"); -+ g_clear_pointer (&error, cogl_error_free); -+ } -+ g_clear_pointer (&stex->saved_mask_surface, cairo_surface_destroy); -+ } -+ -+ /* if the main texture doesn't support direct writes, then -+ * write to the local backing texture instead, and blend old -+ * versus new at paint time. -+ */ -+ if (stex->backing_store) -+ { -+ meta_texture_backing_store_redraw_mask (stex->backing_store); -+ texture = stex->backing_store->texture; -+ } -+ -+ if (!cogl_texture_set_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, -+ cairo_image_surface_get_stride (stex->saved_base_surface), -+ cairo_image_surface_get_data (stex->saved_base_surface), 0, -+ &error)) -+ { -+ g_warning ("Failed to restore texture"); -+ g_clear_pointer (&error, cogl_error_free); -+ } -+ g_clear_pointer (&stex->saved_base_surface, cairo_surface_destroy); -+ -+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); -+} -+ - void - meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, - int fallback_width, -diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h -index c36b8547f..22b4fbd53 100644 ---- a/src/meta/meta-shaped-texture.h -+++ b/src/meta/meta-shaped-texture.h -@@ -66,6 +66,8 @@ META_EXPORT - cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex, - cairo_rectangle_int_t *clip); - -+void meta_shaped_texture_save (MetaShapedTexture *self); -+void meta_shaped_texture_restore (MetaShapedTexture *self); - G_END_DECLS - - #endif /* __META_SHAPED_TEXTURE_H__ */ --- -2.21.0 - diff --git a/SOURCES/handle-hotplug-better.patch b/SOURCES/handle-hotplug-better.patch new file mode 100644 index 0000000..57668d9 --- /dev/null +++ b/SOURCES/handle-hotplug-better.patch @@ -0,0 +1,614 @@ +From d442ef48412e3dc1b24a9f97b02ee3383404d501 Mon Sep 17 00:00:00 2001 +From: Emil Velikov +Date: Wed, 12 Jun 2019 16:58:54 +0000 +Subject: [PATCH 1/8] renderer/native: add missing eglTerminate in EGLDevice + error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the EGLDevice code gets the display and calls eglInitialize. +As a follow-up it checks the required EGL extensions - technically it +could check the EGL device extensions earlier. + +In either case, eglTerminate is missing. Thus the connection to the +display was still bound. + +This was highlighted with Mesa commit d6edccee8da ("egl: add +EGL_platform_device support") + amdgpu. + +In that case, since the eglTerminate is missing, we end up reusing the +underlying amdgpu_device due to some caching in libdrm_amdgpu. The +latter in itself being a good solution since it allows buffer sharing +across primary and render node of the same device. + +Note: we should really get this in branches all the way back to 3.30. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/619 + +Fixes: 934184e23 ("MetaRendererNative: Add EGLDevice based rendering support") +Cc: Jonas Ådahl +Signed-off-by: Emil Velikov + + +(cherry picked from commit 9213574870faee7fe40609791fc48f4b44f861c0) +--- + src/backends/native/meta-renderer-native.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index dbfc97aae..207b654fa 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -4038,6 +4038,7 @@ create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native, + G_IO_ERROR_FAILED, + "Missing EGL extensions required for EGLDevice renderer: %s", + missing_extensions_str); ++ meta_egl_terminate (egl, egl_display, NULL); + g_free (missing_extensions_str); + g_free (missing_extensions); + return NULL; +-- +2.24.1 + + +From e18dfc888343585d21b3f64568571009c4967a95 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 17 Jun 2019 18:18:12 +0200 +Subject: [PATCH 2/8] renderer/native: Use g_set_error() instead of + _cogl_set_error() + +It's even a GError, so lets use the proper API. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/622 +(cherry picked from commit 1efb32d3000ca06ee3cfcc146dc812866d243619) +--- + 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 207b654fa..e7aa6f389 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -1277,7 +1277,7 @@ meta_renderer_native_egl_context_created (CoglDisplay *cogl_display, + cogl_display_egl->dummy_surface, + cogl_display_egl->egl_context)) + { +- _cogl_set_error (error, COGL_WINSYS_ERROR, ++ g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to make context current"); + return FALSE; +-- +2.24.1 + + +From 1947a81db93624d57471ce1edf5548c7774c3569 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 17 Jun 2019 18:18:42 +0200 +Subject: [PATCH 3/8] renderer/native: Make sure we're not destroying an active + EGLSurface + +When making a new surface/context pair current, mesa may want to flush +the old context. Make sure we don't try to flush any freed memory by +unmaking a surface/context pair current before freeing it. + +Not doing this results in the following valgrind warnings: + +==15986== Invalid read of size 8 +==15986== at 0x69A6D80: dri_flush_front_buffer (gbm_dri.c:92) +==15986== by 0x1750D458: intel_flush_front (brw_context.c:251) +==15986== by 0x1750D4BB: intel_glFlush (brw_context.c:296) +==15986== by 0x1739D8DD: dri2_make_current (egl_dri2.c:1461) +==15986== by 0x17393A3A: eglMakeCurrent (eglapi.c:869) +==15986== by 0x54381FB: InternalMakeCurrentVendor (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0) +==15986== by 0x5438515: eglMakeCurrent (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0) +==15986== by 0x522A782: _cogl_winsys_egl_make_current (cogl-winsys-egl.c:303) +==15986== by 0x49B64C8: meta_renderer_native_create_view (meta-renderer-native.c:3076) +==15986== by 0x48D26E7: meta_renderer_create_view (meta-renderer.c:78) +==15986== by 0x48D277A: meta_renderer_rebuild_views (meta-renderer.c:111) +==15986== by 0x49BF46E: meta_stage_native_rebuild_views (meta-stage-native.c:142) +==15986== Address 0x1b076600 is 0 bytes inside a block of size 48 free'd +==15986== at 0x4839A0C: free (vg_replace_malloc.c:540) +==15986== by 0x49B59F3: meta_renderer_native_release_onscreen (meta-renderer-native.c:2651) +==15986== by 0x5211441: _cogl_onscreen_free (cogl-onscreen.c:167) +==15986== by 0x5210D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51) +==15986== by 0x51D0066: _cogl_object_default_unref (cogl-object.c:103) +==15986== by 0x520F989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814) +==15986== by 0x51D00B1: cogl_object_unref (cogl-object.c:115) +==15986== by 0x536F3C7: clutter_stage_view_dispose (clutter-stage-view.c:304) +==15986== by 0x4B7DAF2: g_object_unref (gobject.c:3309) +==15986== by 0x4A9596C: g_list_foreach (glist.c:1013) +==15986== by 0x4A9599A: g_list_free_full (glist.c:223) +==15986== by 0x48D2737: meta_renderer_rebuild_views (meta-renderer.c:100) +==15986== Block was alloc'd at +==15986== at 0x483AB1A: calloc (vg_replace_malloc.c:762) +==15986== by 0x69A76B2: gbm_dri_surface_create (gbm_dri.c:1252) +==15986== by 0x69A6BFE: gbm_surface_create (gbm.c:600) +==15986== by 0x49B4E29: meta_renderer_native_create_surface_gbm (meta-renderer-native.c:2221) +==15986== by 0x49B57DB: meta_onscreen_native_allocate (meta-renderer-native.c:2569) +==15986== by 0x49B6423: meta_renderer_native_create_view (meta-renderer-native.c:3062) +==15986== by 0x48D26E7: meta_renderer_create_view (meta-renderer.c:78) +==15986== by 0x48D277A: meta_renderer_rebuild_views (meta-renderer.c:111) +==15986== by 0x49BF46E: meta_stage_native_rebuild_views (meta-stage-native.c:142) +==15986== by 0x49A75B5: meta_backend_native_update_screen_size (meta-backend-native.c:520) +==15986== by 0x48B01BB: meta_backend_sync_screen_size (meta-backend.c:224) +==15986== by 0x48B09B7: meta_backend_real_post_init (meta-backend.c:501) + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/622 +(cherry picked from commit 56ddaaa3809240a357b5e19b5789d1aa49aaecc3) +--- + src/backends/native/meta-renderer-native.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index e7aa6f389..b7bc3121a 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -3040,6 +3040,8 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + { + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *cogl_context = framebuffer->context; ++ CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); ++ CoglDisplayEGL *cogl_display_egl = cogl_display->winsys; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; +@@ -3052,6 +3054,17 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + + onscreen_native = onscreen_egl->platform; + ++ if (onscreen_egl->egl_surface != EGL_NO_SURFACE && ++ (cogl_display_egl->current_draw_surface == onscreen_egl->egl_surface || ++ cogl_display_egl->current_read_surface == onscreen_egl->egl_surface)) ++ { ++ if (!_cogl_winsys_egl_make_current (cogl_display, ++ cogl_display_egl->dummy_surface, ++ cogl_display_egl->dummy_surface, ++ cogl_display_egl->egl_context)) ++ g_warning ("Failed to clear current context"); ++ } ++ + g_list_free_full (onscreen_native->pending_page_flip_retries, + (GDestroyNotify) retry_page_flip_data_free); + if (onscreen_native->retry_page_flips_source) +-- +2.24.1 + + +From 60551e5e6f984a7ed3ba3339f027ed7b37f802c4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 17 Jun 2019 19:16:12 +0200 +Subject: [PATCH 4/8] renderer/native: Fix EGLSurface destruction order + +Make sure to destroy the EGL surface after releasing held buffers, +otherwise we'll get the following valgrind warnings: + +==24016== Invalid read of size 8 +==24016== at 0x1739943F: release_buffer (platform_drm.c:73) +==24016== by 0x49AC355: meta_drm_buffer_gbm_finalize (meta-drm-buffer-gbm.c:213) +==24016== by 0x4B75B61: g_object_unref (gobject.c:3346) +==24016== by 0x49B4B41: free_current_bo (meta-renderer-native.c:991) +==24016== by 0x49B816F: meta_renderer_native_release_onscreen (meta-renderer-native.c:2971) +==24016== by 0x5209441: _cogl_onscreen_free (cogl-onscreen.c:167) +==24016== by 0x5208D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51) +==24016== by 0x51C8066: _cogl_object_default_unref (cogl-object.c:103) +==24016== by 0x5207989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814) +==24016== by 0x51C80B1: cogl_object_unref (cogl-object.c:115) +==24016== by 0x53673C7: clutter_stage_view_dispose (clutter-stage-view.c:304) +==24016== by 0x4B75AF2: g_object_unref (gobject.c:3309) +==24016== Address 0x18e742a8 is 536 bytes inside a block of size 784 free'd +==24016== at 0x4839A0C: free (vg_replace_malloc.c:540) +==24016== by 0x17399764: dri2_drm_destroy_surface (platform_drm.c:231) +==24016== by 0x1738550A: eglDestroySurface (eglapi.c:1145) +==24016== by 0x5440286: eglDestroySurface (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0) +==24016== by 0x49613A5: meta_egl_destroy_surface (meta-egl.c:432) +==24016== by 0x49B80F9: meta_renderer_native_release_onscreen (meta-renderer-native.c:2954) +==24016== by 0x5209441: _cogl_onscreen_free (cogl-onscreen.c:167) +==24016== by 0x5208D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51) +==24016== by 0x51C8066: _cogl_object_default_unref (cogl-object.c:103) +==24016== by 0x5207989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814) +==24016== by 0x51C80B1: cogl_object_unref (cogl-object.c:115) +==24016== by 0x53673C7: clutter_stage_view_dispose (clutter-stage-view.c:304) +==24016== Block was alloc'd at +==24016== at 0x483AB1A: calloc (vg_replace_malloc.c:762) +==24016== by 0x173997AE: dri2_drm_create_window_surface (platform_drm.c:145) +==24016== by 0x17388906: _eglCreateWindowSurfaceCommon (eglapi.c:929) +==24016== by 0x5440197: eglCreateWindowSurface (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0) +==24016== by 0x49612FF: meta_egl_create_window_surface (meta-egl.c:396) +==24016== by 0x49B752E: meta_renderer_native_create_surface_gbm (meta-renderer-native.c:2538) +==24016== by 0x49B7E6C: meta_onscreen_native_allocate (meta-renderer-native.c:2870) +==24016== by 0x49B8BCF: meta_renderer_native_create_view (meta-renderer-native.c:3387) +==24016== by 0x48D274B: meta_renderer_create_view (meta-renderer.c:78) +==24016== by 0x48D27DE: meta_renderer_rebuild_views (meta-renderer.c:111) +==24016== by 0x49BB4FB: meta_stage_native_rebuild_views (meta-stage-native.c:142) +==24016== by 0x49A733C: meta_backend_native_update_screen_size (meta-backend-native.c:517) + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/622 +(cherry picked from commit d9fb11b04319c00fd89715dd9207fe54e1d18c2d) +--- + src/backends/native/meta-renderer-native.c | 38 +++++++++++++++------- + 1 file changed, 27 insertions(+), 11 deletions(-) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index b7bc3121a..62c27c191 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -3035,6 +3035,28 @@ meta_onscreen_native_allocate (CoglOnscreen *onscreen, + return TRUE; + } + ++static void ++destroy_egl_surface (CoglOnscreen *onscreen) ++{ ++ CoglOnscreenEGL *onscreen_egl = onscreen->winsys; ++ ++ if (onscreen_egl->egl_surface != EGL_NO_SURFACE) ++ { ++ MetaOnscreenNative *onscreen_native = onscreen_egl->platform; ++ MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); ++ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); ++ CoglContext *cogl_context = framebuffer->context; ++ CoglRenderer *cogl_renderer = cogl_context->display->renderer; ++ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; ++ ++ meta_egl_destroy_surface (egl, ++ cogl_renderer_egl->edpy, ++ onscreen_egl->egl_surface, ++ NULL); ++ onscreen_egl->egl_surface = EGL_NO_SURFACE; ++ } ++} ++ + static void + meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + { +@@ -3077,17 +3099,6 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + g_source_destroy); + } + +- if (onscreen_egl->egl_surface != EGL_NO_SURFACE) +- { +- MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); +- +- meta_egl_destroy_surface (egl, +- cogl_renderer_egl->edpy, +- onscreen_egl->egl_surface, +- NULL); +- onscreen_egl->egl_surface = EGL_NO_SURFACE; +- } +- + renderer_gpu_data = + meta_renderer_native_get_gpu_data (onscreen_native->renderer_native, + onscreen_native->render_gpu); +@@ -3100,6 +3111,8 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + + free_current_bo (onscreen); + ++ destroy_egl_surface (onscreen); ++ + if (onscreen_native->gbm.surface) + { + gbm_surface_destroy (onscreen_native->gbm.surface); +@@ -3110,6 +3123,9 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + case META_RENDERER_NATIVE_MODE_EGL_DEVICE: + release_dumb_fb (&onscreen_native->egl.dumb_fb, + onscreen_native->render_gpu); ++ ++ destroy_egl_surface (onscreen); ++ + if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR) + { + MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); +-- +2.24.1 + + +From c447010a23edc03c7a1103b477972ad666c2600f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 19 Jun 2019 20:55:48 +0200 +Subject: [PATCH 5/8] renderer/native: Remove left-over function declarations + +There are no callers and no definitions of these. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/655 +--- + src/backends/native/meta-renderer-native.h | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h +index a006dcbe7..8468208e1 100644 +--- a/src/backends/native/meta-renderer-native.h ++++ b/src/backends/native/meta-renderer-native.h +@@ -55,18 +55,6 @@ gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_n + + void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); + +-gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native, +- MetaRendererView *view, +- int width, +- int height, +- GError **error); +- +-void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native, +- uint32_t id, +- gboolean ignore); +- +-MetaRendererView * meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native); +- + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); + + int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); +-- +2.24.1 + + +From 7f97403d12df19cf936a341cc218743ec339aa0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 19 Jun 2019 20:57:14 +0200 +Subject: [PATCH 6/8] renderer/native: Queue mode reset from new rebuild_views + vfunc + +Simplify the call site a bit and make the native renderer know it should +queue mode reset itself when views have been rebuilt. This is done +partly due to more things needing to be dealt with after views have been +rebuilt. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/655 +--- + src/backends/meta-renderer.c | 8 ++++++++ + src/backends/meta-renderer.h | 1 + + src/backends/native/meta-renderer-native.c | 17 ++++++++++++++++- + src/backends/native/meta-renderer-native.h | 2 -- + src/backends/native/meta-stage-native.c | 1 - + 5 files changed, 25 insertions(+), 4 deletions(-) + +diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c +index 28637437b..87ba9f9f0 100644 +--- a/src/backends/meta-renderer.c ++++ b/src/backends/meta-renderer.c +@@ -90,6 +90,12 @@ meta_renderer_create_view (MetaRenderer *renderer, + */ + void + meta_renderer_rebuild_views (MetaRenderer *renderer) ++{ ++ return META_RENDERER_GET_CLASS (renderer)->rebuild_views (renderer); ++} ++ ++static void ++meta_renderer_real_rebuild_views (MetaRenderer *renderer) + { + MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); + MetaBackend *backend = meta_get_backend (); +@@ -181,4 +187,6 @@ meta_renderer_class_init (MetaRendererClass *klass) + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_renderer_finalize; ++ ++ klass->rebuild_views = meta_renderer_real_rebuild_views; + } +diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h +index dae52cb9a..478baee91 100644 +--- a/src/backends/meta-renderer.h ++++ b/src/backends/meta-renderer.h +@@ -43,6 +43,7 @@ struct _MetaRendererClass + CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer); + MetaRendererView * (* create_view) (MetaRenderer *renderer, + MetaLogicalMonitor *logical_monitor); ++ void (* rebuild_views) (MetaRenderer *renderer); + }; + + CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer); +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index 62c27c191..70e1c4f9d 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -258,6 +258,9 @@ cogl_pixel_format_from_drm_format (uint32_t drm_format, + CoglPixelFormat *out_format, + CoglTextureComponents *out_components); + ++static void ++meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); ++ + static MetaBackend * + backend_from_renderer_native (MetaRendererNative *renderer_native) + { +@@ -3186,7 +3189,7 @@ meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native) + return TRUE; + } + +-void ++static void + meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native) + { + MetaRenderer *renderer = META_RENDERER (renderer_native); +@@ -3552,6 +3555,17 @@ meta_renderer_native_create_view (MetaRenderer *renderer, + return view; + } + ++static void ++meta_renderer_native_rebuild_views (MetaRenderer *renderer) ++{ ++ MetaRendererClass *parent_renderer_class = ++ META_RENDERER_CLASS (meta_renderer_native_parent_class); ++ ++ parent_renderer_class->rebuild_views (renderer); ++ ++ meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); ++} ++ + void + meta_renderer_native_finish_frame (MetaRendererNative *renderer_native) + { +@@ -4350,6 +4364,7 @@ meta_renderer_native_class_init (MetaRendererNativeClass *klass) + + renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer; + renderer_class->create_view = meta_renderer_native_create_view; ++ renderer_class->rebuild_views = meta_renderer_native_rebuild_views; + + obj_props[PROP_MONITOR_MANAGER] = + g_param_spec_object ("monitor-manager", +diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h +index 8468208e1..9eecdead1 100644 +--- a/src/backends/native/meta-renderer-native.h ++++ b/src/backends/native/meta-renderer-native.h +@@ -53,8 +53,6 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms); + + gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native); + +-void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); +- + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); + + int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); +diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c +index add3e81fd..9b9c45ef3 100644 +--- a/src/backends/native/meta-stage-native.c ++++ b/src/backends/native/meta-stage-native.c +@@ -140,7 +140,6 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native) + ClutterActor *stage = meta_backend_get_stage (backend); + + meta_renderer_rebuild_views (renderer); +- meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); + clutter_stage_update_resource_scales (CLUTTER_STAGE (stage)); + ensure_frame_callbacks (stage_native); + } +-- +2.24.1 + + +From 025054c93e43e8359c9ecafb6edea1eb4b7ad681 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 19 Jun 2019 21:14:05 +0200 +Subject: [PATCH 7/8] renderer/native: Discard page flip retries when + rebuilding views + +Rebuilding views means we don't care to retry page flip attempts for +previous views, especially since connectors may have been disconnected, +making a page flip retry hit an assert a flipped CRTC has connectors +associated with it. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/655 +--- + src/backends/native/meta-renderer-native.c | 50 +++++++++++++++++----- + 1 file changed, 39 insertions(+), 11 deletions(-) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index 70e1c4f9d..3cd01bcb7 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -3060,6 +3060,24 @@ destroy_egl_surface (CoglOnscreen *onscreen) + } + } + ++static void ++discard_onscreen_page_flip_retries (MetaOnscreenNative *onscreen_native) ++{ ++ g_list_free_full (onscreen_native->pending_page_flip_retries, ++ (GDestroyNotify) retry_page_flip_data_free); ++ onscreen_native->pending_page_flip_retries = NULL; ++ ++ if (onscreen_native->retry_page_flips_source) ++ { ++ MetaBackend *backend = ++ backend_from_renderer_native (onscreen_native->renderer_native); ++ ++ meta_backend_thaw_updates (backend); ++ g_clear_pointer (&onscreen_native->retry_page_flips_source, ++ g_source_destroy); ++ } ++} ++ + static void + meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + { +@@ -3090,17 +3108,7 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) + g_warning ("Failed to clear current context"); + } + +- g_list_free_full (onscreen_native->pending_page_flip_retries, +- (GDestroyNotify) retry_page_flip_data_free); +- if (onscreen_native->retry_page_flips_source) +- { +- MetaBackend *backend = +- backend_from_renderer_native (onscreen_native->renderer_native); +- +- meta_backend_thaw_updates (backend); +- g_clear_pointer (&onscreen_native->retry_page_flips_source, +- g_source_destroy); +- } ++ discard_onscreen_page_flip_retries (onscreen_native); + + renderer_gpu_data = + meta_renderer_native_get_gpu_data (onscreen_native->renderer_native, +@@ -3555,12 +3563,32 @@ meta_renderer_native_create_view (MetaRenderer *renderer, + return view; + } + ++static void ++discard_page_flip_retries (MetaRenderer *renderer) ++{ ++ GList *l; ++ ++ for (l = meta_renderer_get_views (renderer); l; l = l->next) ++ { ++ ClutterStageView *stage_view = l->data; ++ CoglFramebuffer *framebuffer = ++ clutter_stage_view_get_onscreen (stage_view); ++ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); ++ CoglOnscreenEGL *onscreen_egl = onscreen->winsys; ++ MetaOnscreenNative *onscreen_native = onscreen_egl->platform; ++ ++ discard_onscreen_page_flip_retries (onscreen_native); ++ } ++} ++ + static void + meta_renderer_native_rebuild_views (MetaRenderer *renderer) + { + MetaRendererClass *parent_renderer_class = + META_RENDERER_CLASS (meta_renderer_native_parent_class); + ++ discard_page_flip_retries (renderer); ++ + parent_renderer_class->rebuild_views (renderer); + + meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); +-- +2.24.1 + + +From f4fdec6003e2cf9fa4b1882e92faf1da64e6052e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 27 Nov 2019 17:34:35 +0100 +Subject: [PATCH 8/8] =?UTF-8?q?crtc-kms:=20Ignore=2090=C2=B0=20rotations?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +They tend to require special modifiers or won't work at all; ignore +them. +--- + src/backends/native/meta-crtc-kms.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c +index 8c2fbfe3c..8374376d5 100644 +--- a/src/backends/native/meta-crtc-kms.c ++++ b/src/backends/native/meta-crtc-kms.c +@@ -368,12 +368,8 @@ parse_transforms (MetaCrtc *crtc, + + if (strcmp (prop->enums[i].name, "rotate-0") == 0) + transform = META_MONITOR_TRANSFORM_NORMAL; +- else if (strcmp (prop->enums[i].name, "rotate-90") == 0) +- transform = META_MONITOR_TRANSFORM_90; + else if (strcmp (prop->enums[i].name, "rotate-180") == 0) + transform = META_MONITOR_TRANSFORM_180; +- else if (strcmp (prop->enums[i].name, "rotate-270") == 0) +- transform = META_MONITOR_TRANSFORM_270; + + if (transform != -1) + { +-- +2.24.1 + diff --git a/SOURCES/screen-cast-remote-desktop-improvements.patch b/SOURCES/screen-cast-remote-desktop-improvements.patch new file mode 100644 index 0000000..954602c --- /dev/null +++ b/SOURCES/screen-cast-remote-desktop-improvements.patch @@ -0,0 +1,5977 @@ +From ac409e38b820ebf07a5677a3b393933dd3cf668d Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 18:24:02 -0300 +Subject: [PATCH 01/49] clutter/stage-view: Move unexported functions to + private header + +Next commits will expose ClutterStageView as a public class, so +move the functions private to Clutter to a private header. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage-view-private.h | 37 ++++++++++++++++++++ + clutter/clutter/clutter-stage-view.c | 1 + + clutter/clutter/clutter-stage-view.h | 13 ------- + clutter/clutter/clutter-stage.c | 1 + + clutter/clutter/cogl/clutter-stage-cogl.c | 1 + + clutter/clutter/meson.build | 1 + + 6 files changed, 41 insertions(+), 13 deletions(-) + create mode 100644 clutter/clutter/clutter-stage-view-private.h + +diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h +new file mode 100644 +index 000000000..89c42599f +--- /dev/null ++++ b/clutter/clutter/clutter-stage-view-private.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (C) 2019 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 __CLUTTER_STAGE_VIEW_PRIVATE_H__ ++#define __CLUTTER_STAGE_VIEW_PRIVATE_H__ ++ ++#include "clutter/clutter-stage-view.h" ++ ++void clutter_stage_view_blit_offscreen (ClutterStageView *view, ++ const cairo_rectangle_int_t *clip); ++ ++gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view); ++ ++void clutter_stage_view_set_dirty_viewport (ClutterStageView *view, ++ gboolean dirty); ++ ++gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view); ++ ++void clutter_stage_view_set_dirty_projection (ClutterStageView *view, ++ gboolean dirty); ++ ++ ++#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */ +diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c +index c536ac720..e26e2fc07 100644 +--- a/clutter/clutter/clutter-stage-view.c ++++ b/clutter/clutter/clutter-stage-view.c +@@ -18,6 +18,7 @@ + #include "clutter-build-config.h" + + #include "clutter/clutter-stage-view.h" ++#include "clutter/clutter-stage-view-private.h" + + #include + #include +diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h +index 126498625..0c3448511 100644 +--- a/clutter/clutter/clutter-stage-view.h ++++ b/clutter/clutter/clutter-stage-view.h +@@ -57,22 +57,9 @@ void clutter_stage_view_transform_to_onscreen (ClutterStageView *vie + gfloat *x, + gfloat *y); + +-void clutter_stage_view_blit_offscreen (ClutterStageView *view, +- const cairo_rectangle_int_t *clip); +- + CLUTTER_EXPORT + float clutter_stage_view_get_scale (ClutterStageView *view); + +-gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view); +- +-void clutter_stage_view_set_dirty_viewport (ClutterStageView *view, +- gboolean dirty); +- +-gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view); +- +-void clutter_stage_view_set_dirty_projection (ClutterStageView *view, +- gboolean dirty); +- + CLUTTER_EXPORT + void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view, + CoglMatrix *matrix); +diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c +index 1eea5b305..f254b5d49 100644 +--- a/clutter/clutter/clutter-stage.c ++++ b/clutter/clutter/clutter-stage.c +@@ -72,6 +72,7 @@ + #include "clutter-private.h" + #include "clutter-stage-manager-private.h" + #include "clutter-stage-private.h" ++#include "clutter-stage-view-private.h" + #include "clutter-private.h" + + #include "cogl/cogl.h" +diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c +index eab76e52f..d942d9d41 100644 +--- a/clutter/clutter/cogl/clutter-stage-cogl.c ++++ b/clutter/clutter/cogl/clutter-stage-cogl.c +@@ -45,6 +45,7 @@ + #include "clutter-main.h" + #include "clutter-private.h" + #include "clutter-stage-private.h" ++#include "clutter-stage-view-private.h" + + typedef struct _ClutterStageViewCoglPrivate + { +diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build +index 671d790df..7feed24aa 100644 +--- a/clutter/clutter/meson.build ++++ b/clutter/clutter/meson.build +@@ -206,6 +206,7 @@ clutter_private_headers = [ + 'clutter-stage-manager-private.h', + 'clutter-stage-private.h', + 'clutter-stage-view.h', ++ 'clutter-stage-view-private.h', + 'clutter-stage-window.h', + ] + +-- +2.26.2 + + +From cc2cf250f91d4b4c939aa1c6f8dd9dad4d77d975 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 18:32:12 -0300 +Subject: [PATCH 02/49] clutter/stage-view: Annotate some functions + +The GIR parser cannot figure out the ownership model of +ClutterStageView.get_framebuffer() and .get_offscreen() +without them, and throws us a couple of warnings. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage-view.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c +index e26e2fc07..0fad6fc44 100644 +--- a/clutter/clutter/clutter-stage-view.c ++++ b/clutter/clutter/clutter-stage-view.c +@@ -66,6 +66,14 @@ clutter_stage_view_get_layout (ClutterStageView *view, + *rect = priv->layout; + } + ++/** ++ * clutter_stage_view_get_framebuffer: ++ * @view: a #ClutterStageView ++ * ++ * Retrieves the framebuffer of @view to draw to. ++ * ++ * Returns: (transfer none): a #CoglFramebuffer ++ */ + CoglFramebuffer * + clutter_stage_view_get_framebuffer (ClutterStageView *view) + { +@@ -80,6 +88,14 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view) + return priv->framebuffer; + } + ++/** ++ * clutter_stage_view_get_onscreen: ++ * @view: a #ClutterStageView ++ * ++ * Retrieves the onscreen framebuffer of @view if available. ++ * ++ * Returns: (transfer none): a #CoglFramebuffer ++ */ + CoglFramebuffer * + clutter_stage_view_get_onscreen (ClutterStageView *view) + { +-- +2.26.2 + + +From c21e563398edccbd210defe367d89920b2d3f3d1 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 18:33:17 -0300 +Subject: [PATCH 03/49] clutter: Make ClutterStageView a public class + +As a compositor toolkit, it makes sense to allow consumers +of Clutter interact with the stage views themselves. As such, +ClutterStageView should be a public class. + +As such, it is now included in clutter.h and should not be +included directly. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage-view.h | 4 ++++ + clutter/clutter/clutter.h | 1 + + clutter/clutter/meson.build | 4 ++-- + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h +index 0c3448511..26bf10e79 100644 +--- a/clutter/clutter/clutter-stage-view.h ++++ b/clutter/clutter/clutter-stage-view.h +@@ -18,6 +18,10 @@ + #ifndef __CLUTTER_STAGE_VIEW_H__ + #define __CLUTTER_STAGE_VIEW_H__ + ++#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) ++#error "Only can be included directly." ++#endif ++ + #include + #include + #include +diff --git a/clutter/clutter/clutter.h b/clutter/clutter/clutter.h +index 231d8cd1b..ec846910f 100644 +--- a/clutter/clutter/clutter.h ++++ b/clutter/clutter/clutter.h +@@ -101,6 +101,7 @@ + #include "clutter-snap-constraint.h" + #include "clutter-stage.h" + #include "clutter-stage-manager.h" ++#include "clutter-stage-view.h" + #include "clutter-tap-action.h" + #include "clutter-test-utils.h" + #include "clutter-texture.h" +diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build +index 7feed24aa..8e0484453 100644 +--- a/clutter/clutter/meson.build ++++ b/clutter/clutter/meson.build +@@ -75,6 +75,7 @@ clutter_headers = [ + 'clutter-snap-constraint.h', + 'clutter-stage.h', + 'clutter-stage-manager.h', ++ 'clutter-stage-view.h', + 'clutter-tap-action.h', + 'clutter-test-utils.h', + 'clutter-texture.h', +@@ -163,6 +164,7 @@ clutter_sources = [ + 'clutter-snap-constraint.c', + 'clutter-stage.c', + 'clutter-stage-manager.c', ++ 'clutter-stage-view.c', + 'clutter-stage-window.c', + 'clutter-tap-action.c', + 'clutter-test-utils.c', +@@ -205,7 +207,6 @@ clutter_private_headers = [ + 'clutter-settings-private.h', + 'clutter-stage-manager-private.h', + 'clutter-stage-private.h', +- 'clutter-stage-view.h', + 'clutter-stage-view-private.h', + 'clutter-stage-window.h', + ] +@@ -214,7 +215,6 @@ clutter_nonintrospected_sources = [ + 'clutter-easing.c', + 'clutter-event-translator.c', + 'clutter-id-pool.c', +- 'clutter-stage-view.c', + ] + + clutter_deprecated_headers = [ +-- +2.26.2 + + +From dfb1b9a61f2909be14be5a152f5eacb93cddafa2 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 18:39:34 -0300 +Subject: [PATCH 04/49] clutter/stage: Own clutter_stage_get_view_at() + +This function is exported as a Mutter-specific function, +but now that ClutterStageView is part of the public API, +ClutterStage can own this function. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h +index 5730af7bd..9d0fdd362 100644 +--- a/clutter/clutter/clutter-stage.h ++++ b/clutter/clutter/clutter-stage.h +@@ -30,6 +30,7 @@ + + #include + #include ++#include + + G_BEGIN_DECLS + +@@ -274,6 +275,10 @@ gboolean clutter_stage_capture (ClutterStage *stage, + cairo_rectangle_int_t *rect, + ClutterCapture **captures, + int *n_captures); ++CLUTTER_EXPORT ++ClutterStageView * clutter_stage_get_view_at (ClutterStage *stage, ++ float x, ++ float y); + + G_END_DECLS + +-- +2.26.2 + + +From 29cd64c50a054384bf737ff12ee62770ae20b305 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 19:16:47 -0300 +Subject: [PATCH 05/49] clutter/stage: Emit after-paint after painting + +ClutterStage:after-paint is supposed to be emitted after all +painting is done, but before the frame is finished. However, +as it is right now, it is being emitted after each view is +painted -- on multi-monitor setups, after-frame is being +emitted multiple times. + +Send after-paint only once, after all views are painted and +before finishing the frame. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage-private.h | 1 + + clutter/clutter/clutter-stage.c | 5 +++++ + clutter/clutter/cogl/clutter-stage-cogl.c | 2 ++ + 3 files changed, 8 insertions(+) + +diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h +index 4799c29e1..df0bf642b 100644 +--- a/clutter/clutter/clutter-stage-private.h ++++ b/clutter/clutter/clutter-stage-private.h +@@ -40,6 +40,7 @@ void _clutter_stage_paint_view (ClutterStage + ClutterStageView *view, + const cairo_rectangle_int_t *clip); + ++void _clutter_stage_emit_after_paint (ClutterStage *stage); + void _clutter_stage_set_window (ClutterStage *stage, + ClutterStageWindow *stage_window); + ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage); +diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c +index f254b5d49..2b437e1f6 100644 +--- a/clutter/clutter/clutter-stage.c ++++ b/clutter/clutter/clutter-stage.c +@@ -690,6 +690,11 @@ _clutter_stage_paint_view (ClutterStage *stage, + return; + + clutter_stage_do_paint_view (stage, view, clip); ++} ++ ++void ++_clutter_stage_emit_after_paint (ClutterStage *stage) ++{ + g_signal_emit (stage, stage_signals[AFTER_PAINT], 0); + } + +diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c +index d942d9d41..005c6f692 100644 +--- a/clutter/clutter/cogl/clutter-stage-cogl.c ++++ b/clutter/clutter/cogl/clutter-stage-cogl.c +@@ -936,6 +936,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) + clutter_stage_cogl_redraw_view (stage_window, view) || swap_event; + } + ++ _clutter_stage_emit_after_paint (stage_cogl->wrapper); ++ + _clutter_stage_window_finish_frame (stage_window); + + if (swap_event) +-- +2.26.2 + + +From 152945e1061d37d8e5899d2df9a24c25f46096ed Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 21:33:42 -0300 +Subject: [PATCH 06/49] clutter/stage: Add ClutterStage:paint-view + +Now that ClutterStageView is embraced as part of the public +set of Clutter classes, is it possible to give consumers +of this API more information and control over the drawing +routines of ClutterStage. + +Introduce ClutterStage:paint-view, a signal that is emitted +for painting a specific view. It's defined as a RUN_LAST +signal to give anyone connecting to it the ability to run +before the view is actually painted, or after (using the +G_CONNECT_AFTER flag, or g_signal_connect_after). + +This signal has a corresponding class handler, which allows +Mutter to have much finer control over the painting routines. +In fact, this will allow us to implement a "paint phase watcher" +mechanism in the following patches. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/clutter/clutter-stage.c | 47 ++++++++++++++++++++++++++++++++- + clutter/clutter/clutter-stage.h | 5 +++- + 2 files changed, 50 insertions(+), 2 deletions(-) + +diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c +index 2b437e1f6..34c4e0119 100644 +--- a/clutter/clutter/clutter-stage.c ++++ b/clutter/clutter/clutter-stage.c +@@ -148,6 +148,8 @@ struct _ClutterStagePrivate + gpointer paint_data; + GDestroyNotify paint_notify; + ++ cairo_rectangle_int_t view_clip; ++ + int update_freeze_count; + + guint relayout_pending : 1; +@@ -192,6 +194,7 @@ enum + DEACTIVATE, + DELETE_EVENT, + AFTER_PAINT, ++ PAINT_VIEW, + PRESENTED, + + LAST_SIGNAL +@@ -689,7 +692,15 @@ _clutter_stage_paint_view (ClutterStage *stage, + if (!priv->impl) + return; + +- clutter_stage_do_paint_view (stage, view, clip); ++ priv->view_clip = *clip; ++ ++ if (g_signal_has_handler_pending (stage, stage_signals[PAINT_VIEW], ++ 0, TRUE)) ++ g_signal_emit (stage, stage_signals[PAINT_VIEW], 0, view); ++ else ++ CLUTTER_STAGE_GET_CLASS (stage)->paint_view (stage, view); ++ ++ priv->view_clip = (cairo_rectangle_int_t) { 0 }; + } + + void +@@ -1901,6 +1912,16 @@ clutter_stage_finalize (GObject *object) + G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object); + } + ++static void ++clutter_stage_real_paint_view (ClutterStage *stage, ++ ClutterStageView *view) ++{ ++ ClutterStagePrivate *priv = stage->priv; ++ const cairo_rectangle_int_t *clip = &priv->view_clip; ++ ++ clutter_stage_do_paint_view (stage, view, clip); ++} ++ + static void + clutter_stage_class_init (ClutterStageClass *klass) + { +@@ -1930,6 +1951,8 @@ clutter_stage_class_init (ClutterStageClass *klass) + actor_class->queue_redraw = clutter_stage_real_queue_redraw; + actor_class->apply_transform = clutter_stage_real_apply_transform; + ++ klass->paint_view = clutter_stage_real_paint_view; ++ + /** + * ClutterStage:fullscreen: + * +@@ -2257,6 +2280,28 @@ clutter_stage_class_init (ClutterStageClass *klass) + NULL, NULL, NULL, + G_TYPE_NONE, 0); + ++ /** ++ * ClutterStage::paint-view: ++ * @stage: the stage that received the event ++ * @view: a #ClutterStageView ++ * ++ * The ::paint-view signal is emitted before a #ClutterStageView is being ++ * painted. ++ * ++ * The view is painted in the default handler. Hence, if you want to perform ++ * some action after the view is painted, like reading the contents of the ++ * framebuffer, use g_signal_connect_after() or pass %G_CONNECT_AFTER. ++ */ ++ stage_signals[PAINT_VIEW] = ++ g_signal_new (I_("paint-view"), ++ G_TYPE_FROM_CLASS (gobject_class), ++ G_SIGNAL_RUN_LAST, ++ G_STRUCT_OFFSET (ClutterStageClass, paint_view), ++ NULL, NULL, ++ _clutter_marshal_VOID__OBJECT, ++ G_TYPE_NONE, 1, ++ CLUTTER_TYPE_STAGE_VIEW); ++ + /** + * ClutterStage::presented: (skip) + * @stage: the stage that received the event +diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h +index 9d0fdd362..9da63d211 100644 +--- a/clutter/clutter/clutter-stage.h ++++ b/clutter/clutter/clutter-stage.h +@@ -88,9 +88,12 @@ struct _ClutterStageClass + gboolean (* delete_event) (ClutterStage *stage, + ClutterEvent *event); + ++ void (* paint_view) (ClutterStage *stage, ++ ClutterStageView *view); ++ + /*< private >*/ + /* padding for future expansion */ +- gpointer _padding_dummy[31]; ++ gpointer _padding_dummy[30]; + }; + + /** +-- +2.26.2 + + +From 2da9db1546f025aa02e23136b40e96a8ba99d1c5 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 23:32:00 -0300 +Subject: [PATCH 07/49] clutter/tests: Connect to ClutterStage:paint-view + +ClutterStage:after-paint now does not guarantee a valid +implicit framebuffer pushed to the stack. Instead, use +the new 'paint-view' signal, that is emitted at a point +in the drawing routine where a framebuffer is pushed. + +In addition to that, stop using the implicit framebuffer +API and port the actor-shader-effect test to read from +the view's framebuffer directly. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + clutter/tests/conform/actor-shader-effect.c | 32 ++++++++++++--------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/clutter/tests/conform/actor-shader-effect.c b/clutter/tests/conform/actor-shader-effect.c +index 93a43ea8b..ac99c5b40 100644 +--- a/clutter/tests/conform/actor-shader-effect.c ++++ b/clutter/tests/conform/actor-shader-effect.c +@@ -209,14 +209,16 @@ make_actor (GType shader_type) + } + + static guint32 +-get_pixel (int x, int y) ++get_pixel (CoglFramebuffer *fb, ++ int x, ++ int y) + { + guint8 data[4]; + +- cogl_read_pixels (x, y, 1, 1, +- COGL_READ_PIXELS_COLOR_BUFFER, +- COGL_PIXEL_FORMAT_RGBA_8888_PRE, +- data); ++ cogl_framebuffer_read_pixels (fb, ++ x, y, 1, 1, ++ COGL_PIXEL_FORMAT_RGBA_8888_PRE, ++ data); + + return (((guint32) data[0] << 16) | + ((guint32) data[1] << 8) | +@@ -224,19 +226,21 @@ get_pixel (int x, int y) + } + + static void +-paint_cb (ClutterStage *stage, +- gpointer data) ++view_painted_cb (ClutterStage *stage, ++ ClutterStageView *view, ++ gpointer data) + { ++ CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view); + gboolean *was_painted = data; + + /* old shader effect */ +- g_assert_cmpint (get_pixel (0, 25), ==, 0xff0000); ++ g_assert_cmpint (get_pixel (fb, 0, 25), ==, 0xff0000); + /* new shader effect */ +- g_assert_cmpint (get_pixel (100, 25), ==, 0x00ffff); ++ g_assert_cmpint (get_pixel (fb, 100, 25), ==, 0x00ffff); + /* another new shader effect */ +- g_assert_cmpint (get_pixel (200, 25), ==, 0xff00ff); ++ g_assert_cmpint (get_pixel (fb, 200, 25), ==, 0xff00ff); + /* new shader effect */ +- g_assert_cmpint (get_pixel (300, 25), ==, 0x00ffff); ++ g_assert_cmpint (get_pixel (fb, 300, 25), ==, 0x00ffff); + + *was_painted = TRUE; + } +@@ -271,9 +275,9 @@ actor_shader_effect (void) + clutter_actor_show (stage); + + was_painted = FALSE; +- g_signal_connect (stage, "after-paint", +- G_CALLBACK (paint_cb), +- &was_painted); ++ g_signal_connect_after (stage, "paint-view", ++ G_CALLBACK (view_painted_cb), ++ &was_painted); + + while (!was_painted) + g_main_context_iteration (NULL, FALSE); +-- +2.26.2 + + +From 50271dfbdbb8926474a5cf3019c8552afd40f0da Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 21:43:05 -0300 +Subject: [PATCH 08/49] stage: Introduce MetaStageWatch and family + +MetaStageWatch, watch modes and the watch function are part +of the new stage view watching API. It's design does not +rely on signals on purpose; the number of signals that would +be emitted would be too high, and would impact performance. + +MetaStageWatch is an opaque structure outside of MetaStage. + +This will be used by the screencast code to monitor a single +view, which has a one-to-one relatioship to logical monitors. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + src/backends/meta-stage-private.h | 22 +++++++ + src/backends/meta-stage.c | 104 ++++++++++++++++++++++++++++++ + 2 files changed, 126 insertions(+) + +diff --git a/src/backends/meta-stage-private.h b/src/backends/meta-stage-private.h +index 639d2372c..963017688 100644 +--- a/src/backends/meta-stage-private.h ++++ b/src/backends/meta-stage-private.h +@@ -27,8 +27,21 @@ + + G_BEGIN_DECLS + ++typedef struct _MetaStageWatch MetaStageWatch; + typedef struct _MetaOverlay MetaOverlay; + ++typedef enum ++{ ++ META_STAGE_WATCH_BEFORE_PAINT, ++ META_STAGE_WATCH_AFTER_ACTOR_PAINT, ++ META_STAGE_WATCH_AFTER_OVERLAY_PAINT, ++ META_STAGE_WATCH_AFTER_PAINT, ++} MetaStageWatchPhase; ++ ++typedef void (* MetaStageWatchFunc) (MetaStage *stage, ++ ClutterStageView *view, ++ gpointer user_data); ++ + ClutterActor *meta_stage_new (MetaBackend *backend); + + MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage); +@@ -43,6 +56,15 @@ void meta_stage_update_cursor_overlay (MetaStage *stage, + void meta_stage_set_active (MetaStage *stage, + gboolean is_active); + ++MetaStageWatch * meta_stage_watch_view (MetaStage *stage, ++ ClutterStageView *view, ++ MetaStageWatchPhase watch_mode, ++ MetaStageWatchFunc callback, ++ gpointer user_data); ++ ++void meta_stage_remove_watch (MetaStage *stage, ++ MetaStageWatch *watch); ++ + G_END_DECLS + + #endif /* META_STAGE_PRIVATE_H */ +diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c +index 47a00e51a..8809035d1 100644 +--- a/src/backends/meta-stage.c ++++ b/src/backends/meta-stage.c +@@ -30,6 +30,8 @@ + #include "meta/meta-monitor-manager.h" + #include "meta/util.h" + ++#define N_WATCH_MODES 4 ++ + enum + { + ACTORS_PAINTED, +@@ -39,6 +41,13 @@ enum + + static guint signals[N_SIGNALS]; + ++struct _MetaStageWatch ++{ ++ ClutterStageView *view; ++ MetaStageWatchFunc callback; ++ gpointer user_data; ++}; ++ + struct _MetaOverlay + { + gboolean enabled; +@@ -55,6 +64,9 @@ struct _MetaStage + { + ClutterStage parent; + ++ GPtrArray *watchers[N_WATCH_MODES]; ++ ClutterStageView *current_view; ++ + GList *overlays; + gboolean is_active; + }; +@@ -135,6 +147,7 @@ meta_stage_finalize (GObject *object) + { + MetaStage *stage = META_STAGE (object); + GList *l; ++ int i; + + l = stage->overlays; + while (l) +@@ -143,9 +156,33 @@ meta_stage_finalize (GObject *object) + l = g_list_delete_link (l, l); + } + ++ for (i = 0; i < N_WATCH_MODES; i++) ++ g_clear_pointer (&stage->watchers[i], g_ptr_array_unref); ++ + G_OBJECT_CLASS (meta_stage_parent_class)->finalize (object); + } + ++static void ++notify_watchers_for_mode (MetaStage *stage, ++ ClutterStageView *view, ++ MetaStageWatchPhase watch_phase) ++{ ++ GPtrArray *watchers; ++ int i; ++ ++ watchers = stage->watchers[watch_phase]; ++ ++ for (i = 0; i < watchers->len; i++) ++ { ++ MetaStageWatch *watch = g_ptr_array_index (watchers, i); ++ ++ if (watch->view && view != watch->view) ++ continue; ++ ++ watch->callback (stage, view, watch->user_data); ++ } ++} ++ + static void + meta_stage_paint (ClutterActor *actor) + { +@@ -154,10 +191,30 @@ meta_stage_paint (ClutterActor *actor) + + CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor); + ++ notify_watchers_for_mode (stage, stage->current_view, ++ META_STAGE_WATCH_AFTER_ACTOR_PAINT); ++ + g_signal_emit (stage, signals[ACTORS_PAINTED], 0); + + for (l = stage->overlays; l; l = l->next) + meta_overlay_paint (l->data); ++ ++ notify_watchers_for_mode (stage, stage->current_view, ++ META_STAGE_WATCH_AFTER_OVERLAY_PAINT); ++} ++ ++static void ++meta_stage_paint_view (ClutterStage *stage, ++ ClutterStageView *view) ++{ ++ MetaStage *meta_stage = META_STAGE (stage); ++ ++ notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_BEFORE_PAINT); ++ ++ meta_stage->current_view = view; ++ CLUTTER_STAGE_CLASS (meta_stage_parent_class)->paint_view (stage, view); ++ ++ notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_AFTER_PAINT); + } + + static void +@@ -202,6 +259,7 @@ meta_stage_class_init (MetaStageClass *klass) + + stage_class->activate = meta_stage_activate; + stage_class->deactivate = meta_stage_deactivate; ++ stage_class->paint_view = meta_stage_paint_view; + + signals[ACTORS_PAINTED] = g_signal_new ("actors-painted", + G_TYPE_FROM_CLASS (klass), +@@ -214,7 +272,12 @@ meta_stage_class_init (MetaStageClass *klass) + static void + meta_stage_init (MetaStage *stage) + { ++ int i; ++ + clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE); ++ ++ for (i = 0; i < N_WATCH_MODES; i++) ++ stage->watchers[i] = g_ptr_array_new_with_free_func (g_free); + } + + ClutterActor * +@@ -346,3 +409,44 @@ meta_stage_set_active (MetaStage *stage, + */ + clutter_stage_event (CLUTTER_STAGE (stage), &event); + } ++ ++MetaStageWatch * ++meta_stage_watch_view (MetaStage *stage, ++ ClutterStageView *view, ++ MetaStageWatchPhase watch_phase, ++ MetaStageWatchFunc callback, ++ gpointer user_data) ++{ ++ MetaStageWatch *watch; ++ GPtrArray *watchers; ++ ++ watch = g_new0 (MetaStageWatch, 1); ++ watch->view = view; ++ watch->callback = callback; ++ watch->user_data = user_data; ++ ++ watchers = stage->watchers[watch_phase]; ++ g_ptr_array_add (watchers, watch); ++ ++ return watch; ++} ++ ++void ++meta_stage_remove_watch (MetaStage *stage, ++ MetaStageWatch *watch) ++{ ++ GPtrArray *watchers; ++ gboolean removed = FALSE; ++ int i; ++ ++ for (i = 0; i < N_WATCH_MODES; i++) ++ { ++ watchers = stage->watchers[i]; ++ removed = g_ptr_array_remove_fast (watchers, watch); ++ ++ if (removed) ++ break; ++ } ++ ++ g_assert (removed); ++} +-- +2.26.2 + + +From 8c509454f193945f09ef7afb5a397df266d2fffd Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 17 Jun 2019 21:49:45 -0300 +Subject: [PATCH 09/49] screen-cast-monitor-stream-src: Watch monitors using + MetaStageWatch + +This uses the API introduced by the previous commit. By watching specific +monitors directly, and not whole stage views, we avoid showing artifacts +on multi-monitor setups. + +Fixes https://gitlab.gnome.org/GNOME/mutter/issues/424 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/623 +--- + .../meta-screen-cast-monitor-stream-src.c | 65 +++++++++++++------ + 1 file changed, 44 insertions(+), 21 deletions(-) + +diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c +index cb9823148..f582217e5 100644 +--- a/src/backends/meta-screen-cast-monitor-stream-src.c ++++ b/src/backends/meta-screen-cast-monitor-stream-src.c +@@ -32,6 +32,7 @@ + #include "backends/meta-monitor.h" + #include "backends/meta-screen-cast-monitor-stream.h" + #include "backends/meta-screen-cast-session.h" ++#include "backends/meta-stage-private.h" + #include "clutter/clutter.h" + #include "clutter/clutter-mutter.h" + #include "core/boxes-private.h" +@@ -42,8 +43,9 @@ struct _MetaScreenCastMonitorStreamSrc + + gboolean cursor_bitmap_invalid; + +- gulong actors_painted_handler_id; +- gulong paint_handler_id; ++ MetaStageWatch *paint_watch; ++ MetaStageWatch *after_paint_watch; ++ + gulong cursor_moved_handler_id; + gulong cursor_changed_handler_id; + }; +@@ -113,10 +115,11 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src, + } + + static void +-stage_painted (ClutterActor *actor, +- MetaScreenCastMonitorStreamSrc *monitor_src) ++stage_painted (MetaStage *stage, ++ ClutterStageView *view, ++ gpointer user_data) + { +- MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src); ++ MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data); + + meta_screen_cast_stream_src_maybe_record_frame (src); + } +@@ -245,12 +248,28 @@ meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) + MetaScreenCastMonitorStreamSrc *monitor_src = + META_SCREEN_CAST_MONITOR_STREAM_SRC (src); + MetaBackend *backend = get_backend (monitor_src); ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); ++ MetaRendererView *view; ++ MetaMonitor *monitor; ++ MetaLogicalMonitor *logical_monitor; ++ MetaStage *meta_stage; ++ ClutterStageView *stage_view; + ClutterStage *stage; + MetaScreenCastStream *stream; + + stream = meta_screen_cast_stream_src_get_stream (src); + stage = get_stage (monitor_src); ++ meta_stage = META_STAGE (stage); ++ monitor = get_monitor (monitor_src); ++ logical_monitor = meta_monitor_get_logical_monitor (monitor); ++ view = meta_renderer_get_view_from_logical_monitor (renderer, ++ logical_monitor); ++ ++ if (view) ++ stage_view = CLUTTER_STAGE_VIEW (view); ++ else ++ stage_view = NULL; + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { +@@ -265,17 +284,21 @@ meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) + monitor_src); + /* Intentional fall-through */ + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: +- monitor_src->actors_painted_handler_id = +- g_signal_connect (stage, "actors-painted", +- G_CALLBACK (stage_painted), +- monitor_src); ++ monitor_src->paint_watch = ++ meta_stage_watch_view (meta_stage, ++ stage_view, ++ META_STAGE_WATCH_AFTER_ACTOR_PAINT, ++ stage_painted, ++ monitor_src); + break; + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + inhibit_hw_cursor (monitor_src); +- monitor_src->paint_handler_id = +- g_signal_connect_after (stage, "paint", +- G_CALLBACK (stage_painted), +- monitor_src); ++ monitor_src->after_paint_watch = ++ meta_stage_watch_view (meta_stage, ++ stage_view, ++ META_STAGE_WATCH_AFTER_PAINT, ++ stage_painted, ++ monitor_src); + break; + } + +@@ -290,21 +313,21 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src) + MetaBackend *backend = get_backend (monitor_src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + ClutterStage *stage; ++ MetaStage *meta_stage; + + stage = get_stage (monitor_src); ++ meta_stage = META_STAGE (stage); + +- if (monitor_src->actors_painted_handler_id) ++ if (monitor_src->paint_watch) + { +- g_signal_handler_disconnect (stage, +- monitor_src->actors_painted_handler_id); +- monitor_src->actors_painted_handler_id = 0; ++ meta_stage_remove_watch (meta_stage, monitor_src->paint_watch); ++ monitor_src->paint_watch = NULL; + } + +- if (monitor_src->paint_handler_id) ++ if (monitor_src->after_paint_watch) + { +- g_signal_handler_disconnect (stage, +- monitor_src->paint_handler_id); +- monitor_src->paint_handler_id = 0; ++ meta_stage_remove_watch (meta_stage, monitor_src->after_paint_watch); ++ monitor_src->after_paint_watch = NULL; + uninhibit_hw_cursor (monitor_src); + } + +-- +2.26.2 + + +From 547e3f004f9d9235efc5dfd816f4a1214cf44616 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 26 Aug 2019 16:09:53 +0300 +Subject: [PATCH 10/49] window-actor: Add 'damaged' signal + +Make it possible to listen for damage on a window actor. For X11, the +signal is emitted when damage is reported; for Wayland, it is emitted +when any of the surfaces associated with the window is damaged. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/752 +--- + src/compositor/meta-window-actor-private.h | 2 ++ + src/compositor/meta-window-actor.c | 23 ++++++++++++++++++ + src/wayland/meta-wayland-surface.c | 27 +++++++++++++++++++--- + 3 files changed, 49 insertions(+), 3 deletions(-) + +diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h +index 9c1c12d09..3df520ac5 100644 +--- a/src/compositor/meta-window-actor-private.h ++++ b/src/compositor/meta-window-actor-private.h +@@ -81,4 +81,6 @@ void meta_window_actor_stereo_notify (MetaWindowActor *actor, + + gboolean meta_window_actor_is_stereo (MetaWindowActor *actor); + ++void meta_window_actor_notify_damaged (MetaWindowActor *window_actor); ++ + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 11686d00b..f4eba6d42 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -116,6 +116,7 @@ enum + { + FIRST_FRAME, + EFFECTS_COMPLETED, ++ DAMAGED, + + LAST_SIGNAL + }; +@@ -226,6 +227,20 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) + NULL, NULL, NULL, + G_TYPE_NONE, 0); + ++ /** ++ * MetaWindowActor::damaged: ++ * @actor: the #MetaWindowActor instance ++ * ++ * Notify that one or more of the surfaces of the window have been damaged. ++ */ ++ signals[DAMAGED] = ++ g_signal_new ("damaged", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_LAST, ++ 0, ++ NULL, NULL, NULL, ++ G_TYPE_NONE, 0); ++ + pspec = g_param_spec_object ("meta-window", + "MetaWindow", + "The displayed MetaWindow", +@@ -1445,6 +1460,8 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self, + event->area.y, + event->area.width, + event->area.height); ++ ++ meta_window_actor_notify_damaged (self); + } + + void +@@ -2053,3 +2070,9 @@ meta_window_actor_is_stereo (MetaWindowActor *self) + else + return FALSE; + } ++ ++void ++meta_window_actor_notify_damaged (MetaWindowActor *window_actor) ++{ ++ g_signal_emit (window_actor, signals[DAMAGED], 0); ++} +diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c +index ddad1a45c..6ffcd6a7f 100644 +--- a/src/wayland/meta-wayland-surface.c ++++ b/src/wayland/meta-wayland-surface.c +@@ -669,6 +669,8 @@ void + meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, + MetaWaylandPendingState *pending) + { ++ gboolean had_damage = FALSE; ++ + if (surface->role) + { + meta_wayland_surface_role_pre_commit (surface->role, pending); +@@ -771,9 +773,12 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, + + if (!cairo_region_is_empty (pending->surface_damage) || + !cairo_region_is_empty (pending->buffer_damage)) +- surface_process_damage (surface, +- pending->surface_damage, +- pending->buffer_damage); ++ { ++ surface_process_damage (surface, ++ pending->surface_damage, ++ pending->buffer_damage); ++ had_damage = TRUE; ++ } + + surface->offset_x += pending->dx; + surface->offset_y += pending->dy; +@@ -834,6 +839,22 @@ cleanup: + pending_state_reset (pending); + + g_list_foreach (surface->subsurfaces, parent_surface_state_applied, NULL); ++ ++ if (had_damage) ++ { ++ MetaWindow *toplevel_window; ++ ++ toplevel_window = meta_wayland_surface_get_toplevel_window (surface); ++ if (toplevel_window) ++ { ++ MetaWindowActor *toplevel_window_actor; ++ ++ toplevel_window_actor = ++ meta_window_actor_from_window (toplevel_window); ++ if (toplevel_window_actor) ++ meta_window_actor_notify_damaged (toplevel_window_actor); ++ } ++ } + } + + static void +-- +2.26.2 + + +From 27ada1ee57ac85d77cea9a1aee71b77f4939439f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 26 Aug 2019 16:12:30 +0300 +Subject: [PATCH 11/49] screen-cast/window: Use window actor damaged signal + instead of paint + +We are really more interested in when a window is damaged, rather than +when it's painted, for screen casting windows. This also has the benefit +of not listening on the "paint" signal of the actor, meaning it'll open +doors for hacks currently necessary for taking a screenshot of a window +consisting of multiple surfaces. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/752 +--- + .../meta-screen-cast-window-stream-src.c | 45 +++++-------------- + 1 file changed, 11 insertions(+), 34 deletions(-) + +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index dbf330420..c31830b03 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -34,13 +34,11 @@ struct _MetaScreenCastWindowStreamSrc + + MetaScreenCastWindow *screen_cast_window; + +- unsigned long screen_cast_window_before_paint_handler_id; +- unsigned long screen_cast_window_after_paint_handler_id; ++ unsigned long screen_cast_window_damaged_handler_id; + unsigned long screen_cast_window_destroyed_handler_id; + unsigned long cursor_moved_handler_id; + unsigned long cursor_changed_handler_id; + +- gboolean actor_was_dirty; + gboolean cursor_bitmap_invalid; + }; + +@@ -255,15 +253,10 @@ meta_screen_cast_window_stream_src_stop (MetaScreenCastWindowStreamSrc *window_s + if (!window_src->screen_cast_window) + return; + +- if (window_src->screen_cast_window_before_paint_handler_id) ++ if (window_src->screen_cast_window_damaged_handler_id) + g_signal_handler_disconnect (window_src->screen_cast_window, +- window_src->screen_cast_window_before_paint_handler_id); +- window_src->screen_cast_window_before_paint_handler_id = 0; +- +- if (window_src->screen_cast_window_after_paint_handler_id) +- g_signal_handler_disconnect (window_src->screen_cast_window, +- window_src->screen_cast_window_after_paint_handler_id); +- window_src->screen_cast_window_after_paint_handler_id = 0; ++ window_src->screen_cast_window_damaged_handler_id); ++ window_src->screen_cast_window_damaged_handler_id = 0; + + if (window_src->screen_cast_window_destroyed_handler_id) + g_signal_handler_disconnect (window_src->screen_cast_window, +@@ -282,23 +275,12 @@ meta_screen_cast_window_stream_src_stop (MetaScreenCastWindowStreamSrc *window_s + } + + static void +-screen_cast_window_before_paint (MetaScreenCastWindow *screen_cast_window, +- MetaScreenCastWindowStreamSrc *window_src) +-{ +- window_src->actor_was_dirty = +- meta_screen_cast_window_has_damage (screen_cast_window); +-} +- +-static void +-screen_cast_window_after_paint (MetaWindowActor *actor, +- MetaScreenCastWindowStreamSrc *window_src) ++screen_cast_window_damaged (MetaWindowActor *actor, ++ MetaScreenCastWindowStreamSrc *window_src) + { +- if (window_src->actor_was_dirty) +- { +- MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); ++ MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); + +- meta_screen_cast_stream_src_maybe_record_frame (src); +- } ++ meta_screen_cast_stream_src_maybe_record_frame (src); + } + + static void +@@ -378,16 +360,11 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src) + + window_src->screen_cast_window = META_SCREEN_CAST_WINDOW (window_actor); + +- window_src->screen_cast_window_before_paint_handler_id = ++ window_src->screen_cast_window_damaged_handler_id = + g_signal_connect (window_src->screen_cast_window, +- "paint", +- G_CALLBACK (screen_cast_window_before_paint), ++ "damaged", ++ G_CALLBACK (screen_cast_window_damaged), + window_src); +- window_src->screen_cast_window_after_paint_handler_id = +- g_signal_connect_after (window_src->screen_cast_window, +- "paint", +- G_CALLBACK (screen_cast_window_after_paint), +- window_src); + + window_src->screen_cast_window_destroyed_handler_id = + g_signal_connect (window_src->screen_cast_window, +-- +2.26.2 + + +From 2bf9b015901aa58826ebf96d941f9dbf803ec6b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 26 Aug 2019 16:29:33 +0300 +Subject: [PATCH 12/49] window-actor: Add API to get a cairo surface of the + window + +This currently uses a hack where it pushes a CoglFramebuffer backed by a +texture to the framebuffer stack, then calls clutter_actor_paint() on +the window actor causing it to render into the framebuffer. This has the +effect that all subsurfaces of a window will be drawn as part of the +window. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/752 +--- + src/compositor/meta-window-actor.c | 113 +++++++++++++++++++++++++++++ + src/meta/meta-window-actor.h | 4 + + 2 files changed, 117 insertions(+) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index f4eba6d42..9d215c745 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2076,3 +2076,116 @@ meta_window_actor_notify_damaged (MetaWindowActor *window_actor) + { + g_signal_emit (window_actor, signals[DAMAGED], 0); + } ++ ++cairo_surface_t * ++meta_window_actor_get_image (MetaWindowActor *self, ++ MetaRectangle *clip) ++{ ++ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); ++ ClutterActor *actor = CLUTTER_ACTOR (self); ++ MetaBackend *backend = meta_get_backend (); ++ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_backend); ++ float resource_scale; ++ float width, height; ++ CoglTexture2D *texture; ++ g_autoptr (GError) error = NULL; ++ CoglOffscreen *offscreen; ++ CoglFramebuffer *framebuffer; ++ CoglColor clear_color; ++ float x, y; ++ MetaRectangle scaled_clip; ++ cairo_surface_t *surface; ++ ++ if (!priv->surface) ++ return NULL; ++ ++ if (clutter_actor_get_n_children (actor) == 1) ++ { ++ MetaShapedTexture *stex; ++ ++ stex = meta_surface_actor_get_texture (priv->surface); ++ return meta_shaped_texture_get_image (stex, clip); ++ } ++ ++ clutter_actor_get_size (actor, &width, &height); ++ ++ if (width == 0 || height == 0) ++ return NULL; ++ ++ if (!clutter_actor_get_resource_scale (actor, &resource_scale)) ++ return NULL; ++ ++ width = ceilf (width * resource_scale); ++ height = ceilf (height * resource_scale); ++ ++ texture = cogl_texture_2d_new_with_size (cogl_context, width, height); ++ if (!texture) ++ return NULL; ++ ++ cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture), ++ FALSE); ++ ++ offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture)); ++ framebuffer = COGL_FRAMEBUFFER (offscreen); ++ ++ cogl_object_unref (texture); ++ ++ if (!cogl_framebuffer_allocate (framebuffer, &error)) ++ { ++ g_warning ("Failed to allocate framebuffer for screenshot: %s", ++ error->message); ++ cogl_object_unref (framebuffer); ++ cogl_object_unref (texture); ++ return NULL; ++ } ++ ++ cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); ++ clutter_actor_get_position (actor, &x, &y); ++ ++ cogl_push_framebuffer (framebuffer); ++ ++ cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); ++ cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); ++ cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); ++ cogl_framebuffer_translate (framebuffer, -x, -y, 0); ++ ++ clutter_actor_paint (actor); ++ ++ cogl_pop_framebuffer (); ++ ++ if (clip) ++ { ++ meta_rectangle_scale_double (clip, resource_scale, ++ META_ROUNDING_STRATEGY_GROW, ++ &scaled_clip); ++ meta_rectangle_intersect (&scaled_clip, ++ &(MetaRectangle) { ++ .width = width, ++ .height = height, ++ }, ++ &scaled_clip); ++ } ++ else ++ { ++ scaled_clip = (MetaRectangle) { ++ .width = width, ++ .height = height, ++ }; ++ } ++ ++ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ++ scaled_clip.width, scaled_clip.height); ++ cogl_framebuffer_read_pixels (framebuffer, ++ scaled_clip.x, scaled_clip.y, ++ scaled_clip.width, scaled_clip.height, ++ CLUTTER_CAIRO_FORMAT_ARGB32, ++ cairo_image_surface_get_data (surface)); ++ ++ cogl_object_unref (framebuffer); ++ ++ cairo_surface_mark_dirty (surface); ++ ++ return surface; ++} +diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h +index 9ba164910..30a17c56b 100644 +--- a/src/meta/meta-window-actor.h ++++ b/src/meta/meta-window-actor.h +@@ -46,6 +46,10 @@ void meta_window_actor_sync_visibility (MetaWindowActor *self + META_EXPORT + gboolean meta_window_actor_is_destroyed (MetaWindowActor *self); + ++META_EXPORT ++cairo_surface_t * meta_window_actor_get_image (MetaWindowActor *self, ++ cairo_rectangle_int_t *clip); ++ + typedef enum + { + META_SHADOW_MODE_AUTO, +-- +2.26.2 + + +From 2aea9fb5c0b37f764911654e90d7d1917bf3aa0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 26 Aug 2019 16:31:06 +0300 +Subject: [PATCH 13/49] window-actor: Use new get_image() API to screen casting + window content + +This fixes screen casting of windows consisting of multiple surfaces to +work. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/752 +--- + src/compositor/meta-window-actor.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 9d215c745..b82326600 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -1985,8 +1985,6 @@ meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, + uint8_t *data) + { + MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); +- MetaWindowActorPrivate *priv = +- meta_window_actor_get_instance_private (window_actor); + cairo_surface_t *image; + uint8_t *cr_data; + int cr_stride; +@@ -1997,7 +1995,7 @@ meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, + if (meta_window_actor_is_destroyed (window_actor)) + return; + +- image = meta_surface_actor_get_image (priv->surface, bounds); ++ image = meta_window_actor_get_image (window_actor, bounds); + cr_data = cairo_image_surface_get_data (image); + cr_width = cairo_image_surface_get_width (image); + cr_height = cairo_image_surface_get_height (image); +-- +2.26.2 + + +From 6edebf1a7beed7162f9a69270338010a77088b75 Mon Sep 17 00:00:00 2001 +From: Pascal Nowack +Date: Mon, 16 Dec 2019 19:00:19 +0100 +Subject: [PATCH 14/49] screen-cast: Fix window recording on HiDPI + +Using the same scale for the window as the +logical monitor only works correctly when having +the experimental 'scale-monitor-framebuffer' +feature enabled. +Without this experimental feature, the stream +will contain a black screen, where the actual +window only takes a small part of it. + +Therefore, use a scale of 1 for the non- +experimental case. + +Patch is based on commit 3fa6a92cc5dda6ab3939c3e982185f6caf453360. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/976 +--- + src/backends/meta-screen-cast-window-stream.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c +index 50d1806cd..b9a732cba 100644 +--- a/src/backends/meta-screen-cast-window-stream.c ++++ b/src/backends/meta-screen-cast-window-stream.c +@@ -226,11 +226,15 @@ meta_screen_cast_window_stream_initable_init (GInitable *initable, + G_CALLBACK (on_window_unmanaged), + window_stream); + ++ if (meta_is_stage_views_scaled ()) ++ scale = (int) ceilf (meta_logical_monitor_get_scale (logical_monitor)); ++ else ++ scale = 1; ++ + /* We cannot set the stream size to the exact size of the window, because + * windows can be resized, whereas streams cannot. + * So we set a size equals to the size of the logical monitor for the window. + */ +- scale = (int) ceil (meta_logical_monitor_get_scale (logical_monitor)); + window_stream->logical_width = logical_monitor->rect.width; + window_stream->logical_height = logical_monitor->rect.height; + window_stream->stream_width = logical_monitor->rect.width * scale; +-- +2.26.2 + + +From 077217b337f18619d3b3b878c5faae488cbafd15 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 4 Feb 2020 14:58:30 +0100 +Subject: [PATCH 15/49] window-actor: Ensure clipping in `capture_into()` + +The clip bounds passed in `meta_window_actor_capture_into()` represent +the actual allocated buffer size where the window actor image will be +eventually copied. + +As such, it is completely agnostic to the scaling factors that might +affect the different surface actors which compose the window actor. + +So instead of trying to compute the scale factor by which the given +clipping bounds need to be adjusted, simply clip the resulting image +based on the given bounds to make sure we never overflow the destination +buffer. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1022 +--- + src/compositor/meta-window-actor.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index b82326600..6d4aa6c1b 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2001,32 +2001,36 @@ meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, + cr_height = cairo_image_surface_get_height (image); + cr_stride = cairo_image_surface_get_stride (image); + +- if (cr_width < bounds->width || cr_height < bounds->height) ++ if (cr_width == bounds->width && cr_height == bounds->height) + { ++ memcpy (data, cr_data, cr_height * cr_stride); ++ } ++ else ++ { ++ int width = MIN (bounds->width, cr_width); ++ int height = MIN (bounds->height, cr_height); ++ int stride = width * bpp; + uint8_t *src, *dst; ++ + src = cr_data; + dst = data; + +- for (int i = 0; i < cr_height; i++) ++ for (int i = 0; i < height; i++) + { +- memcpy (dst, src, cr_stride); +- if (cr_width < bounds->width) +- memset (dst + cr_stride, 0, (bounds->width * bpp) - cr_stride); ++ memcpy (dst, src, stride); ++ if (width < bounds->width) ++ memset (dst + stride, 0, (bounds->width * bpp) - stride); + + src += cr_stride; + dst += bounds->width * bpp; + } + +- for (int i = cr_height; i < bounds->height; i++) ++ for (int i = height; i < bounds->height; i++) + { + memset (dst, 0, bounds->width * bpp); + dst += bounds->width * bpp; + } + } +- else +- { +- memcpy (data, cr_data, cr_height * cr_stride); +- } + + cairo_surface_destroy (image); + } +-- +2.26.2 + + +From 06dcbe104c58e1efd1d99fc7d4761698f9d32824 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 3 Feb 2020 14:18:57 +0100 +Subject: [PATCH 16/49] shaped-texture: Add `get_width()`/`get_height()` API + +Add an API to retrieve the content size of a shaped texture. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1022 +--- + src/compositor/meta-shaped-texture-private.h | 3 +++ + src/compositor/meta-shaped-texture.c | 20 ++++++++++++++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h +index d0efdd4dc..362bbb93f 100644 +--- a/src/compositor/meta-shaped-texture-private.h ++++ b/src/compositor/meta-shaped-texture-private.h +@@ -53,4 +53,7 @@ void meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex, + int dst_height); + void meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex); + ++int meta_shaped_texture_get_width (MetaShapedTexture *stex); ++int meta_shaped_texture_get_height (MetaShapedTexture *stex); ++ + #endif +diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c +index e77a32109..6ef2125c3 100644 +--- a/src/compositor/meta-shaped-texture.c ++++ b/src/compositor/meta-shaped-texture.c +@@ -1585,3 +1585,23 @@ meta_shaped_texture_new (void) + { + return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL); + } ++ ++int ++meta_shaped_texture_get_width (MetaShapedTexture *stex) ++{ ++ g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0); ++ ++ ensure_size_valid (stex); ++ ++ return stex->dst_width; ++} ++ ++int ++meta_shaped_texture_get_height (MetaShapedTexture *stex) ++{ ++ g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0); ++ ++ ensure_size_valid (stex); ++ ++ return stex->dst_height; ++} +-- +2.26.2 + + +From 9a9a4466e79d61996304ca0c3e9b327c9b3abc25 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 28 Jan 2020 11:13:41 +0100 +Subject: [PATCH 17/49] screen-cast-window: Use buffer bounds in place of frame + bounds + +The frame bounds as returned by `meta_window_actor_get_frame_bounds()` +would be used as cropping values when streaming a window content. + +But, as its name implies, it returns the actual frame bounds, whereas we +may want to include the whole buffer, to include client side shadows for +example. + +Rename the `get_frame_bounds()` API to `get_buffer_bounds()` (which was +previously partly removed with commit 11bd84789) and return the actual +buffer bounds to use as the cropping area when streaming a window. + +Fixes: 931934511 - "Implement MetaScreenCastWindow interface" +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1022 +Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1018 +--- + .../meta-screen-cast-window-stream-src.c | 4 +-- + src/backends/meta-screen-cast-window.c | 8 +++--- + src/backends/meta-screen-cast-window.h | 8 +++--- + src/compositor/meta-window-actor.c | 26 ++++++------------- + 4 files changed, 18 insertions(+), 28 deletions(-) + +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index c31830b03..210ea0807 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -230,8 +230,8 @@ meta_screen_cast_window_stream_src_get_videocrop (MetaScreenCastStreamSrc *src, + META_SCREEN_CAST_WINDOW_STREAM_SRC (src); + MetaRectangle stream_rect; + +- meta_screen_cast_window_get_frame_bounds (window_src->screen_cast_window, +- crop_rect); ++ meta_screen_cast_window_get_buffer_bounds (window_src->screen_cast_window, ++ crop_rect); + + stream_rect.x = 0; + stream_rect.y = 0; +diff --git a/src/backends/meta-screen-cast-window.c b/src/backends/meta-screen-cast-window.c +index ce2bf82c9..91515ded8 100644 +--- a/src/backends/meta-screen-cast-window.c ++++ b/src/backends/meta-screen-cast-window.c +@@ -30,11 +30,11 @@ meta_screen_cast_window_default_init (MetaScreenCastWindowInterface *iface) + } + + void +-meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, +- MetaRectangle *bounds) ++meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds) + { +- META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->get_frame_bounds (screen_cast_window, +- bounds); ++ META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->get_buffer_bounds (screen_cast_window, ++ bounds); + } + + void +diff --git a/src/backends/meta-screen-cast-window.h b/src/backends/meta-screen-cast-window.h +index badd88224..69e5a34dc 100644 +--- a/src/backends/meta-screen-cast-window.h ++++ b/src/backends/meta-screen-cast-window.h +@@ -37,8 +37,8 @@ struct _MetaScreenCastWindowInterface + { + GTypeInterface parent_iface; + +- void (*get_frame_bounds) (MetaScreenCastWindow *screen_cast_window, +- MetaRectangle *bounds); ++ void (*get_buffer_bounds) (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds); + + void (*transform_relative_position) (MetaScreenCastWindow *screen_cast_window, + double x, +@@ -59,8 +59,8 @@ struct _MetaScreenCastWindowInterface + gboolean (*has_damage) (MetaScreenCastWindow *screen_cast_window); + }; + +-void meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, +- MetaRectangle *bounds); ++void meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds); + + void meta_screen_cast_window_transform_relative_position (MetaScreenCastWindow *screen_cast_window, + double x, +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 6d4aa6c1b..81eb04c84 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -1877,29 +1877,19 @@ meta_window_actor_from_window (MetaWindow *window) + } + + static void +-meta_window_actor_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, +- MetaRectangle *bounds) ++meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds) + { + MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); + MetaWindowActorPrivate *priv = + meta_window_actor_get_instance_private (window_actor); +- MetaWindow *window; + MetaShapedTexture *stex; +- MetaRectangle buffer_rect; +- MetaRectangle frame_rect; +- double scale_x, scale_y; + + stex = meta_surface_actor_get_texture (priv->surface); +- clutter_actor_get_scale (CLUTTER_ACTOR (stex), &scale_x, &scale_y); +- +- window = priv->window; +- meta_window_get_buffer_rect (window, &buffer_rect); +- meta_window_get_frame_rect (window, &frame_rect); +- +- bounds->x = (int) floor ((frame_rect.x - buffer_rect.x) / scale_x); +- bounds->y = (int) floor ((frame_rect.y - buffer_rect.y) / scale_y); +- bounds->width = (int) ceil (frame_rect.width / scale_x); +- bounds->height = (int) ceil (frame_rect.height / scale_y); ++ *bounds = (MetaRectangle) { ++ .width = meta_shaped_texture_get_width (stex), ++ .height = meta_shaped_texture_get_height (stex) ++ }; + } + + static void +@@ -1917,7 +1907,7 @@ meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast + MetaRectangle bounds; + ClutterVertex v1 = { 0.f, }, v2 = { 0.f, }; + +- meta_window_actor_get_frame_bounds (screen_cast_window, &bounds); ++ meta_window_actor_get_buffer_bounds (screen_cast_window, &bounds); + + v1.x = CLAMP ((float) x, + bounds.x, +@@ -2044,7 +2034,7 @@ meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window) + static void + screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface) + { +- iface->get_frame_bounds = meta_window_actor_get_frame_bounds; ++ iface->get_buffer_bounds = meta_window_actor_get_buffer_bounds; + iface->transform_relative_position = meta_window_actor_transform_relative_position; + iface->transform_cursor_position = meta_window_actor_transform_cursor_position; + iface->capture_into = meta_window_actor_capture_into; +-- +2.26.2 + + +From c6f68fe763e736c5fd84913407427254c5dc7dea Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Tue, 14 Jan 2020 09:44:45 +0100 +Subject: [PATCH 18/49] screen-cast: Update to PipeWire 0.3 API + +Update to 0.3 API + +[jadahl: update Dockerfile to include new enough pipewire] +[jadahl: dropped Dockerfile changes for backport] + +Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/1051 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1062 +--- + meson.build | 4 +- + src/backends/meta-screen-cast-stream-src.c | 255 ++++++++------------- + 2 files changed, 101 insertions(+), 158 deletions(-) + +diff --git a/meson.build b/meson.build +index b2239ed81..8ef592bc5 100644 +--- a/meson.build ++++ b/meson.build +@@ -43,7 +43,7 @@ libinput_req = '>= 1.4' + gbm_req = '>= 10.3' + + # screen cast version requirements +-libpipewire_req = '>= 0.2.5' ++libpipewire_req = '>= 0.3.0' + + gnome = import('gnome') + pkg = import('pkgconfig') +@@ -233,7 +233,7 @@ endif + + have_remote_desktop = get_option('remote_desktop') + if have_remote_desktop +- libpipewire_dep = dependency('libpipewire-0.2', version: libpipewire_req) ++ libpipewire_dep = dependency('libpipewire-0.3', version: libpipewire_req) + endif + + have_introspection = get_option('introspection') +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 82c5cba43..ba1ce94a7 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -62,15 +63,6 @@ enum + + static guint signals[N_SIGNALS]; + +-typedef struct _MetaSpaType +-{ +- struct spa_type_media_type media_type; +- struct spa_type_media_subtype media_subtype; +- struct spa_type_format_video format_video; +- struct spa_type_video_format video_format; +- uint32_t meta_cursor; +-} MetaSpaType; +- + typedef struct _MetaPipeWireSource + { + GSource base; +@@ -82,19 +74,19 @@ typedef struct _MetaScreenCastStreamSrcPrivate + { + MetaScreenCastStream *stream; + ++ struct pw_context *pipewire_context; + struct pw_core *pipewire_core; +- struct pw_remote *pipewire_remote; +- struct pw_type *pipewire_type; + MetaPipeWireSource *pipewire_source; +- struct spa_hook pipewire_remote_listener; ++ struct spa_hook pipewire_core_listener; + + gboolean is_enabled; + + struct pw_stream *pipewire_stream; + struct spa_hook pipewire_stream_listener; ++ uint32_t node_id; + +- MetaSpaType spa_type; + struct spa_video_info_raw video_format; ++ int video_stride; + + uint64_t last_frame_timestamp_us; + +@@ -112,8 +104,6 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastStreamSrc, + meta_screen_cast_stream_src_init_initable_iface) + G_ADD_PRIVATE (MetaScreenCastStreamSrc)) + +-#define PROP_RANGE(min, max) 2, (min), (max) +- + static void + meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src, + int *width, +@@ -286,9 +276,6 @@ meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (MetaScreenCastStre + int x, + int y) + { +- MetaScreenCastStreamSrcPrivate *priv = +- meta_screen_cast_stream_src_get_instance_private (src); +- MetaSpaType *spa_type = &priv->spa_type; + struct spa_meta_bitmap *spa_meta_bitmap; + + spa_meta_cursor->id = 1; +@@ -300,7 +287,7 @@ meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (MetaScreenCastStre + spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, + spa_meta_cursor->bitmap_offset, + struct spa_meta_bitmap); +- spa_meta_bitmap->format = spa_type->video_format.RGBA; ++ spa_meta_bitmap->format = SPA_VIDEO_FORMAT_RGBA; + spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); + + spa_meta_cursor->hotspot.x = 0; +@@ -317,9 +304,6 @@ meta_screen_cast_stream_src_set_cursor_sprite_metadata (MetaScreenCastStreamSrc + int y, + float scale) + { +- MetaScreenCastStreamSrcPrivate *priv = +- meta_screen_cast_stream_src_get_instance_private (src); +- MetaSpaType *spa_type = &priv->spa_type; + CoglTexture *cursor_texture; + struct spa_meta_bitmap *spa_meta_bitmap; + int hotspot_x, hotspot_y; +@@ -346,7 +330,7 @@ meta_screen_cast_stream_src_set_cursor_sprite_metadata (MetaScreenCastStreamSrc + spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, + spa_meta_cursor->bitmap_offset, + struct spa_meta_bitmap); +- spa_meta_bitmap->format = spa_type->video_format.RGBA; ++ spa_meta_bitmap->format = SPA_VIDEO_FORMAT_RGBA; + spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); + + meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); +@@ -382,12 +366,10 @@ static void + add_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_buffer *spa_buffer) + { +- MetaScreenCastStreamSrcPrivate *priv = +- meta_screen_cast_stream_src_get_instance_private (src); +- MetaSpaType *spa_type = &priv->spa_type; + struct spa_meta_cursor *spa_meta_cursor; + +- spa_meta_cursor = spa_buffer_find_meta (spa_buffer, spa_type->meta_cursor); ++ spa_meta_cursor = spa_buffer_find_meta_data (spa_buffer, SPA_META_Cursor, ++ sizeof (*spa_meta_cursor)); + if (spa_meta_cursor) + meta_screen_cast_stream_src_set_cursor_metadata (src, spa_meta_cursor); + } +@@ -447,14 +429,14 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + { + data = spa_buffer->datas[0].data; + } +- else if (spa_buffer->datas[0].type == priv->pipewire_type->data.MemFd) ++ else if (spa_buffer->datas[0].type == SPA_DATA_MemFd) + { + map = mmap (NULL, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset, + PROT_READ | PROT_WRITE, MAP_SHARED, + spa_buffer->datas[0].fd, 0); + if (map == MAP_FAILED) + { +- g_warning ("Failed to mmap pipewire stream buffer: %s\n", ++ g_warning ("Failed to mmap pipewire stream buffer: %s", + strerror (errno)); + return; + } +@@ -469,28 +451,30 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + + if (meta_screen_cast_stream_src_record_frame (src, data)) + { +- struct spa_meta_video_crop *spa_meta_video_crop; ++ struct spa_meta_region *spa_meta_video_crop; + + spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize; ++ spa_buffer->datas[0].chunk->stride = priv->video_stride; + + /* Update VideoCrop if needed */ + spa_meta_video_crop = +- spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop); ++ spa_buffer_find_meta_data (spa_buffer, SPA_META_VideoCrop, ++ sizeof (*spa_meta_video_crop)); + if (spa_meta_video_crop) + { + if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect)) + { +- spa_meta_video_crop->x = crop_rect.x; +- spa_meta_video_crop->y = crop_rect.y; +- spa_meta_video_crop->width = crop_rect.width; +- spa_meta_video_crop->height = crop_rect.height; ++ spa_meta_video_crop->region.position.x = crop_rect.x; ++ spa_meta_video_crop->region.position.y = crop_rect.y; ++ spa_meta_video_crop->region.size.width = crop_rect.width; ++ spa_meta_video_crop->region.size.height = crop_rect.height; + } + else + { +- spa_meta_video_crop->x = 0; +- spa_meta_video_crop->y = 0; +- spa_meta_video_crop->width = priv->stream_width; +- spa_meta_video_crop->height = priv->stream_height; ++ spa_meta_video_crop->region.position.x = 0; ++ spa_meta_video_crop->region.position.y = 0; ++ spa_meta_video_crop->region.size.width = priv->stream_width; ++ spa_meta_video_crop->region.size.height = priv->stream_height; + } + } + } +@@ -555,7 +539,6 @@ on_stream_state_changed (void *data, + MetaScreenCastStreamSrc *src = data; + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); +- uint32_t node_id; + + switch (state) + { +@@ -563,14 +546,12 @@ on_stream_state_changed (void *data, + g_warning ("pipewire stream error: %s", error_message); + meta_screen_cast_stream_src_notify_closed (src); + break; +- case PW_STREAM_STATE_CONFIGURE: +- node_id = pw_stream_get_node_id (priv->pipewire_stream); +- g_signal_emit (src, signals[READY], 0, (unsigned int) node_id); +- break; +- case PW_STREAM_STATE_UNCONNECTED: +- case PW_STREAM_STATE_CONNECTING: +- case PW_STREAM_STATE_READY: + case PW_STREAM_STATE_PAUSED: ++ if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream) ++ { ++ priv->node_id = pw_stream_get_node_id (priv->pipewire_stream); ++ g_signal_emit (src, signals[READY], 0, (unsigned int) priv->node_id); ++ } + if (meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_disable (src); + break; +@@ -578,68 +559,69 @@ on_stream_state_changed (void *data, + if (!meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_enable (src); + break; ++ case PW_STREAM_STATE_UNCONNECTED: ++ case PW_STREAM_STATE_CONNECTING: ++ break; + } + } + + static void +-on_stream_format_changed (void *data, +- const struct spa_pod *format) ++on_stream_param_changed (void *data, ++ uint32_t id, ++ const struct spa_pod *format) + { + MetaScreenCastStreamSrc *src = data; + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); +- struct pw_type *pipewire_type = priv->pipewire_type; + uint8_t params_buffer[1024]; + int32_t width, height, stride, size; + struct spa_pod_builder pod_builder; + const struct spa_pod *params[3]; + const int bpp = 4; + +- if (!format) +- { +- pw_stream_finish_format (priv->pipewire_stream, 0, NULL, 0); +- return; +- } ++ if (!format || id != SPA_PARAM_Format) ++ return; + + spa_format_video_raw_parse (format, +- &priv->video_format, +- &priv->spa_type.format_video); ++ &priv->video_format); + + width = priv->video_format.size.width; + height = priv->video_format.size.height; + stride = SPA_ROUND_UP_N (width * bpp, 4); + size = height * stride; + ++ priv->video_stride = stride; ++ + pod_builder = SPA_POD_BUILDER_INIT (params_buffer, sizeof (params_buffer)); + +- params[0] = spa_pod_builder_object ( ++ params[0] = spa_pod_builder_add_object ( + &pod_builder, +- pipewire_type->param.idBuffers, pipewire_type->param_buffers.Buffers, +- ":", pipewire_type->param_buffers.size, "i", size, +- ":", pipewire_type->param_buffers.stride, "i", stride, +- ":", pipewire_type->param_buffers.buffers, "iru", 16, PROP_RANGE (2, 16), +- ":", pipewire_type->param_buffers.align, "i", 16); +- +- params[1] = spa_pod_builder_object ( ++ SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, ++ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int (16, 2, 16), ++ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int (1), ++ SPA_PARAM_BUFFERS_size, SPA_POD_Int (size), ++ SPA_PARAM_BUFFERS_stride, SPA_POD_Int (stride), ++ SPA_PARAM_BUFFERS_align, SPA_POD_Int (16)); ++ ++ params[1] = spa_pod_builder_add_object ( + &pod_builder, +- pipewire_type->param.idMeta, pipewire_type->param_meta.Meta, +- ":", pipewire_type->param_meta.type, "I", pipewire_type->meta.VideoCrop, +- ":", pipewire_type->param_meta.size, "i", sizeof (struct spa_meta_video_crop)); ++ SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, ++ SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoCrop), ++ SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_region))); + +- params[2] = spa_pod_builder_object ( ++ params[2] = spa_pod_builder_add_object ( + &pod_builder, +- pipewire_type->param.idMeta, pipewire_type->param_meta.Meta, +- ":", pipewire_type->param_meta.type, "I", priv->spa_type.meta_cursor, +- ":", pipewire_type->param_meta.size, "i", CURSOR_META_SIZE (64, 64)); ++ SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, ++ SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Cursor), ++ SPA_PARAM_META_size, SPA_POD_Int (CURSOR_META_SIZE (64, 64))); + +- pw_stream_finish_format (priv->pipewire_stream, 0, +- params, G_N_ELEMENTS (params)); ++ pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params)); + } + + static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .state_changed = on_stream_state_changed, +- .format_changed = on_stream_format_changed, ++ .param_changed = on_stream_param_changed, + }; + + static struct pw_stream * +@@ -652,8 +634,6 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + uint8_t buffer[1024]; + struct spa_pod_builder pod_builder = + SPA_POD_BUILDER_INIT (buffer, sizeof (buffer)); +- MetaSpaType *spa_type = &priv->spa_type; +- struct pw_type *pipewire_type = priv->pipewire_type; + float frame_rate; + MetaFraction frame_rate_fraction; + struct spa_fraction max_framerate; +@@ -661,7 +641,9 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + const struct spa_pod *params[1]; + int result; + +- pipewire_stream = pw_stream_new (priv->pipewire_remote, ++ priv->node_id = SPA_ID_INVALID; ++ ++ pipewire_stream = pw_stream_new (priv->pipewire_core, + "meta-screen-cast-src", + NULL); + if (!pipewire_stream) +@@ -682,17 +664,17 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + max_framerate = SPA_FRACTION (frame_rate_fraction.num, + frame_rate_fraction.denom); + +- params[0] = spa_pod_builder_object ( ++ params[0] = spa_pod_builder_add_object ( + &pod_builder, +- pipewire_type->param.idEnumFormat, pipewire_type->spa_format, +- "I", spa_type->media_type.video, +- "I", spa_type->media_subtype.raw, +- ":", spa_type->format_video.format, "I", spa_type->video_format.BGRx, +- ":", spa_type->format_video.size, "R", &SPA_RECTANGLE (priv->stream_width, +- priv->stream_height), +- ":", spa_type->format_video.framerate, "F", &SPA_FRACTION (0, 1), +- ":", spa_type->format_video.max_framerate, "Fru", &max_framerate, +- PROP_RANGE (&min_framerate, ++ 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 (priv->stream_width, ++ priv->stream_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)); + + pw_stream_add_listener (pipewire_stream, +@@ -702,7 +684,7 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + + result = pw_stream_connect (pipewire_stream, + PW_DIRECTION_OUTPUT, +- NULL, ++ SPA_ID_INVALID, + (PW_STREAM_FLAG_DRIVER | + PW_STREAM_FLAG_MAP_BUFFERS), + params, G_N_ELEMENTS (params)); +@@ -717,40 +699,18 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + } + + static void +-on_state_changed (void *data, +- enum pw_remote_state old, +- enum pw_remote_state state, +- const char *error_message) ++on_core_error (void *data, ++ uint32_t id, ++ int seq, ++ int res, ++ const char *message) + { + MetaScreenCastStreamSrc *src = data; +- MetaScreenCastStreamSrcPrivate *priv = +- meta_screen_cast_stream_src_get_instance_private (src); +- struct pw_stream *pipewire_stream; +- GError *error = NULL; + +- switch (state) +- { +- case PW_REMOTE_STATE_ERROR: +- g_warning ("pipewire remote error: %s\n", error_message); +- meta_screen_cast_stream_src_notify_closed (src); +- break; +- case PW_REMOTE_STATE_CONNECTED: +- pipewire_stream = create_pipewire_stream (src, &error); +- if (!pipewire_stream) +- { +- g_warning ("Could not create pipewire stream: %s", error->message); +- g_error_free (error); +- meta_screen_cast_stream_src_notify_closed (src); +- } +- else +- { +- priv->pipewire_stream = pipewire_stream; +- } +- break; +- case PW_REMOTE_STATE_UNCONNECTED: +- case PW_REMOTE_STATE_CONNECTING: +- break; +- } ++ g_warning ("pipewire remote error: id:%u %s", id, message); ++ ++ if (id == PW_ID_CORE && res == -EPIPE) ++ meta_screen_cast_stream_src_notify_closed (src); + } + + static gboolean +@@ -793,17 +753,6 @@ static GSourceFuncs pipewire_source_funcs = + pipewire_loop_source_finalize + }; + +-static void +-init_spa_type (MetaSpaType *type, +- struct spa_type_map *map) +-{ +- spa_type_media_type_map (map, &type->media_type); +- spa_type_media_subtype_map (map, &type->media_subtype); +- spa_type_format_video_map (map, &type->format_video); +- spa_type_video_format_map (map, &type->video_format); +- type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); +-} +- + static MetaPipeWireSource * + create_pipewire_source (void) + { +@@ -829,9 +778,9 @@ create_pipewire_source (void) + return pipewire_source; + } + +-static const struct pw_remote_events remote_events = { +- PW_VERSION_REMOTE_EVENTS, +- .state_changed = on_state_changed, ++static const struct pw_core_events core_events = { ++ PW_VERSION_CORE_EVENTS, ++ .error = on_core_error, + }; + + static gboolean +@@ -851,37 +800,31 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable, + return FALSE; + } + +- priv->pipewire_core = pw_core_new (priv->pipewire_source->pipewire_loop, +- NULL); +- if (!priv->pipewire_core) ++ priv->pipewire_context = pw_context_new (priv->pipewire_source->pipewire_loop, ++ NULL, 0); ++ if (!priv->pipewire_context) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Failed to create pipewire core"); ++ "Failed to create pipewire context"); + return FALSE; + } + +- priv->pipewire_remote = pw_remote_new (priv->pipewire_core, NULL, 0); +- if (!priv->pipewire_remote) ++ priv->pipewire_core = pw_context_connect (priv->pipewire_context, NULL, 0); ++ if (!priv->pipewire_core) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Couldn't creat pipewire remote"); ++ "Couldn't connect pipewire context"); + return FALSE; + } + +- pw_remote_add_listener (priv->pipewire_remote, +- &priv->pipewire_remote_listener, +- &remote_events, +- src); ++ pw_core_add_listener (priv->pipewire_core, ++ &priv->pipewire_core_listener, ++ &core_events, ++ src); + +- priv->pipewire_type = pw_core_get_type (priv->pipewire_core); +- init_spa_type (&priv->spa_type, priv->pipewire_type->map); +- +- if (pw_remote_connect (priv->pipewire_remote) != 0) +- { +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Couldn't connect pipewire remote"); +- return FALSE; +- } ++ priv->pipewire_stream = create_pipewire_stream (src, error); ++ if (!priv->pipewire_stream) ++ return FALSE; + + return TRUE; + } +@@ -912,8 +855,8 @@ meta_screen_cast_stream_src_finalize (GObject *object) + meta_screen_cast_stream_src_disable (src); + + g_clear_pointer (&priv->pipewire_stream, pw_stream_destroy); +- g_clear_pointer (&priv->pipewire_remote, pw_remote_destroy); +- g_clear_pointer (&priv->pipewire_core, pw_core_destroy); ++ g_clear_pointer (&priv->pipewire_core, pw_core_disconnect); ++ g_clear_pointer (&priv->pipewire_context, pw_context_destroy); + g_source_destroy (&priv->pipewire_source->base); + + G_OBJECT_CLASS (meta_screen_cast_stream_src_parent_class)->finalize (object); +-- +2.26.2 + + +From b29e2f833357a0b29bb42999b4d6be725be067d1 Mon Sep 17 00:00:00 2001 +From: Pekka Paalanen +Date: Mon, 10 Jun 2019 17:07:55 +0300 +Subject: [PATCH 19/49] egl: Introduce meta_egl_create_dmabuf_image + +This bit of code was more or less duplicated in meta-renderer-native-gles3.c +and meta-wayland-dma-buf.c. Start consolidating the two implementations by +moving the *-gles3.c function into meta-egl.c and generalizing it so it could +also accommodate the meta-wayland-dma-buf.c usage. + +The workaround in the *-gles3.c implementation is moved to the caller. It is +the caller's responsibility to check for the existence of the appropriate EGL +extensions. + +Commit 6f59e4858e24c828e3ab0e611d36dfaaded1b272 worked around the lack of +EGL_EXT_image_dma_buf_import_modifiers with the assumption that if the modifier +is linear, there is no need to pass it into EGL. The problem is that not +passing a modifier explicitly to EGL invokes implementation-defined behaviour, +so we should not have that workaround in meta-egl.c. + +This patch intends to be pure refactoring, no behavioral changes. The one +change is the addition of g_assert to catch overwriting arbitrary memory. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/615 +--- + src/backends/meta-egl.c | 94 ++++++++++++- + src/backends/meta-egl.h | 13 ++ + .../native/meta-renderer-native-gles3.c | 125 +++--------------- + 3 files changed, 127 insertions(+), 105 deletions(-) + +diff --git a/src/backends/meta-egl.c b/src/backends/meta-egl.c +index a28eef4ca..fdeff4f77 100644 +--- a/src/backends/meta-egl.c ++++ b/src/backends/meta-egl.c +@@ -1,7 +1,8 @@ + /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + + /* +- * Copyright (C) 2016 Red Hat Inc. ++ * Copyright (C) 2016, 2017 Red Hat Inc. ++ * Copyright (C) 2018, 2019 DisplayLink (UK) Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as +@@ -575,6 +576,97 @@ meta_egl_destroy_image (MetaEgl *egl, + return TRUE; + } + ++EGLImageKHR ++meta_egl_create_dmabuf_image (MetaEgl *egl, ++ EGLDisplay egl_display, ++ unsigned int width, ++ unsigned int height, ++ uint32_t drm_format, ++ uint32_t n_planes, ++ const int *fds, ++ const uint32_t *strides, ++ const uint32_t *offsets, ++ const uint64_t *modifiers, ++ GError **error) ++{ ++ EGLint attribs[37]; ++ int atti = 0; ++ ++ /* This requires the Mesa commit in ++ * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or ++ * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652). ++ * Otherwise Mesa closes the fd behind our back and re-importing ++ * will fail. ++ * https://bugs.freedesktop.org/show_bug.cgi?id=76188 ++ */ ++ ++ attribs[atti++] = EGL_WIDTH; ++ attribs[atti++] = width; ++ attribs[atti++] = EGL_HEIGHT; ++ attribs[atti++] = height; ++ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; ++ attribs[atti++] = drm_format; ++ ++ if (n_planes > 0) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; ++ attribs[atti++] = fds[0]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; ++ attribs[atti++] = offsets[0]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; ++ attribs[atti++] = strides[0]; ++ if (modifiers) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; ++ attribs[atti++] = modifiers[0] & 0xFFFFFFFF; ++ attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; ++ attribs[atti++] = modifiers[0] >> 32; ++ } ++ } ++ ++ if (n_planes > 1) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; ++ attribs[atti++] = fds[1]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; ++ attribs[atti++] = offsets[1]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; ++ attribs[atti++] = strides[1]; ++ if (modifiers) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; ++ attribs[atti++] = modifiers[1] & 0xFFFFFFFF; ++ attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; ++ attribs[atti++] = modifiers[1] >> 32; ++ } ++ } ++ ++ if (n_planes > 2) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; ++ attribs[atti++] = fds[2]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; ++ attribs[atti++] = offsets[2]; ++ attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; ++ attribs[atti++] = strides[2]; ++ if (modifiers) ++ { ++ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT; ++ attribs[atti++] = modifiers[2] & 0xFFFFFFFF; ++ attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; ++ attribs[atti++] = modifiers[2] >> 32; ++ } ++ } ++ ++ attribs[atti++] = EGL_NONE; ++ g_assert (atti <= G_N_ELEMENTS (attribs)); ++ ++ return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, ++ EGL_LINUX_DMA_BUF_EXT, NULL, ++ attribs, ++ error); ++} ++ + gboolean + meta_egl_make_current (MetaEgl *egl, + EGLDisplay display, +diff --git a/src/backends/meta-egl.h b/src/backends/meta-egl.h +index 81b53b32d..4591e7d85 100644 +--- a/src/backends/meta-egl.h ++++ b/src/backends/meta-egl.h +@@ -2,6 +2,7 @@ + + /* + * Copyright (C) 2016 Red Hat Inc. ++ * Copyright (C) 2019 DisplayLink (UK) Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as +@@ -101,6 +102,18 @@ gboolean meta_egl_destroy_image (MetaEgl *egl, + EGLImageKHR image, + GError **error); + ++EGLImageKHR meta_egl_create_dmabuf_image (MetaEgl *egl, ++ EGLDisplay egl_display, ++ unsigned int width, ++ unsigned int height, ++ uint32_t drm_format, ++ uint32_t n_planes, ++ const int *fds, ++ const uint32_t *strides, ++ const uint32_t *offsets, ++ const uint64_t *modifiers, ++ GError **error); ++ + EGLSurface meta_egl_create_window_surface (MetaEgl *egl, + EGLDisplay display, + EGLConfig config, +diff --git a/src/backends/native/meta-renderer-native-gles3.c b/src/backends/native/meta-renderer-native-gles3.c +index 7afea8648..740b52ef6 100644 +--- a/src/backends/native/meta-renderer-native-gles3.c ++++ b/src/backends/native/meta-renderer-native-gles3.c +@@ -45,101 +45,6 @@ + #error "Somehow included OpenGL headers when we shouldn't have" + #endif + +-static EGLImageKHR +-create_egl_image (MetaEgl *egl, +- EGLDisplay egl_display, +- EGLContext egl_context, +- unsigned int width, +- unsigned int height, +- uint32_t n_planes, +- uint32_t *strides, +- uint32_t *offsets, +- uint64_t *modifiers, +- uint32_t format, +- int fd, +- GError **error) +-{ +- EGLint attribs[37]; +- int atti = 0; +- gboolean has_modifier; +- +- /* This requires the Mesa commit in +- * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or +- * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652). +- * Otherwise Mesa closes the fd behind our back and re-importing +- * will fail. +- * https://bugs.freedesktop.org/show_bug.cgi?id=76188 +- */ +- +- attribs[atti++] = EGL_WIDTH; +- attribs[atti++] = width; +- attribs[atti++] = EGL_HEIGHT; +- attribs[atti++] = height; +- attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; +- attribs[atti++] = format; +- +- has_modifier = (modifiers[0] != DRM_FORMAT_MOD_INVALID && +- modifiers[0] != DRM_FORMAT_MOD_LINEAR); +- +- if (n_planes > 0) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; +- attribs[atti++] = fd; +- attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; +- attribs[atti++] = offsets[0]; +- attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; +- attribs[atti++] = strides[0]; +- if (has_modifier) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; +- attribs[atti++] = modifiers[0] & 0xFFFFFFFF; +- attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; +- attribs[atti++] = modifiers[0] >> 32; +- } +- } +- +- if (n_planes > 1) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; +- attribs[atti++] = fd; +- attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; +- attribs[atti++] = offsets[1]; +- attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; +- attribs[atti++] = strides[1]; +- if (has_modifier) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; +- attribs[atti++] = modifiers[1] & 0xFFFFFFFF; +- attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; +- attribs[atti++] = modifiers[1] >> 32; +- } +- } +- +- if (n_planes > 2) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; +- attribs[atti++] = fd; +- attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; +- attribs[atti++] = offsets[2]; +- attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; +- attribs[atti++] = strides[2]; +- if (has_modifier) +- { +- attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT; +- attribs[atti++] = modifiers[2] & 0xFFFFFFFF; +- attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; +- attribs[atti++] = modifiers[2] >> 32; +- } +- } +- +- attribs[atti++] = EGL_NONE; +- +- return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, +- EGL_LINUX_DMA_BUF_EXT, NULL, +- attribs, +- error); +-} +- + static void + paint_egl_image (MetaGles3 *gles3, + EGLImageKHR egl_image, +@@ -195,8 +100,10 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, + uint32_t strides[4] = { 0 }; + uint32_t offsets[4] = { 0 }; + uint64_t modifiers[4] = { 0 }; ++ int fds[4] = { -1, -1, -1, -1 }; + uint32_t format; + EGLImageKHR egl_image; ++ gboolean use_modifiers; + + shared_bo_fd = gbm_bo_get_fd (shared_bo); + if (shared_bo_fd < 0) +@@ -216,17 +123,27 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, + strides[i] = gbm_bo_get_stride_for_plane (shared_bo, i); + offsets[i] = gbm_bo_get_offset (shared_bo, i); + modifiers[i] = gbm_bo_get_modifier (shared_bo); ++ fds[i] = shared_bo_fd; + } + +- egl_image = create_egl_image (egl, +- egl_display, +- egl_context, +- width, height, +- n_planes, +- strides, offsets, +- modifiers, format, +- shared_bo_fd, +- error); ++ /* Workaround for https://gitlab.gnome.org/GNOME/mutter/issues/18 */ ++ if (modifiers[0] == DRM_FORMAT_MOD_LINEAR || ++ modifiers[0] == DRM_FORMAT_MOD_INVALID) ++ use_modifiers = FALSE; ++ else ++ use_modifiers = TRUE; ++ ++ egl_image = meta_egl_create_dmabuf_image (egl, ++ egl_display, ++ width, ++ height, ++ format, ++ n_planes, ++ fds, ++ strides, ++ offsets, ++ use_modifiers ? modifiers : NULL, ++ error); + close (shared_bo_fd); + + if (!egl_image) +-- +2.26.2 + + +From 5af71a6c4a723951b26597ee710462b18867d113 Mon Sep 17 00:00:00 2001 +From: Pekka Paalanen +Date: Thu, 29 Nov 2018 13:37:16 +0200 +Subject: [PATCH 20/49] renderer/native: Add meta_dumb_buffer_ensure_dmabuf_fd + +Follow-up work will use this in an attempt to use the primary GPU to +copy into secondary GPU dumb buffers. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/615 +--- + src/backends/native/meta-renderer-native.c | 36 ++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index ffb64a6bd..76cc79e23 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -133,6 +133,7 @@ typedef struct _MetaDumbBuffer + int height; + int stride_bytes; + uint32_t drm_format; ++ int dmabuf_fd; + } MetaDumbBuffer; + + typedef struct _MetaOnscreenNativeSecondaryGpuState +@@ -242,6 +243,10 @@ init_dumb_fb (MetaDumbBuffer *dumb_fb, + uint32_t format, + GError **error); + ++static int ++meta_dumb_buffer_ensure_dmabuf_fd (MetaDumbBuffer *dumb_fb, ++ MetaGpuKms *gpu_kms); ++ + static MetaEgl * + meta_renderer_native_get_egl (MetaRendererNative *renderer_native); + +@@ -2892,6 +2897,7 @@ init_dumb_fb (MetaDumbBuffer *dumb_fb, + dumb_fb->height = height; + dumb_fb->stride_bytes = create_arg.pitch; + dumb_fb->drm_format = format; ++ dumb_fb->dmabuf_fd = -1; + + return TRUE; + +@@ -2909,6 +2915,33 @@ err_ioctl: + return FALSE; + } + ++static int ++meta_dumb_buffer_ensure_dmabuf_fd (MetaDumbBuffer *dumb_fb, ++ MetaGpuKms *gpu_kms) ++{ ++ int ret; ++ int kms_fd; ++ int dmabuf_fd; ++ ++ if (dumb_fb->dmabuf_fd != -1) ++ return dumb_fb->dmabuf_fd; ++ ++ kms_fd = meta_gpu_kms_get_fd (gpu_kms); ++ ++ ret = drmPrimeHandleToFD (kms_fd, dumb_fb->handle, DRM_CLOEXEC, ++ &dmabuf_fd); ++ if (ret) ++ { ++ g_debug ("Failed to export dumb drm buffer: %s", ++ g_strerror (errno)); ++ return -1; ++ } ++ ++ dumb_fb->dmabuf_fd = dmabuf_fd; ++ ++ return dumb_fb->dmabuf_fd; ++} ++ + static void + release_dumb_fb (MetaDumbBuffer *dumb_fb, + MetaGpuKms *gpu_kms) +@@ -2919,6 +2952,9 @@ release_dumb_fb (MetaDumbBuffer *dumb_fb, + if (!dumb_fb->map) + return; + ++ if (dumb_fb->dmabuf_fd != -1) ++ close (dumb_fb->dmabuf_fd); ++ + munmap (dumb_fb->map, dumb_fb->map_size); + dumb_fb->map = NULL; + +-- +2.26.2 + + +From a6e2e1cb5fd25e152bbc3347078b0e9261a94ceb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 16 Jul 2019 18:27:38 +0200 +Subject: [PATCH 21/49] cogl/texture: Make is_get_data_supported() a bool on + the texture + +Comparing the gl target is not enough. More on that later. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/687 +--- + cogl/cogl/cogl-texture-2d-private.h | 1 + + cogl/cogl/cogl-texture-2d.c | 1 + + cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 6 ++---- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/cogl/cogl/cogl-texture-2d-private.h b/cogl/cogl/cogl-texture-2d-private.h +index 450d156f1..c1e6dff50 100644 +--- a/cogl/cogl/cogl-texture-2d-private.h ++++ b/cogl/cogl/cogl-texture-2d-private.h +@@ -47,6 +47,7 @@ struct _CoglTexture2D + gboolean auto_mipmap; + gboolean mipmaps_dirty; + gboolean is_foreign; ++ gboolean is_get_data_supported; + + /* TODO: factor out these OpenGL specific members into some form + * of driver private state. */ +diff --git a/cogl/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c +index 76f0e3a87..76cb75a5c 100644 +--- a/cogl/cogl/cogl-texture-2d.c ++++ b/cogl/cogl/cogl-texture-2d.c +@@ -107,6 +107,7 @@ _cogl_texture_2d_create_base (CoglContext *ctx, + + tex_2d->mipmaps_dirty = TRUE; + tex_2d->auto_mipmap = TRUE; ++ tex_2d->is_get_data_supported = TRUE; + + tex_2d->gl_target = GL_TEXTURE_2D; + +diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +index e36c3523e..a9329ad50 100644 +--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c ++++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +@@ -514,6 +514,7 @@ allocate_custom_egl_image_external (CoglTexture2D *tex_2d, + + tex_2d->internal_format = internal_format; + tex_2d->gl_target = GL_TEXTURE_EXTERNAL_OES; ++ tex_2d->is_get_data_supported = FALSE; + + return TRUE; + } +@@ -840,10 +841,7 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, + gboolean + _cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d) + { +- if (tex_2d->gl_target == GL_TEXTURE_EXTERNAL_OES) +- return FALSE; +- else +- return TRUE; ++ return tex_2d->is_get_data_supported; + } + + void +-- +2.26.2 + + +From 50108eca1503c8883370f0f877cab8d25f89ad2e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 16 Jul 2019 18:29:29 +0200 +Subject: [PATCH 22/49] cogl/texture: Add EGLImage texture import flags + +The flags are 'none', and 'no-get-data' meaning get_data() is not +supported. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/687 +--- + cogl/cogl/cogl-texture-2d.c | 3 +++ + cogl/cogl/cogl-texture-2d.h | 7 +++++++ + cogl/cogl/cogl-texture-private.h | 1 + + cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 2 ++ + cogl/cogl/winsys/cogl-winsys-egl-x11.c | 1 + + src/wayland/meta-wayland-buffer.c | 3 +++ + src/wayland/meta-wayland-dma-buf.c | 3 +++ + 7 files changed, 20 insertions(+) + +diff --git a/cogl/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c +index 76cb75a5c..6544f8a62 100644 +--- a/cogl/cogl/cogl-texture-2d.c ++++ b/cogl/cogl/cogl-texture-2d.c +@@ -242,6 +242,7 @@ cogl_egl_texture_2d_new_from_image (CoglContext *ctx, + int height, + CoglPixelFormat format, + EGLImageKHR image, ++ CoglEglImageFlags flags, + CoglError **error) + { + CoglTextureLoader *loader; +@@ -262,6 +263,7 @@ cogl_egl_texture_2d_new_from_image (CoglContext *ctx, + loader->src.egl_image.width = width; + loader->src.egl_image.height = height; + loader->src.egl_image.format = format; ++ loader->src.egl_image.flags = flags; + + tex = _cogl_texture_2d_create_base (ctx, width, height, format, loader); + +@@ -436,6 +438,7 @@ cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, + width, height, + internal_format, + image, ++ COGL_EGL_IMAGE_FLAG_NONE, + error); + _cogl_egl_destroy_image (ctx, image); + return tex; +diff --git a/cogl/cogl/cogl-texture-2d.h b/cogl/cogl/cogl-texture-2d.h +index 29b8b2d6b..44b9d4636 100644 +--- a/cogl/cogl/cogl-texture-2d.h ++++ b/cogl/cogl/cogl-texture-2d.h +@@ -65,6 +65,12 @@ G_BEGIN_DECLS + typedef struct _CoglTexture2D CoglTexture2D; + #define COGL_TEXTURE_2D(X) ((CoglTexture2D *)X) + ++typedef enum _CoglEglImageFlags ++{ ++ COGL_EGL_IMAGE_FLAG_NONE = 0, ++ COGL_EGL_IMAGE_FLAG_NO_GET_DATA = 1 << 0, ++} CoglEglImageFlags; ++ + /** + * cogl_texture_2d_get_gtype: + * +@@ -244,6 +250,7 @@ cogl_egl_texture_2d_new_from_image (CoglContext *ctx, + int height, + CoglPixelFormat format, + EGLImageKHR image, ++ CoglEglImageFlags flags, + CoglError **error); + + typedef gboolean (*CoglTexture2DEGLImageExternalAlloc) (CoglTexture2D *tex_2d, +diff --git a/cogl/cogl/cogl-texture-private.h b/cogl/cogl/cogl-texture-private.h +index 05a0045f8..794d0d7e7 100644 +--- a/cogl/cogl/cogl-texture-private.h ++++ b/cogl/cogl/cogl-texture-private.h +@@ -184,6 +184,7 @@ typedef struct _CoglTextureLoader + int width; + int height; + CoglPixelFormat format; ++ CoglEglImageFlags flags; + } egl_image; + #endif + #if defined (COGL_HAS_EGL_SUPPORT) +diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +index a9329ad50..34432ccba 100644 +--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c ++++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +@@ -328,6 +328,8 @@ allocate_from_egl_image (CoglTexture2D *tex_2d, + } + + tex_2d->internal_format = internal_format; ++ tex_2d->is_get_data_supported = ++ !(loader->src.egl_image.flags & COGL_EGL_IMAGE_FLAG_NO_GET_DATA); + + _cogl_texture_set_allocated (tex, + internal_format, +diff --git a/cogl/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/cogl/winsys/cogl-winsys-egl-x11.c +index 4f0a12543..6a89206a1 100644 +--- a/cogl/cogl/winsys/cogl-winsys-egl-x11.c ++++ b/cogl/cogl/winsys/cogl-winsys-egl-x11.c +@@ -802,6 +802,7 @@ _cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap) + tex->height, + texture_format, + egl_tex_pixmap->image, ++ COGL_EGL_IMAGE_FLAG_NONE, + NULL)); + + tex_pixmap->winsys = egl_tex_pixmap; +diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c +index f45679d3a..cdaad26eb 100644 +--- a/src/wayland/meta-wayland-buffer.c ++++ b/src/wayland/meta-wayland-buffer.c +@@ -289,6 +289,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer, + int format, width, height, y_inverted; + CoglPixelFormat cogl_format; + EGLImageKHR egl_image; ++ CoglEglImageFlags flags; + CoglTexture2D *texture_2d; + + if (buffer->egl_image.texture) +@@ -343,10 +344,12 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer, + if (egl_image == EGL_NO_IMAGE_KHR) + return FALSE; + ++ flags = COGL_EGL_IMAGE_FLAG_NONE; + texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context, + width, height, + cogl_format, + egl_image, ++ flags, + error); + + meta_egl_destroy_image (egl, egl_display, egl_image, NULL); +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index e49fba9cf..786b88304 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -77,6 +77,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, + MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf; + CoglPixelFormat cogl_format; + EGLImageKHR egl_image; ++ CoglEglImageFlags flags; + CoglTexture2D *texture; + EGLint attribs[64]; + int attr_idx = 0; +@@ -184,11 +185,13 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, + if (egl_image == EGL_NO_IMAGE_KHR) + return FALSE; + ++ flags = COGL_EGL_IMAGE_FLAG_NONE; + texture = cogl_egl_texture_2d_new_from_image (cogl_context, + dma_buf->width, + dma_buf->height, + cogl_format, + egl_image, ++ flags, + error); + + meta_egl_destroy_image (egl, egl_display, egl_image, NULL); +-- +2.26.2 + + +From cca085b00c029debaed80c070e316a3a7ff7e44d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 16 Jul 2019 18:30:12 +0200 +Subject: [PATCH 23/49] dma-buf: Mark DMA-BUF textures as paint-only + +Reading pixels directly from a texture imported from a DMA-BUF EGLImage +may result compressed textures to be transferred into non-compressed +texture. This may have side effects causing it to be rendered +incorrectly in subsequent paints. + +Avoid this by passing the no-get-data flag to the texture creator +function, eventually causing mutter to use an intermediate offscreen +framebuffer when reading pixels from such textures. + +https://bugs.freedesktop.org/show_bug.cgi?id=111140 +https://gitlab.freedesktop.org/xorg/xserver/issues/545 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/687 +--- + src/wayland/meta-wayland-dma-buf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 786b88304..5661fb6ff 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -185,7 +185,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, + if (egl_image == EGL_NO_IMAGE_KHR) + return FALSE; + +- flags = COGL_EGL_IMAGE_FLAG_NONE; ++ flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA; + texture = cogl_egl_texture_2d_new_from_image (cogl_context, + dma_buf->width, + dma_buf->height, +-- +2.26.2 + + +From 8e25a750e9084cbc4f7e7048453ef33dfa9ea314 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 24 Feb 2020 12:44:52 -0300 +Subject: [PATCH 24/49] cogl/framebuffer: Add cogl_framebuffer_flush + +In future patches, we'll create additional CoglFramebuffers that +will be shared via DMA-Buf with PipeWire. When recording frames, +we'll blit the current onscreen framebuffer into the shared one. + +However, that presents a problem: cogl_framebuffer_blit() mimics +glBlitFramebuffer() semantics, and doesn't do an implicit flush +of the GPU command stream. As a consequence, clients may receive +unblitted or incomplete framebuffers. + +We could use cogl_framebuffer_finish() to ensure the commands were +submitted to the GPU, but it is too harsh -- it blocks the CPU +completely until the commands are finished! + +Add cogl_framebuffer_flush(), which ensures the command stream is +submitted to the GPU without blocking the CPU. Even though we don't +use the framebuffer specifically, it may be useful in the future +for e.g. a potential Vulkan backend to have access to the framebuffer. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + cogl/cogl/cogl-driver.h | 3 +++ + cogl/cogl/cogl-framebuffer.c | 11 +++++++++++ + cogl/cogl/cogl-framebuffer.h | 12 ++++++++++++ + cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h | 3 +++ + cogl/cogl/driver/gl/cogl-framebuffer-gl.c | 6 ++++++ + cogl/cogl/driver/gl/gl/cogl-driver-gl.c | 1 + + cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 1 + + cogl/cogl/driver/nop/cogl-driver-nop.c | 1 + + cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h | 3 +++ + cogl/cogl/driver/nop/cogl-framebuffer-nop.c | 5 +++++ + 10 files changed, 46 insertions(+) + +diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h +index 86682d8a7..af92146d0 100644 +--- a/cogl/cogl/cogl-driver.h ++++ b/cogl/cogl/cogl-driver.h +@@ -87,6 +87,9 @@ struct _CoglDriverVtable + void + (* framebuffer_finish) (CoglFramebuffer *framebuffer); + ++ void ++ (* framebuffer_flush) (CoglFramebuffer *framebuffer); ++ + void + (* framebuffer_discard_buffers) (CoglFramebuffer *framebuffer, + unsigned long buffers); +diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c +index 948cd112d..d64fc89fb 100644 +--- a/cogl/cogl/cogl-framebuffer.c ++++ b/cogl/cogl/cogl-framebuffer.c +@@ -1568,6 +1568,17 @@ cogl_framebuffer_finish (CoglFramebuffer *framebuffer) + ctx->driver_vtable->framebuffer_finish (framebuffer); + } + ++void ++cogl_framebuffer_flush (CoglFramebuffer *framebuffer) ++{ ++ ++ CoglContext *ctx = framebuffer->context; ++ ++ _cogl_framebuffer_flush_journal (framebuffer); ++ ++ ctx->driver_vtable->framebuffer_flush (framebuffer); ++} ++ + void + cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer) + { +diff --git a/cogl/cogl/cogl-framebuffer.h b/cogl/cogl/cogl-framebuffer.h +index 230a78627..38ada9feb 100644 +--- a/cogl/cogl/cogl-framebuffer.h ++++ b/cogl/cogl/cogl-framebuffer.h +@@ -1910,6 +1910,18 @@ cogl_blit_framebuffer (CoglFramebuffer *src, + int height, + GError **error); + ++/** ++ * cogl_framebuffer_flush: ++ * @framebuffer: A #CoglFramebuffer pointer ++ * ++ * Flushes @framebuffer to ensure the current batch of commands is ++ * submitted to the GPU. ++ * ++ * Unlike cogl_framebuffer_finish(), this does not block the CPU. ++ */ ++void ++cogl_framebuffer_flush (CoglFramebuffer *framebuffer); ++ + G_END_DECLS + + #endif /* __COGL_FRAMEBUFFER_H */ +diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h +index 214f45f0f..bbd7b0e99 100644 +--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h ++++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h +@@ -61,6 +61,9 @@ _cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer, + void + _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer); + ++void ++_cogl_framebuffer_gl_flush (CoglFramebuffer *framebuffer); ++ + void + _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers); +diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +index 90d08954d..6466fd6bc 100644 +--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c ++++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +@@ -1115,6 +1115,12 @@ _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer) + GE (framebuffer->context, glFinish ()); + } + ++void ++_cogl_framebuffer_gl_flush (CoglFramebuffer *framebuffer) ++{ ++ GE (framebuffer->context, glFlush ()); ++} ++ + void + _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers) +diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +index e06e27961..716617b54 100644 +--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c ++++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +@@ -668,6 +668,7 @@ _cogl_driver_gl = + _cogl_framebuffer_gl_clear, + _cogl_framebuffer_gl_query_bits, + _cogl_framebuffer_gl_finish, ++ _cogl_framebuffer_gl_flush, + _cogl_framebuffer_gl_discard_buffers, + _cogl_framebuffer_gl_draw_attributes, + _cogl_framebuffer_gl_draw_indexed_attributes, +diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +index bcb0bdf07..902bd0bd3 100644 +--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c ++++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +@@ -447,6 +447,7 @@ _cogl_driver_gles = + _cogl_framebuffer_gl_clear, + _cogl_framebuffer_gl_query_bits, + _cogl_framebuffer_gl_finish, ++ _cogl_framebuffer_gl_flush, + _cogl_framebuffer_gl_discard_buffers, + _cogl_framebuffer_gl_draw_attributes, + _cogl_framebuffer_gl_draw_indexed_attributes, +diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c +index b41a2bcc5..8cab69afa 100644 +--- a/cogl/cogl/driver/nop/cogl-driver-nop.c ++++ b/cogl/cogl/driver/nop/cogl-driver-nop.c +@@ -66,6 +66,7 @@ _cogl_driver_nop = + _cogl_framebuffer_nop_clear, + _cogl_framebuffer_nop_query_bits, + _cogl_framebuffer_nop_finish, ++ _cogl_framebuffer_nop_flush, + _cogl_framebuffer_nop_discard_buffers, + _cogl_framebuffer_nop_draw_attributes, + _cogl_framebuffer_nop_draw_indexed_attributes, +diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h +index 05bbde6b4..810b98413 100644 +--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h ++++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h +@@ -64,6 +64,9 @@ _cogl_framebuffer_nop_query_bits (CoglFramebuffer *framebuffer, + void + _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer); + ++void ++_cogl_framebuffer_nop_flush (CoglFramebuffer *framebuffer); ++ + void + _cogl_framebuffer_nop_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers); +diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c +index 643e304ea..db9819524 100644 +--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c ++++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c +@@ -76,6 +76,11 @@ _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer) + { + } + ++void ++_cogl_framebuffer_nop_flush (CoglFramebuffer *framebuffer) ++{ ++} ++ + void + _cogl_framebuffer_nop_discard_buffers (CoglFramebuffer *framebuffer, + unsigned long buffers) +-- +2.26.2 + + +From 80affcf2cd04a0a05dd6cb45ea7475b12d9f6841 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 9 Dec 2019 10:03:07 -0300 +Subject: [PATCH 25/49] cogl/context: Add cogl_renderer_create_dma_buf() and + family + +This is a winsys-specific API that allows exporting a DMA buffer fd. +The CoglDmaBufHandle structure allows passing the ownership of the +DMA buffer to whoever is using it, so the winsys doesn't need to +manually track it. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + cogl/cogl/cogl-dma-buf-handle.c | 94 ++++++++++++++++++++++++++ + cogl/cogl/cogl-dma-buf-handle.h | 83 +++++++++++++++++++++++ + cogl/cogl/cogl-renderer.c | 14 ++++ + cogl/cogl/cogl-renderer.h | 21 ++++++ + cogl/cogl/cogl-types.h | 8 +++ + cogl/cogl/cogl.h | 1 + + cogl/cogl/meson.build | 2 + + cogl/cogl/winsys/cogl-winsys-private.h | 6 ++ + 8 files changed, 229 insertions(+) + create mode 100644 cogl/cogl/cogl-dma-buf-handle.c + create mode 100644 cogl/cogl/cogl-dma-buf-handle.h + +diff --git a/cogl/cogl/cogl-dma-buf-handle.c b/cogl/cogl/cogl-dma-buf-handle.c +new file mode 100644 +index 000000000..4a8f709f2 +--- /dev/null ++++ b/cogl/cogl/cogl-dma-buf-handle.c +@@ -0,0 +1,94 @@ ++/* ++ * Cogl ++ * ++ * A Low Level GPU Graphics and Utilities API ++ * ++ * Copyright (C) 2020 Endless, Inc. ++ * ++ * 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 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. ++ * ++ * Authors: ++ * Georges Basile Stavracas Neto ++ */ ++ ++#include "cogl-config.h" ++ ++#include "cogl-dma-buf-handle.h" ++#include "cogl-object.h" ++ ++#include ++ ++struct _CoglDmaBufHandle ++{ ++ CoglFramebuffer *framebuffer; ++ int dmabuf_fd; ++ gpointer user_data; ++ GDestroyNotify destroy_func; ++}; ++ ++CoglDmaBufHandle * ++cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer, ++ int dmabuf_fd, ++ gpointer user_data, ++ GDestroyNotify destroy_func) ++{ ++ CoglDmaBufHandle *dmabuf_handle; ++ ++ g_assert (framebuffer); ++ g_assert (dmabuf_fd != -1); ++ ++ dmabuf_handle = g_new0 (CoglDmaBufHandle, 1); ++ dmabuf_handle->framebuffer = cogl_object_ref (framebuffer); ++ dmabuf_handle->dmabuf_fd = dmabuf_fd; ++ dmabuf_handle->user_data = user_data; ++ dmabuf_handle->destroy_func = destroy_func; ++ ++ return dmabuf_handle; ++} ++ ++void ++cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle) ++{ ++ g_return_if_fail (dmabuf_handle != NULL); ++ ++ g_clear_pointer (&dmabuf_handle->framebuffer, cogl_object_unref); ++ ++ if (dmabuf_handle->destroy_func) ++ g_clear_pointer (&dmabuf_handle->user_data, dmabuf_handle->destroy_func); ++ ++ if (dmabuf_handle->dmabuf_fd != -1) ++ close (dmabuf_handle->dmabuf_fd); ++ ++ g_free (dmabuf_handle); ++} ++ ++CoglFramebuffer * ++cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle) ++{ ++ return dmabuf_handle->framebuffer; ++} ++ ++int ++cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle) ++{ ++ return dmabuf_handle->dmabuf_fd; ++} ++ +diff --git a/cogl/cogl/cogl-dma-buf-handle.h b/cogl/cogl/cogl-dma-buf-handle.h +new file mode 100644 +index 000000000..25b9b0ccb +--- /dev/null ++++ b/cogl/cogl/cogl-dma-buf-handle.h +@@ -0,0 +1,83 @@ ++/* ++ * Cogl ++ * ++ * A Low Level GPU Graphics and Utilities API ++ * ++ * Copyright (C) 2020 Endless, Inc. ++ * ++ * 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 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. ++ * ++ * Authors: ++ * Georges Basile Stavracas Neto ++ */ ++ ++ ++#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) ++#error "Only can be included directly." ++#endif ++ ++#ifndef __COGL_DMA_BUF_HANDLE_H__ ++#define __COGL_DMA_BUF_HANDLE_H__ ++ ++#include ++#include ++ ++/** ++ * cogl_dma_buf_handle_new: (skip) ++ */ ++CoglDmaBufHandle * ++cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer, ++ int dmabuf_fd, ++ gpointer data, ++ GDestroyNotify destroy_func); ++ ++/** ++ * cogl_dma_buf_handle_free: (skip) ++ * ++ * Releases @dmabuf_handle; it is a programming error to release ++ * an already released handle. ++ */ ++void ++cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle); ++ ++/** ++ * cogl_dma_buf_handle_get_framebuffer: (skip) ++ * ++ * Retrieves the #CoglFramebuffer, backed by an exported DMABuf buffer, ++ * of @dmabuf_handle. ++ * ++ * Returns: (transfer none): a #CoglFramebuffer ++ */ ++CoglFramebuffer * ++cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle); ++ ++/** ++ * cogl_dma_buf_handle_get_fd: (skip) ++ * ++ * Retrieves the file descriptor of @dmabuf_handle. ++ * ++ * Returns: a valid file descriptor ++ */ ++int ++cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle); ++ ++ ++#endif /* __COGL_DMA_BUF_HANDLE_H__ */ +diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c +index 854aa1fdd..8c2ff0702 100644 +--- a/cogl/cogl/cogl-renderer.c ++++ b/cogl/cogl/cogl-renderer.c +@@ -838,3 +838,17 @@ cogl_renderer_foreach_output (CoglRenderer *renderer, + for (l = renderer->outputs; l; l = l->next) + callback (l->data, user_data); + } ++ ++CoglDmaBufHandle * ++cogl_renderer_create_dma_buf (CoglRenderer *renderer, ++ int width, ++ int height, ++ GError **error) ++{ ++ const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer); ++ ++ if (winsys->renderer_create_dma_buf) ++ return winsys->renderer_create_dma_buf (renderer, width, height, error); ++ ++ return NULL; ++} +diff --git a/cogl/cogl/cogl-renderer.h b/cogl/cogl/cogl-renderer.h +index 0b3ddb8f2..c5e904106 100644 +--- a/cogl/cogl/cogl-renderer.h ++++ b/cogl/cogl/cogl-renderer.h +@@ -418,6 +418,27 @@ cogl_renderer_foreach_output (CoglRenderer *renderer, + CoglOutputCallback callback, + void *user_data); + ++/** ++ * cogl_renderer_create_dma_buf: (skip) ++ * @renderer: A #CoglRenderer ++ * @width: width of the new ++ * @height: height of the new ++ * @error: (nullable): return location for a #GError ++ * ++ * Creates a new #CoglFramebuffer with @width x @height, and format ++ * hardcoded to XRGB, and exports the new framebuffer's DMA buffer ++ * handle. ++ * ++ * Returns: (nullable)(transfer full): a #CoglDmaBufHandle. The ++ * return result must be released with cogl_dma_buf_handle_free() ++ * after use. ++ */ ++CoglDmaBufHandle * ++cogl_renderer_create_dma_buf (CoglRenderer *renderer, ++ int width, ++ int height, ++ GError **error); ++ + G_END_DECLS + + #endif /* __COGL_RENDERER_H__ */ +diff --git a/cogl/cogl/cogl-types.h b/cogl/cogl/cogl-types.h +index 69d304cf0..1d420dc2c 100644 +--- a/cogl/cogl/cogl-types.h ++++ b/cogl/cogl/cogl-types.h +@@ -138,6 +138,14 @@ typedef int32_t CoglAngle; + typedef struct _CoglColor CoglColor; + typedef struct _CoglTextureVertex CoglTextureVertex; + ++/** ++ * CoglDmaBufHandle: (skip) ++ * ++ * An opaque type that tracks the lifetime of a DMA buffer fd. Release ++ * with cogl_dma_buf_handle_free(). ++ */ ++typedef struct _CoglDmaBufHandle CoglDmaBufHandle; ++ + /* Enum declarations */ + + #define COGL_A_BIT (1 << 4) +diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h +index 565ea289a..065278d36 100644 +--- a/cogl/cogl/cogl.h ++++ b/cogl/cogl/cogl.h +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build +index 8032669e4..1934e7574 100644 +--- a/cogl/cogl/meson.build ++++ b/cogl/cogl/meson.build +@@ -102,6 +102,7 @@ cogl_nonintrospected_headers = [ + 'cogl-renderer.h', + 'cogl-swap-chain.h', + 'cogl-onscreen-template.h', ++ 'cogl-dma-buf-handle.h', + 'cogl-display.h', + 'cogl-context.h', + 'cogl-snippet.h', +@@ -217,6 +218,7 @@ cogl_sources = [ + 'cogl-i18n-private.h', + 'cogl-debug.h', + 'cogl-debug-options.h', ++ 'cogl-dma-buf-handle.c', + 'cogl-gpu-info.c', + 'cogl-gpu-info-private.h', + 'cogl-context-private.h', +diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h +index c6b2f3579..59c8945ce 100644 +--- a/cogl/cogl/winsys/cogl-winsys-private.h ++++ b/cogl/cogl/winsys/cogl-winsys-private.h +@@ -100,6 +100,12 @@ typedef struct _CoglWinsysVtable + void + (*display_destroy) (CoglDisplay *display); + ++ CoglDmaBufHandle * ++ (*renderer_create_dma_buf) (CoglRenderer *renderer, ++ int width, ++ int height, ++ GError **error); ++ + gboolean + (*context_init) (CoglContext *context, CoglError **error); + +-- +2.26.2 + + +From aee3b6d1933375b9b8fb144c523a6227cd935142 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 9 Dec 2019 10:04:56 -0300 +Subject: [PATCH 26/49] renderer-native: Move DMA buffer creation to an + auxiliary function + +This will be reused by the DMA buffer exporting function. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/native/meta-renderer-native.c | 92 +++++++++++++++++++--- + 1 file changed, 83 insertions(+), 9 deletions(-) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index 76cc79e23..75d6ec4c2 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -2214,6 +2214,89 @@ wait_for_pending_flips (CoglOnscreen *onscreen) + meta_gpu_kms_wait_for_flip (onscreen_native->render_gpu, NULL); + } + ++static CoglContext * ++cogl_context_from_renderer_native (MetaRendererNative *renderer_native) ++{ ++ MetaBackend *backend = backend_from_renderer_native (renderer_native); ++ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ++ ++ return clutter_backend_get_cogl_context (clutter_backend); ++} ++ ++static CoglFramebuffer * ++create_dma_buf_framebuffer (MetaRendererNative *renderer_native, ++ int dmabuf_fd, ++ uint32_t width, ++ uint32_t height, ++ uint32_t stride, ++ uint32_t offset, ++ uint64_t modifier, ++ uint32_t drm_format, ++ GError **error) ++{ ++ CoglContext *cogl_context = ++ cogl_context_from_renderer_native (renderer_native); ++ CoglDisplay *cogl_display = cogl_context->display; ++ CoglRenderer *cogl_renderer = cogl_display->renderer; ++ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; ++ EGLDisplay egl_display = cogl_renderer_egl->edpy; ++ MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); ++ EGLImageKHR egl_image; ++ uint32_t strides[1]; ++ uint32_t offsets[1]; ++ uint64_t modifiers[1]; ++ CoglPixelFormat cogl_format; ++ CoglEglImageFlags flags; ++ CoglTexture2D *cogl_tex; ++ CoglOffscreen *cogl_fbo; ++ int ret; ++ ++ ret = cogl_pixel_format_from_drm_format (drm_format, &cogl_format, NULL); ++ g_assert (ret); ++ ++ strides[0] = stride; ++ offsets[0] = offset; ++ modifiers[0] = modifier; ++ egl_image = meta_egl_create_dmabuf_image (egl, ++ egl_display, ++ width, ++ height, ++ drm_format, ++ 1 /* n_planes */, ++ &dmabuf_fd, ++ strides, ++ offsets, ++ modifiers, ++ error); ++ if (egl_image == EGL_NO_IMAGE_KHR) ++ return NULL; ++ ++ flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA; ++ cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context, ++ width, ++ height, ++ cogl_format, ++ egl_image, ++ flags, ++ error); ++ ++ meta_egl_destroy_image (egl, egl_display, egl_image, NULL); ++ ++ if (!cogl_tex) ++ return NULL; ++ ++ cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex)); ++ cogl_object_unref (cogl_tex); ++ ++ if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error)) ++ { ++ cogl_object_unref (cogl_fbo); ++ return NULL; ++ } ++ ++ return COGL_FRAMEBUFFER (cogl_fbo); ++} ++ + static void + copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, + MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, +@@ -3457,15 +3540,6 @@ calculate_view_transform (MetaMonitorManager *monitor_manager, + return crtc_transform; + } + +-static CoglContext * +-cogl_context_from_renderer_native (MetaRendererNative *renderer_native) +-{ +- MetaBackend *backend = backend_from_renderer_native (renderer_native); +- ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); +- +- return clutter_backend_get_cogl_context (clutter_backend); +-} +- + static gboolean + should_force_shadow_fb (MetaRendererNative *renderer_native, + MetaGpuKms *primary_gpu) +-- +2.26.2 + + +From 1eab96d6e3813ec5745e882d9a195adf4a226ff6 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 9 Dec 2019 10:05:37 -0300 +Subject: [PATCH 27/49] renderer-native: Implement DMA buffer creation + +Create a new gbm_bo using the same given geometry, and export the new +bo's DMA buffer fd. The new bo lives as long as necessary to be used, +and reused, by PipeWire. + +Unfortunately, PipeWire doesn't support modifiers properly, so use the +linear format for now. For now, a hardcoded format of DRM_FORMAT_XRGB8888 +is set, so we don't need to negotiate the format with PipeWire early. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/native/meta-renderer-native.c | 68 ++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + +diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c +index 75d6ec4c2..ba98de650 100644 +--- a/src/backends/native/meta-renderer-native.c ++++ b/src/backends/native/meta-renderer-native.c +@@ -2618,6 +2618,73 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, + _cogl_winsys_egl_ensure_current (cogl_display); + } + ++static CoglDmaBufHandle * ++meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, ++ int width, ++ int height, ++ GError **error) ++{ ++ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; ++ MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; ++ MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; ++ ++ switch (renderer_gpu_data->mode) ++ { ++ case META_RENDERER_NATIVE_MODE_GBM: ++ { ++ CoglFramebuffer *dmabuf_fb; ++ struct gbm_bo *new_bo; ++ int dmabuf_fd = -1; ++ ++ new_bo = gbm_bo_create (renderer_gpu_data->gbm.device, ++ width, height, DRM_FORMAT_XRGB8888, ++ GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); ++ ++ if (!new_bo) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Failed to allocate buffer"); ++ return NULL; ++ } ++ ++ dmabuf_fd = gbm_bo_get_fd (new_bo); ++ ++ if (dmabuf_fd == -1) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, ++ "Failed to export buffer's DMA fd: %s", ++ g_strerror (errno)); ++ return NULL; ++ } ++ ++ dmabuf_fb = create_dma_buf_framebuffer (renderer_native, ++ dmabuf_fd, ++ width, height, ++ gbm_bo_get_stride (new_bo), ++ gbm_bo_get_offset (new_bo, 0), ++ DRM_FORMAT_MOD_LINEAR, ++ DRM_FORMAT_XRGB8888, ++ error); ++ ++ if (!dmabuf_fb) ++ return NULL; ++ ++ return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo, ++ (GDestroyNotify) gbm_bo_destroy); ++ } ++ break; ++#ifdef HAVE_EGL_DEVICE ++ case META_RENDERER_NATIVE_MODE_EGL_DEVICE: ++ break; ++#endif ++ } ++ ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, ++ "Current mode does not support exporting DMA buffers"); ++ ++ return NULL; ++} ++ + static gboolean + meta_renderer_native_init_egl_context (CoglContext *cogl_context, + GError **error) +@@ -3461,6 +3528,7 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) + + vtable.renderer_connect = meta_renderer_native_connect; + vtable.renderer_disconnect = meta_renderer_native_disconnect; ++ vtable.renderer_create_dma_buf = meta_renderer_native_create_dma_buf; + + vtable.onscreen_init = meta_renderer_native_init_onscreen; + vtable.onscreen_deinit = meta_renderer_native_release_onscreen; +-- +2.26.2 + + +From a8503b2e8b5573f9decf97264a26877adf65c4c0 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 9 Dec 2019 10:07:29 -0300 +Subject: [PATCH 28/49] screen-cast-stream-src: Support DMA buffer sharing + +Implement PipeWire's add_buffer and remove buffer, try and export +a DMA buffer first and, on failure, fallback to memfd. + +When DMA buffers are successfully created and shared, blit the +framebuffer contents when drawing instead of downloading the pixels. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/meta-screen-cast-stream-src.c | 189 ++++++++++++++++++--- + src/backends/meta-screen-cast-stream-src.h | 2 + + 2 files changed, 164 insertions(+), 27 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index ba1ce94a7..0eb9f4d8c 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -25,6 +25,7 @@ + #include "backends/meta-screen-cast-stream-src.h" + + #include ++#include + #include + #include + #include +@@ -90,6 +91,8 @@ typedef struct _MetaScreenCastStreamSrcPrivate + + uint64_t last_frame_timestamp_us; + ++ GHashTable *dmabuf_handles; ++ + int stream_width; + int stream_height; + } MetaScreenCastStreamSrcPrivate; +@@ -139,6 +142,19 @@ meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src, + return klass->record_frame (src, data); + } + ++static gboolean ++meta_screen_cast_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src, ++ CoglFramebuffer *framebuffer) ++{ ++ MetaScreenCastStreamSrcClass *klass = ++ META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); ++ ++ if (klass->blit_to_framebuffer) ++ return klass->blit_to_framebuffer (src, framebuffer); ++ ++ return FALSE; ++} ++ + static void + meta_screen_cast_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +@@ -394,6 +410,33 @@ maybe_record_cursor (MetaScreenCastStreamSrc *src, + g_assert_not_reached (); + } + ++static gboolean ++do_record_frame (MetaScreenCastStreamSrc *src, ++ struct spa_buffer *spa_buffer, ++ uint8_t *data) ++{ ++ MetaScreenCastStreamSrcPrivate *priv = ++ meta_screen_cast_stream_src_get_instance_private (src); ++ ++ if (spa_buffer->datas[0].data || ++ spa_buffer->datas[0].type == SPA_DATA_MemFd) ++ { ++ return meta_screen_cast_stream_src_record_frame (src, data); ++ } ++ else if (spa_buffer->datas[0].type == SPA_DATA_DmaBuf) ++ { ++ CoglDmaBufHandle *dmabuf_handle = ++ g_hash_table_lookup (priv->dmabuf_handles, ++ GINT_TO_POINTER (spa_buffer->datas[0].fd)); ++ CoglFramebuffer *dmabuf_fbo = ++ cogl_dma_buf_handle_get_framebuffer (dmabuf_handle); ++ ++ return meta_screen_cast_stream_src_blit_to_framebuffer (src, dmabuf_fbo); ++ } ++ ++ return FALSE; ++} ++ + void + meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + { +@@ -402,8 +445,7 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + MetaRectangle crop_rect; + struct pw_buffer *buffer; + struct spa_buffer *spa_buffer; +- uint8_t *map = NULL; +- uint8_t *data; ++ uint8_t *data = NULL; + uint64_t now_us; + + now_us = g_get_monotonic_time (); +@@ -424,32 +466,15 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + } + + spa_buffer = buffer->buffer; ++ data = spa_buffer->datas[0].data; + +- if (spa_buffer->datas[0].data) +- { +- data = spa_buffer->datas[0].data; +- } +- else if (spa_buffer->datas[0].type == SPA_DATA_MemFd) ++ if (spa_buffer->datas[0].type != SPA_DATA_DmaBuf && !data) + { +- map = mmap (NULL, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset, +- PROT_READ | PROT_WRITE, MAP_SHARED, +- spa_buffer->datas[0].fd, 0); +- if (map == MAP_FAILED) +- { +- g_warning ("Failed to mmap pipewire stream buffer: %s", +- strerror (errno)); +- return; +- } +- +- data = SPA_MEMBER (map, spa_buffer->datas[0].mapoffset, uint8_t); +- } +- else +- { +- g_warning ("Unhandled spa buffer type: %d", spa_buffer->datas[0].type); ++ g_critical ("Invalid buffer data"); + return; + } + +- if (meta_screen_cast_stream_src_record_frame (src, data)) ++ if (do_record_frame (src, spa_buffer, data)) + { + struct spa_meta_region *spa_meta_video_crop; + +@@ -487,9 +512,6 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + + priv->last_frame_timestamp_us = now_us; + +- if (map) +- munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset); +- + pw_stream_queue_buffer (priv->pipewire_stream, buffer); + } + +@@ -618,10 +640,116 @@ on_stream_param_changed (void *data, + pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params)); + } + ++static void ++on_stream_add_buffer (void *data, ++ struct pw_buffer *buffer) ++{ ++ MetaScreenCastStreamSrc *src = data; ++ MetaScreenCastStreamSrcPrivate *priv = ++ meta_screen_cast_stream_src_get_instance_private (src); ++ CoglContext *context = ++ clutter_backend_get_cogl_context (clutter_get_default_backend ()); ++ CoglRenderer *renderer = cogl_context_get_renderer (context); ++ g_autoptr (GError) error = NULL; ++ CoglDmaBufHandle *dmabuf_handle; ++ struct spa_buffer *spa_buffer = buffer->buffer; ++ struct spa_data *spa_data = spa_buffer->datas; ++ const int bpp = 4; ++ int stride; ++ ++ stride = SPA_ROUND_UP_N (priv->video_format.size.width * bpp, 4); ++ ++ spa_data[0].mapoffset = 0; ++ spa_data[0].maxsize = stride * priv->video_format.size.height; ++ ++ dmabuf_handle = cogl_renderer_create_dma_buf (renderer, ++ priv->stream_width, ++ priv->stream_height, ++ &error); ++ ++ if (error) ++ g_debug ("Error exporting DMA buffer handle: %s", error->message); ++ ++ if (dmabuf_handle) ++ { ++ spa_data[0].type = SPA_DATA_DmaBuf; ++ spa_data[0].flags = SPA_DATA_FLAG_READWRITE; ++ spa_data[0].fd = cogl_dma_buf_handle_get_fd (dmabuf_handle); ++ spa_data[0].data = NULL; ++ ++ g_hash_table_insert (priv->dmabuf_handles, ++ GINT_TO_POINTER (spa_data[0].fd), ++ dmabuf_handle); ++ } ++ else ++ { ++ unsigned int seals; ++ ++ /* Fallback to a memfd buffer */ ++ spa_data[0].type = SPA_DATA_MemFd; ++ spa_data[0].flags = SPA_DATA_FLAG_READWRITE; ++ spa_data[0].fd = memfd_create ("mutter-screen-cast-memfd", ++ MFD_CLOEXEC | MFD_ALLOW_SEALING); ++ if (spa_data[0].fd == -1) ++ { ++ g_critical ("Can't create memfd: %m"); ++ return; ++ } ++ spa_data[0].mapoffset = 0; ++ spa_data[0].maxsize = stride * priv->video_format.size.height; ++ ++ if (ftruncate (spa_data[0].fd, spa_data[0].maxsize) < 0) ++ { ++ g_critical ("Can't truncate to %d: %m", spa_data[0].maxsize); ++ return; ++ } ++ ++ seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; ++ if (fcntl (spa_data[0].fd, F_ADD_SEALS, seals) == -1) ++ g_warning ("Failed to add seals: %m"); ++ ++ spa_data[0].data = mmap (NULL, ++ spa_data[0].maxsize, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, ++ spa_data[0].fd, ++ spa_data[0].mapoffset); ++ if (spa_data[0].data == MAP_FAILED) ++ { ++ g_critical ("Failed to mmap memory: %m"); ++ return; ++ } ++ } ++} ++ ++static void ++on_stream_remove_buffer (void *data, ++ struct pw_buffer *buffer) ++{ ++ MetaScreenCastStreamSrc *src = data; ++ MetaScreenCastStreamSrcPrivate *priv = ++ meta_screen_cast_stream_src_get_instance_private (src); ++ struct spa_buffer *spa_buffer = buffer->buffer; ++ struct spa_data *spa_data = spa_buffer->datas; ++ ++ if (spa_data[0].type == SPA_DATA_DmaBuf) ++ { ++ if (!g_hash_table_remove (priv->dmabuf_handles, GINT_TO_POINTER (spa_data[0].fd))) ++ g_critical ("Failed to remove non-exported DMA buffer"); ++ } ++ else if (spa_data[0].type == SPA_DATA_MemFd) ++ { ++ munmap (spa_data[0].data, spa_data[0].maxsize); ++ close (spa_data[0].fd); ++ } ++} ++ + static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .state_changed = on_stream_state_changed, + .param_changed = on_stream_param_changed, ++ .add_buffer = on_stream_add_buffer, ++ .remove_buffer = on_stream_remove_buffer, + }; + + static struct pw_stream * +@@ -686,7 +814,7 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, + PW_DIRECTION_OUTPUT, + SPA_ID_INVALID, + (PW_STREAM_FLAG_DRIVER | +- PW_STREAM_FLAG_MAP_BUFFERS), ++ PW_STREAM_FLAG_ALLOC_BUFFERS), + params, G_N_ELEMENTS (params)); + if (result != 0) + { +@@ -854,6 +982,7 @@ meta_screen_cast_stream_src_finalize (GObject *object) + if (meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_disable (src); + ++ g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy); + g_clear_pointer (&priv->pipewire_stream, pw_stream_destroy); + g_clear_pointer (&priv->pipewire_core, pw_core_disconnect); + g_clear_pointer (&priv->pipewire_context, pw_context_destroy); +@@ -905,6 +1034,12 @@ meta_screen_cast_stream_src_get_property (GObject *object, + static void + meta_screen_cast_stream_src_init (MetaScreenCastStreamSrc *src) + { ++ MetaScreenCastStreamSrcPrivate *priv = ++ meta_screen_cast_stream_src_get_instance_private (src); ++ ++ priv->dmabuf_handles = ++ g_hash_table_new_full (NULL, NULL, NULL, ++ (GDestroyNotify) cogl_dma_buf_handle_free); + } + + static void +diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h +index fc0e5bc77..3f6a1af2b 100644 +--- a/src/backends/meta-screen-cast-stream-src.h ++++ b/src/backends/meta-screen-cast-stream-src.h +@@ -55,6 +55,8 @@ struct _MetaScreenCastStreamSrcClass + void (* disable) (MetaScreenCastStreamSrc *src); + gboolean (* record_frame) (MetaScreenCastStreamSrc *src, + uint8_t *data); ++ gboolean (* blit_to_framebuffer) (MetaScreenCastStreamSrc *src, ++ CoglFramebuffer *framebuffer); + gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src, + MetaRectangle *crop_rect); + void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src, +-- +2.26.2 + + +From b25135cdeda1ee1aa26bb645ba981478c823d413 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 9 Dec 2019 10:11:51 -0300 +Subject: [PATCH 29/49] monitor-stream-src: Implement blitting view + framebuffers + +Add the vfunc override that actually consume the new Cogl API. Every +view that fits into the logical monitor is rendered. + +Fixes https://gitlab.gnome.org/GNOME/mutter/issues/639 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + .../meta-screen-cast-monitor-stream-src.c | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c +index f582217e5..0c7d8ec17 100644 +--- a/src/backends/meta-screen-cast-monitor-stream-src.c ++++ b/src/backends/meta-screen-cast-monitor-stream-src.c +@@ -367,6 +367,66 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src, + return TRUE; + } + ++static gboolean ++meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src, ++ CoglFramebuffer *framebuffer) ++{ ++ MetaScreenCastMonitorStreamSrc *monitor_src = ++ META_SCREEN_CAST_MONITOR_STREAM_SRC (src); ++ MetaBackend *backend = get_backend (monitor_src); ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ MetaMonitor *monitor; ++ MetaLogicalMonitor *logical_monitor; ++ MetaRectangle logical_monitor_layout; ++ GList *l; ++ float view_scale; ++ ++ monitor = get_monitor (monitor_src); ++ logical_monitor = meta_monitor_get_logical_monitor (monitor); ++ logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor); ++ ++ if (meta_is_stage_views_scaled ()) ++ view_scale = meta_logical_monitor_get_scale (logical_monitor); ++ else ++ view_scale = 1.0; ++ ++ for (l = meta_renderer_get_views (renderer); l; l = l->next) ++ { ++ ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data); ++ g_autoptr (GError) error = NULL; ++ CoglFramebuffer *view_framebuffer; ++ MetaRectangle view_layout; ++ int x, y; ++ ++ clutter_stage_view_get_layout (view, &view_layout); ++ ++ if (!meta_rectangle_overlap (&logical_monitor_layout, &view_layout)) ++ continue; ++ ++ view_framebuffer = clutter_stage_view_get_framebuffer (view); ++ ++ x = (int) roundf ((view_layout.x - logical_monitor_layout.x) * view_scale); ++ y = (int) roundf ((view_layout.y - logical_monitor_layout.y) * view_scale); ++ ++ if (!cogl_blit_framebuffer (view_framebuffer, ++ framebuffer, ++ 0, 0, ++ x, y, ++ cogl_framebuffer_get_width (view_framebuffer), ++ cogl_framebuffer_get_height (view_framebuffer), ++ &error)) ++ { ++ g_warning ("Error blitting view into DMABuf framebuffer: %s", ++ error->message); ++ return FALSE; ++ } ++ } ++ ++ cogl_framebuffer_flush (framebuffer); ++ ++ return TRUE; ++} ++ + static void + meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +@@ -492,6 +552,8 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl + src_class->enable = meta_screen_cast_monitor_stream_src_enable; + src_class->disable = meta_screen_cast_monitor_stream_src_disable; + src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame; ++ src_class->blit_to_framebuffer = ++ meta_screen_cast_monitor_stream_src_blit_to_framebuffer; + src_class->set_cursor_metadata = + meta_screen_cast_monitor_stream_src_set_cursor_metadata; + } +-- +2.26.2 + + +From 7806ab62bbf51e2ca884b17a314c74b38f3ae9c5 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Fri, 28 Feb 2020 12:23:15 -0300 +Subject: [PATCH 30/49] window-stream-source: Draw into DMA buffer image + +Much like monitor streaming, implement window streaming by +making the window actor draw itself with a paint context +that used the passed framebuffer. + +Now that all MetaScreenCastStreamSrc subclasses implement +blit_to_framebuffer, remove the conditional check from +meta_screen_cast_stream_src_blit_to_framebuffer(). + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/meta-screen-cast-stream-src.c | 5 +- + .../meta-screen-cast-window-stream-src.c | 21 +++++++ + src/backends/meta-screen-cast-window.c | 11 ++++ + src/backends/meta-screen-cast-window.h | 8 +++ + src/compositor/meta-window-actor.c | 63 +++++++++++++++++++ + 5 files changed, 104 insertions(+), 4 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 0eb9f4d8c..6f7551ad4 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -149,10 +149,7 @@ meta_screen_cast_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src, + MetaScreenCastStreamSrcClass *klass = + META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); + +- if (klass->blit_to_framebuffer) +- return klass->blit_to_framebuffer (src, framebuffer); +- +- return FALSE; ++ return klass->blit_to_framebuffer (src, framebuffer); + } + + static void +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index 210ea0807..3f9cab694 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -412,6 +412,25 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src, + return TRUE; + } + ++static gboolean ++meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src, ++ CoglFramebuffer *framebuffer) ++{ ++ MetaScreenCastWindowStreamSrc *window_src = ++ META_SCREEN_CAST_WINDOW_STREAM_SRC (src); ++ MetaRectangle stream_rect; ++ ++ stream_rect.x = 0; ++ stream_rect.y = 0; ++ stream_rect.width = get_stream_width (window_src); ++ stream_rect.height = get_stream_height (window_src); ++ ++ return ++ meta_screen_cast_window_blit_to_framebuffer (window_src->screen_cast_window, ++ &stream_rect, ++ framebuffer); ++} ++ + static void + meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +@@ -496,6 +515,8 @@ meta_screen_cast_window_stream_src_class_init (MetaScreenCastWindowStreamSrcClas + src_class->enable = meta_screen_cast_window_stream_src_enable; + src_class->disable = meta_screen_cast_window_stream_src_disable; + src_class->record_frame = meta_screen_cast_window_stream_src_record_frame; ++ src_class->blit_to_framebuffer = ++ meta_screen_cast_window_stream_src_blit_to_framebuffer; + src_class->get_videocrop = meta_screen_cast_window_stream_src_get_videocrop; + src_class->set_cursor_metadata = meta_screen_cast_window_stream_src_set_cursor_metadata; + } +diff --git a/src/backends/meta-screen-cast-window.c b/src/backends/meta-screen-cast-window.c +index 91515ded8..50b65a5df 100644 +--- a/src/backends/meta-screen-cast-window.c ++++ b/src/backends/meta-screen-cast-window.c +@@ -78,6 +78,17 @@ meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window, + data); + } + ++gboolean ++meta_screen_cast_window_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds, ++ CoglFramebuffer *framebuffer) ++{ ++ MetaScreenCastWindowInterface *iface = ++ META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window); ++ ++ return iface->blit_to_framebuffer (screen_cast_window, bounds, framebuffer); ++} ++ + gboolean + meta_screen_cast_window_has_damage (MetaScreenCastWindow *screen_cast_window) + { +diff --git a/src/backends/meta-screen-cast-window.h b/src/backends/meta-screen-cast-window.h +index 69e5a34dc..45b681292 100644 +--- a/src/backends/meta-screen-cast-window.h ++++ b/src/backends/meta-screen-cast-window.h +@@ -56,6 +56,10 @@ struct _MetaScreenCastWindowInterface + MetaRectangle *bounds, + uint8_t *data); + ++ gboolean (*blit_to_framebuffer) (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds, ++ CoglFramebuffer *framebuffer); ++ + gboolean (*has_damage) (MetaScreenCastWindow *screen_cast_window); + }; + +@@ -78,6 +82,10 @@ void meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_win + MetaRectangle *bounds, + uint8_t *data); + ++gboolean meta_screen_cast_window_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds, ++ CoglFramebuffer *framebuffer); ++ + gboolean meta_screen_cast_window_has_damage (MetaScreenCastWindow *screen_cast_window); + + G_END_DECLS +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 81eb04c84..a7dc25004 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2025,6 +2025,68 @@ meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, + cairo_surface_destroy (image); + } + ++static gboolean ++meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, ++ MetaRectangle *bounds, ++ CoglFramebuffer *framebuffer) ++{ ++ MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); ++ ClutterActor *actor = CLUTTER_ACTOR (window_actor); ++ MetaRectangle scaled_clip; ++ CoglColor clear_color; ++ float resource_scale; ++ float width, height; ++ float x, y; ++ ++ if (meta_window_actor_is_destroyed (window_actor)) ++ return FALSE; ++ ++ clutter_actor_get_size (actor, &width, &height); ++ ++ if (width == 0 || height == 0) ++ return FALSE; ++ ++ if (!clutter_actor_get_resource_scale (actor, &resource_scale)) ++ return FALSE; ++ ++ width = ceilf (width * resource_scale); ++ height = ceilf (height * resource_scale); ++ ++ cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); ++ clutter_actor_get_position (actor, &x, &y); ++ ++ cogl_framebuffer_push_matrix (framebuffer); ++ ++ cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); ++ cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); ++ cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); ++ cogl_framebuffer_translate (framebuffer, -x, -y, 0); ++ ++ meta_rectangle_scale_double (bounds, resource_scale, ++ META_ROUNDING_STRATEGY_GROW, ++ &scaled_clip); ++ meta_rectangle_intersect (&scaled_clip, ++ &(MetaRectangle) { ++ .width = width, ++ .height = height, ++ }, ++ &scaled_clip); ++ ++ cogl_framebuffer_push_rectangle_clip (framebuffer, ++ scaled_clip.x, scaled_clip.y, ++ scaled_clip.x + scaled_clip.width, ++ scaled_clip.y + scaled_clip.height); ++ ++ cogl_push_framebuffer (framebuffer); ++ clutter_actor_paint (actor); ++ cogl_pop_framebuffer (); ++ ++ cogl_framebuffer_pop_clip (framebuffer); ++ cogl_framebuffer_pop_matrix (framebuffer); ++ ++ return TRUE; ++} ++ + static gboolean + meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window) + { +@@ -2038,6 +2100,7 @@ screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface) + iface->transform_relative_position = meta_window_actor_transform_relative_position; + iface->transform_cursor_position = meta_window_actor_transform_cursor_position; + iface->capture_into = meta_window_actor_capture_into; ++ iface->blit_to_framebuffer = meta_window_actor_blit_to_framebuffer; + iface->has_damage = meta_window_actor_has_damage; + } + +-- +2.26.2 + + +From d005b89e4846aeaca01568865dd7d440f036c783 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 24 Feb 2020 14:14:07 -0300 +Subject: [PATCH 31/49] screen-cast-stream-src: Remove unused parameter + +The 'data' parameter is not used in maybe_record_cursor(), so remove +it. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/meta-screen-cast-stream-src.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 6f7551ad4..9c3657c75 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -389,8 +389,7 @@ add_cursor_metadata (MetaScreenCastStreamSrc *src, + + static void + maybe_record_cursor (MetaScreenCastStreamSrc *src, +- struct spa_buffer *spa_buffer, +- uint8_t *data) ++ struct spa_buffer *spa_buffer) + { + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + +@@ -505,7 +504,7 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + spa_buffer->datas[0].chunk->size = 0; + } + +- maybe_record_cursor (src, spa_buffer, data); ++ maybe_record_cursor (src, spa_buffer); + + priv->last_frame_timestamp_us = now_us; + +-- +2.26.2 + + +From 0b8f27b4adf72ade1c8f5e958d9fcf31a9063d94 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Fri, 28 Feb 2020 15:47:23 -0300 +Subject: [PATCH 32/49] monitor-stream-src: Use cogl_framebuffer_finish() + +Even though cogl_framebuffer_flush() was supposed to be enough, +it ends up creating streams with odd visual glitches that look +very much like unfinished frames. + +Switch back to cogl_framebuffer_finish(), which is admittedly +an overkill, but it's what works for now. There is anedoctal +evidence showing it doesn't incur in worse performance. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086 +--- + src/backends/meta-screen-cast-monitor-stream-src.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c +index 0c7d8ec17..af763dc09 100644 +--- a/src/backends/meta-screen-cast-monitor-stream-src.c ++++ b/src/backends/meta-screen-cast-monitor-stream-src.c +@@ -422,7 +422,7 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + } + } + +- cogl_framebuffer_flush (framebuffer); ++ cogl_framebuffer_finish (framebuffer); + + return TRUE; + } +-- +2.26.2 + + +From 1b9704405568f1a52168ce8c5267fe9a5ab1f789 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 9 Mar 2020 17:43:54 +0100 +Subject: [PATCH 33/49] screen-cast-stream-src: Don't complain when we can't + dequeue buffer + +PipeWire will be unable to dequeue a buffer if all are already busy. +This can happen for valid reasons, e.g. the stream consumer not being +fast enough, so don't complain in the journal if it happens. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1115 +--- + src/backends/meta-screen-cast-stream-src.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 9c3657c75..170f34043 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -456,10 +456,7 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + + buffer = pw_stream_dequeue_buffer (priv->pipewire_stream); + if (!buffer) +- { +- g_warning ("Failed to dequeue at PipeWire buffer"); +- return; +- } ++ return; + + spa_buffer = buffer->buffer; + data = spa_buffer->datas[0].data; +-- +2.26.2 + + +From 99a671e71cedcb3ef3093d0afcc823bfdd8eaf79 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 5 Mar 2020 23:29:26 +0100 +Subject: [PATCH 34/49] screen-cast-stream-src: Don't leak GSource + +For every stream src, we created and attached a GSource. Upon stream +src destruction, we g_source_destroy():ed the GSource. What +g_source_destroy() does, hawever, is not really "destroy" it but only +detaches it from the main context removing the reference the context had +added for it via g_source_attach(). This caused the GSource to leak, +although in a detached state, as the reference taken on creation was +still held. + +Fix this by also removing our own reference to it when finalizing. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1106 +--- + src/backends/meta-screen-cast-stream-src.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 170f34043..4f3d821ef 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -885,7 +885,7 @@ create_pipewire_source (void) + pipewire_source->pipewire_loop = pw_loop_new (NULL); + if (!pipewire_source->pipewire_loop) + { +- g_source_destroy ((GSource *) pipewire_source); ++ g_source_unref ((GSource *) pipewire_source); + return NULL; + } + +@@ -980,6 +980,7 @@ meta_screen_cast_stream_src_finalize (GObject *object) + g_clear_pointer (&priv->pipewire_core, pw_core_disconnect); + g_clear_pointer (&priv->pipewire_context, pw_context_destroy); + g_source_destroy (&priv->pipewire_source->base); ++ g_source_unref (&priv->pipewire_source->base); + + G_OBJECT_CLASS (meta_screen_cast_stream_src_parent_class)->finalize (object); + } +-- +2.26.2 + + +From 6af35cad8bc09c291c29fffb08fe8ba3b76b779e Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 16 Mar 2020 19:47:30 -0300 +Subject: [PATCH 35/49] window-actor: Shuffle some lines around + +Move the CoglColor assignment right above the cogl_framebuffer_clear() call, +and let these wonderful partners together to delight us with an easier to +read code. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + src/compositor/meta-window-actor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index a7dc25004..f90d2b0af 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2052,11 +2052,11 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + width = ceilf (width * resource_scale); + height = ceilf (height * resource_scale); + +- cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + clutter_actor_get_position (actor, &x, &y); + + cogl_framebuffer_push_matrix (framebuffer); + ++ cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); + cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); +-- +2.26.2 + + +From 4ecb19fffd37786d6b8efc3b05e7239bee49e763 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 16 Mar 2020 19:55:16 -0300 +Subject: [PATCH 36/49] window-actor: Clip before translate when blitting + +cogl_framebuffer_push_rectangle_clip() acts on the current modelview +matrix. That means the result of clipping then translating will be +different of the result of translating then clipping. + +What we want for window screencasting is the former, not the latter. +Move the translation code (and associated) to after clipping. + +Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/1097 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + src/compositor/meta-window-actor.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index f90d2b0af..c9ef5846a 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2054,13 +2054,9 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + + clutter_actor_get_position (actor, &x, &y); + +- cogl_framebuffer_push_matrix (framebuffer); +- + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); +- cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); +- cogl_framebuffer_translate (framebuffer, -x, -y, 0); + + meta_rectangle_scale_double (bounds, resource_scale, + META_ROUNDING_STRATEGY_GROW, +@@ -2077,12 +2073,16 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + scaled_clip.x + scaled_clip.width, + scaled_clip.y + scaled_clip.height); + ++ cogl_framebuffer_push_matrix (framebuffer); ++ cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); ++ cogl_framebuffer_translate (framebuffer, -x, -y, 0); ++ + cogl_push_framebuffer (framebuffer); + clutter_actor_paint (actor); + cogl_pop_framebuffer (); + +- cogl_framebuffer_pop_clip (framebuffer); + cogl_framebuffer_pop_matrix (framebuffer); ++ cogl_framebuffer_pop_clip (framebuffer); + + return TRUE; + } +-- +2.26.2 + + +From 14f76043aa912b186ecbce0e5dae46f521fec10f Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Tue, 17 Mar 2020 16:55:39 -0300 +Subject: [PATCH 37/49] window-stream-src: Ensure initial frame is recorded + +MetaScreenCastWindowStreamSrc connects to the "damaged" signal of +MetaWindowActor. This signal is not exactly tied to the paint cycle +of the stage, and a damage may take quite a while to arrive when +a client doesn't want to draw anything. For that reason, the window +screencast can start empty, waiting for a damage to arrive. + +Ensure at least one frame is recorded when enabling the window stream. + +Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/1097 + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + src/backends/meta-screen-cast-window-stream-src.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index 3f9cab694..0e0907e82 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -389,6 +389,8 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src) + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } ++ ++ meta_screen_cast_stream_src_maybe_record_frame (src); + } + + static void +-- +2.26.2 + + +From 4c4324e21cc3739c6d0a384519f8b8a47d9d8216 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Tue, 17 Mar 2020 18:22:29 -0300 +Subject: [PATCH 38/49] window-stream-src: Implement cursor blitting + +A regression compared to the old code, we're not drawing the cursor +when on EMBEDDED mode. + +Blit the cursor to the screencast framebuffer when on EMBEDDED mode. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + .../meta-screen-cast-window-stream-src.c | 81 ++++++++++++++++++- + 1 file changed, 77 insertions(+), 4 deletions(-) + +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index 0e0907e82..87505b793 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -178,6 +178,65 @@ maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, + cairo_surface_destroy (cursor_surface); + } + ++static void ++maybe_blit_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, ++ CoglFramebuffer *framebuffer, ++ MetaRectangle *stream_rect) ++{ ++ MetaBackend *backend = get_backend (window_src); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_get_default_backend ()); ++ MetaCursorRenderer *cursor_renderer = ++ meta_backend_get_cursor_renderer (backend); ++ MetaScreenCastWindow *screen_cast_window; ++ MetaCursorSprite *cursor_sprite; ++ ClutterPoint relative_cursor_position; ++ ClutterPoint cursor_position; ++ CoglTexture *cursor_texture; ++ CoglPipeline *pipeline; ++ int width, height; ++ float scale; ++ int hotspot_x, hotspot_y; ++ float x, y; ++ ++ cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); ++ if (!cursor_sprite) ++ return; ++ ++ cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); ++ if (!cursor_texture) ++ return; ++ ++ screen_cast_window = window_src->screen_cast_window; ++ cursor_position = meta_cursor_renderer_get_position (cursor_renderer); ++ if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window, ++ cursor_sprite, ++ &cursor_position, ++ &scale, ++ &relative_cursor_position)) ++ return; ++ ++ meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); ++ ++ x = (relative_cursor_position.x - hotspot_x) * scale; ++ y = (relative_cursor_position.y - hotspot_y) * scale; ++ width = cogl_texture_get_width (cursor_texture); ++ height = cogl_texture_get_height (cursor_texture); ++ ++ pipeline = cogl_pipeline_new (cogl_context); ++ cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture); ++ cogl_pipeline_set_layer_filters (pipeline, 0, ++ COGL_PIPELINE_FILTER_LINEAR, ++ COGL_PIPELINE_FILTER_LINEAR); ++ ++ cogl_framebuffer_draw_rectangle (framebuffer, ++ pipeline, ++ x, y, ++ x + width, y + height); ++ ++ cogl_object_unref (pipeline); ++} ++ + static gboolean + capture_into (MetaScreenCastWindowStreamSrc *window_src, + uint8_t *data) +@@ -420,6 +479,7 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + { + MetaScreenCastWindowStreamSrc *window_src = + META_SCREEN_CAST_WINDOW_STREAM_SRC (src); ++ MetaScreenCastStream *stream; + MetaRectangle stream_rect; + + stream_rect.x = 0; +@@ -427,10 +487,23 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + stream_rect.width = get_stream_width (window_src); + stream_rect.height = get_stream_height (window_src); + +- return +- meta_screen_cast_window_blit_to_framebuffer (window_src->screen_cast_window, +- &stream_rect, +- framebuffer); ++ if (!meta_screen_cast_window_blit_to_framebuffer (window_src->screen_cast_window, ++ &stream_rect, ++ framebuffer)) ++ return FALSE; ++ ++ stream = meta_screen_cast_stream_src_get_stream (src); ++ switch (meta_screen_cast_stream_get_cursor_mode (stream)) ++ { ++ case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: ++ maybe_blit_cursor_sprite (window_src, framebuffer, &stream_rect); ++ break; ++ case META_SCREEN_CAST_CURSOR_MODE_METADATA: ++ case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: ++ break; ++ } ++ ++ return TRUE; + } + + static void +-- +2.26.2 + + +From f454e95162dd44feb1581b52521c637b378aa3bd Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Mon, 16 Mar 2020 19:31:25 -0300 +Subject: [PATCH 39/49] window-stream-src: Finish framebuffer after blitting + +Just like what's done for monitor screencasting. Unfortunately, there's +no mechanism to share fences with PipeWire clients yet, which forces +us to guarantee that a frame is completed after blitting. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + src/backends/meta-screen-cast-window-stream-src.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c +index 87505b793..c252b4356 100644 +--- a/src/backends/meta-screen-cast-window-stream-src.c ++++ b/src/backends/meta-screen-cast-window-stream-src.c +@@ -503,6 +503,8 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + break; + } + ++ cogl_framebuffer_finish (framebuffer); ++ + return TRUE; + } + +-- +2.26.2 + + +From 3658b9f61921b6568913966be5bd28ceb111c23b Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Wed, 18 Mar 2020 21:12:26 -0300 +Subject: [PATCH 40/49] clutter/actor: Add culling inhibiting API + +This will allow us to continue painting actors that are +outside the visible boundaries of the stage view. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + clutter/clutter/clutter-actor.c | 64 ++++++++++++++++++++++++++++++++- + clutter/clutter/clutter-actor.h | 5 +++ + 2 files changed, 68 insertions(+), 1 deletion(-) + +diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c +index 803f76aae..77a61ae1a 100644 +--- a/clutter/clutter/clutter-actor.c ++++ b/clutter/clutter/clutter-actor.c +@@ -703,6 +703,7 @@ struct _ClutterActorPrivate + + guint8 opacity; + gint opacity_override; ++ unsigned int inhibit_culling_counter; + + ClutterOffscreenRedirect offscreen_redirect; + +@@ -3824,6 +3825,7 @@ clutter_actor_paint (ClutterActor *self) + { + ClutterActorPrivate *priv; + ClutterPickMode pick_mode; ++ gboolean culling_inhibited; + gboolean clip_set = FALSE; + ClutterStage *stage; + +@@ -3973,7 +3975,10 @@ clutter_actor_paint (ClutterActor *self) + * paint then the last-paint-volume would likely represent the new + * actor position not the old. + */ +- if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE) ++ culling_inhibited = priv->inhibit_culling_counter > 0; ++ if (!culling_inhibited && ++ !in_clone_paint () && ++ pick_mode == CLUTTER_PICK_NONE) + { + gboolean success; + /* annoyingly gcc warns if uninitialized even though +@@ -16014,6 +16019,63 @@ clutter_actor_get_opacity_override (ClutterActor *self) + return self->priv->opacity_override; + } + ++/** ++ * clutter_actor_inhibit_culling: ++ * @actor: a #ClutterActor ++ * ++ * Increases the culling inhibitor counter. Inhibiting culling ++ * forces the actor to be painted even when outside the visible ++ * bounds of the stage view. ++ * ++ * This is usually necessary when an actor is being painted on ++ * another paint context. ++ * ++ * Pair with clutter_actor_uninhibit_culling() when the actor doesn't ++ * need to be painted anymore. ++ */ ++void ++clutter_actor_inhibit_culling (ClutterActor *actor) ++{ ++ ClutterActorPrivate *priv; ++ ++ g_return_if_fail (CLUTTER_IS_ACTOR (actor)); ++ ++ priv = actor->priv; ++ ++ priv->inhibit_culling_counter++; ++ _clutter_actor_set_enable_paint_unmapped (actor, TRUE); ++} ++ ++/** ++ * clutter_actor_uninhibit_culling: ++ * @actor: a #ClutterActor ++ * ++ * Decreases the culling inhibitor counter. See clutter_actor_inhibit_culling() ++ * for when inhibit culling is necessary. ++ * ++ * Calling this function without a matching call to ++ * clutter_actor_inhibit_culling() is a programming error. ++ */ ++void ++clutter_actor_uninhibit_culling (ClutterActor *actor) ++{ ++ ClutterActorPrivate *priv; ++ ++ g_return_if_fail (CLUTTER_IS_ACTOR (actor)); ++ ++ priv = actor->priv; ++ ++ if (priv->inhibit_culling_counter == 0) ++ { ++ g_critical ("Unpaired call to clutter_actor_uninhibit_culling"); ++ return; ++ } ++ ++ priv->inhibit_culling_counter--; ++ if (priv->inhibit_culling_counter == 0) ++ _clutter_actor_set_enable_paint_unmapped (actor, FALSE); ++} ++ + /* Allows you to disable applying the actors model view transform during + * a paint. Used by ClutterClone. */ + void +diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h +index 7d2168af1..f6e0acbb2 100644 +--- a/clutter/clutter/clutter-actor.h ++++ b/clutter/clutter/clutter-actor.h +@@ -870,6 +870,11 @@ void clutter_actor_set_opacity_override + CLUTTER_EXPORT + gint clutter_actor_get_opacity_override (ClutterActor *self); + ++CLUTTER_EXPORT ++void clutter_actor_inhibit_culling (ClutterActor *actor); ++CLUTTER_EXPORT ++void clutter_actor_uninhibit_culling (ClutterActor *actor); ++ + /** + * ClutterActorCreateChildFunc: + * @item: (type GObject): the item in the model +-- +2.26.2 + + +From 471c6d372bd9e1a79cf10e46fb8cbc4c110d1da6 Mon Sep 17 00:00:00 2001 +From: Georges Basile Stavracas Neto +Date: Wed, 18 Mar 2020 21:14:58 -0300 +Subject: [PATCH 41/49] window-actor: Inhibit culling when blitting to + screencast + +This allows us to screencast any window continuously, even +without it being visible. Because it's still being painted, +clients continue to receive frame callbacks, and people +are happy again. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/1129 +--- + src/compositor/meta-window-actor.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index c9ef5846a..08d1b0a87 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2049,6 +2049,8 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + if (!clutter_actor_get_resource_scale (actor, &resource_scale)) + return FALSE; + ++ clutter_actor_inhibit_culling (actor); ++ + width = ceilf (width * resource_scale); + height = ceilf (height * resource_scale); + +@@ -2084,6 +2086,8 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + cogl_framebuffer_pop_matrix (framebuffer); + cogl_framebuffer_pop_clip (framebuffer); + ++ clutter_actor_uninhibit_culling (actor); ++ + return TRUE; + } + +@@ -2151,33 +2155,36 @@ meta_window_actor_get_image (MetaWindowActor *self, + CoglColor clear_color; + float x, y; + MetaRectangle scaled_clip; +- cairo_surface_t *surface; ++ cairo_surface_t *surface = NULL; + + if (!priv->surface) + return NULL; + ++ clutter_actor_inhibit_culling (actor); ++ + if (clutter_actor_get_n_children (actor) == 1) + { + MetaShapedTexture *stex; + + stex = meta_surface_actor_get_texture (priv->surface); +- return meta_shaped_texture_get_image (stex, clip); ++ surface = meta_shaped_texture_get_image (stex, clip); ++ goto out; + } + + clutter_actor_get_size (actor, &width, &height); + + if (width == 0 || height == 0) +- return NULL; ++ goto out; + + if (!clutter_actor_get_resource_scale (actor, &resource_scale)) +- return NULL; ++ goto out; + + width = ceilf (width * resource_scale); + height = ceilf (height * resource_scale); + + texture = cogl_texture_2d_new_with_size (cogl_context, width, height); + if (!texture) +- return NULL; ++ goto out; + + cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture), + FALSE); +@@ -2193,7 +2200,7 @@ meta_window_actor_get_image (MetaWindowActor *self, + error->message); + cogl_object_unref (framebuffer); + cogl_object_unref (texture); +- return NULL; ++ goto out; + } + + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); +@@ -2242,5 +2249,7 @@ meta_window_actor_get_image (MetaWindowActor *self, + + cairo_surface_mark_dirty (surface); + ++out: ++ clutter_actor_uninhibit_culling (actor); + return surface; + } +-- +2.26.2 + + +From f29763e93ddf7933bd5ea3d2cd5769683b9e312b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 18 May 2020 17:52:09 +0200 +Subject: [PATCH 42/49] screen-cast/monitor-src: Get views from the stage + +Otherwise we don't get the views when in the X11 session. +--- + clutter/clutter/clutter-mutter.h | 3 +++ + clutter/clutter/clutter-stage-private.h | 2 -- + src/backends/meta-screen-cast-monitor-stream-src.c | 4 ++-- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h +index a53080457..6137605d4 100644 +--- a/clutter/clutter/clutter-mutter.h ++++ b/clutter/clutter/clutter-mutter.h +@@ -55,6 +55,9 @@ void clutter_stage_update_resource_scales (ClutterStage *stage); + CLUTTER_EXPORT + gboolean clutter_actor_has_damage (ClutterActor *actor); + ++CLUTTER_EXPORT ++GList *_clutter_stage_peek_stage_views (ClutterStage *stage); ++ + #undef __CLUTTER_H_INSIDE__ + + #endif /* __CLUTTER_MUTTER_H__ */ +diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h +index df0bf642b..42474687a 100644 +--- a/clutter/clutter/clutter-stage-private.h ++++ b/clutter/clutter/clutter-stage-private.h +@@ -133,8 +133,6 @@ void _clutter_stage_presented (ClutterStage *stag + CoglFrameEvent frame_event, + ClutterFrameInfo *frame_info); + +-GList * _clutter_stage_peek_stage_views (ClutterStage *stage); +- + G_END_DECLS + + #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ +diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c +index af763dc09..655b68261 100644 +--- a/src/backends/meta-screen-cast-monitor-stream-src.c ++++ b/src/backends/meta-screen-cast-monitor-stream-src.c +@@ -374,7 +374,7 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + MetaScreenCastMonitorStreamSrc *monitor_src = + META_SCREEN_CAST_MONITOR_STREAM_SRC (src); + MetaBackend *backend = get_backend (monitor_src); +- MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + MetaMonitor *monitor; + MetaLogicalMonitor *logical_monitor; + MetaRectangle logical_monitor_layout; +@@ -390,7 +390,7 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc + else + view_scale = 1.0; + +- for (l = meta_renderer_get_views (renderer); l; l = l->next) ++ for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next) + { + ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data); + g_autoptr (GError) error = NULL; +-- +2.26.2 + + +From d6d401f74452e7eb2f2ac0272b30603782ea95c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 12 May 2020 08:52:01 +0200 +Subject: [PATCH 43/49] screen-cast-stream-src: Don't throttle if max framerate + is 1/0 + +The max framerate 1/0 means variable without any particular max, so +don't throttle if that was set. + +Not doing this would end up with a floating point exception. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251 +--- + src/backends/meta-screen-cast-stream-src.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 4f3d821ef..ad0d9ed79 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -445,7 +445,8 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) + uint64_t now_us; + + now_us = g_get_monotonic_time (); +- if (priv->last_frame_timestamp_us != 0 && ++ if (priv->video_format.max_framerate.num > 0 && ++ priv->last_frame_timestamp_us != 0 && + (now_us - priv->last_frame_timestamp_us < + ((1000000 * priv->video_format.max_framerate.denom) / + priv->video_format.max_framerate.num))) +-- +2.26.2 + + +From 0e00b9b3516362009c671cfd62dd32dc9691e647 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 12 May 2020 16:14:00 +0200 +Subject: [PATCH 44/49] screen-cast-src: Notify that about the stream being + closed on idle + +We're iterating inside the PipeWire loop when detecting PipeWire errors, +and shouldn't destroy the PipeWire objects mid-iteration. Avoid this by +first disabling the stream src (effectively stopping the recording), +then notifying about it being closed in an idle callback. The +notification eventually makes the rest of the screen cast code clean up +the objects, including the src and the associated PipeWire objects, but +will do so outside the PipeWire loop iteration. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251 +--- + src/backends/meta-screen-cast-stream-src.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index ad0d9ed79..0500bfec5 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -540,10 +540,16 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src) + priv->is_enabled = FALSE; + } + +-static void +-meta_screen_cast_stream_src_notify_closed (MetaScreenCastStreamSrc *src) ++static gboolean ++notify_stream_src_closed_idle (gpointer user_data) + { ++ MetaScreenCastStreamSrc *src = user_data; ++ + g_signal_emit (src, signals[CLOSED], 0); ++ ++ g_object_unref (src); ++ ++ return G_SOURCE_REMOVE; + } + + static void +@@ -560,7 +566,9 @@ on_stream_state_changed (void *data, + { + case PW_STREAM_STATE_ERROR: + g_warning ("pipewire stream error: %s", error_message); +- meta_screen_cast_stream_src_notify_closed (src); ++ if (meta_screen_cast_stream_src_is_enabled (src)) ++ meta_screen_cast_stream_src_disable (src); ++ g_idle_add (notify_stream_src_closed_idle, g_object_ref (src)); + break; + case PW_STREAM_STATE_PAUSED: + if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream) +@@ -832,7 +840,11 @@ on_core_error (void *data, + g_warning ("pipewire remote error: id:%u %s", id, message); + + if (id == PW_ID_CORE && res == -EPIPE) +- meta_screen_cast_stream_src_notify_closed (src); ++ { ++ if (meta_screen_cast_stream_src_is_enabled (src)) ++ meta_screen_cast_stream_src_disable (src); ++ g_idle_add (notify_stream_src_closed_idle, g_object_ref (src)); ++ } + } + + static gboolean +-- +2.26.2 + + +From 788a6f4adea0f976598014744149fb78feac145d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 18 May 2020 19:10:49 +0200 +Subject: [PATCH 45/49] compositor: Only check for stereo when using GLX + +If EGL Xlib is used, we'll get bogus return value and crash. +--- + src/compositor/compositor.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index 6c08c8fe4..a6ae55abb 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -534,9 +534,17 @@ typedef struct { + static gboolean + display_has_stereo_tree_ext (MetaX11Display *x11_display) + { ++ MetaBackend *backend = meta_get_backend (); ++ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_backend); ++ CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context); + Display *xdisplay = x11_display->xdisplay; + const char *extensions_string; + ++ if (cogl_renderer_get_winsys_id (cogl_renderer) != COGL_WINSYS_ID_GLX) ++ return FALSE; ++ + static const char * (*query_extensions_string) (Display *display, + int screen); + +-- +2.26.2 + + +From 1aa9d081b69dc8ce7948a2189bd6ca0dd4c9611b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 3 Apr 2020 17:12:58 +0200 +Subject: [PATCH 46/49] window-actor: Set viewport when blitting to screencast + fb + +This fixes an issue where a non-maximized screen casted window would be +stretched to fill the whole screen cast stream, instead of just the crop +that corresponds to the current window size. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1174 +--- + src/compositor/meta-window-actor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 08d1b0a87..1167acfa5 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2059,6 +2059,7 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window, + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); ++ cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height); + + meta_rectangle_scale_double (bounds, resource_scale, + META_ROUNDING_STRATEGY_GROW, +-- +2.26.2 + + +From 289cad91ac820b7280485603865d3060b5f84cf8 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Sat, 16 May 2020 10:44:04 +0200 +Subject: [PATCH 47/49] backends: Ensure remote desktop dbus interface state + +Ensure that it does receive Start and Stop orderly, and error out +otherwise. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258 +--- + src/backends/meta-remote-desktop-session.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c +index f069cba2f..8d53dc41c 100644 +--- a/src/backends/meta-remote-desktop-session.c ++++ b/src/backends/meta-remote-desktop-session.c +@@ -56,6 +56,7 @@ struct _MetaRemoteDesktopSession + + MetaScreenCastSession *screen_cast_session; + gulong screen_cast_session_closed_handler_id; ++ guint started : 1; + + ClutterVirtualInputDevice *virtual_pointer; + ClutterVirtualInputDevice *virtual_keyboard; +@@ -120,7 +121,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session, + ClutterDeviceManager *device_manager = + clutter_device_manager_get_default (); + +- g_assert (!session->virtual_pointer && !session->virtual_keyboard); ++ g_assert (!session->started); + + if (session->screen_cast_session) + { +@@ -140,6 +141,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session, + CLUTTER_TOUCHSCREEN_DEVICE); + + init_remote_access_handle (session); ++ session->started = TRUE; + + return TRUE; + } +@@ -150,6 +152,8 @@ meta_remote_desktop_session_close (MetaRemoteDesktopSession *session) + MetaDBusRemoteDesktopSession *skeleton = + META_DBUS_REMOTE_DESKTOP_SESSION (session); + ++ session->started = FALSE; ++ + if (session->screen_cast_session) + { + g_signal_handler_disconnect (session->screen_cast_session, +@@ -261,6 +265,14 @@ handle_start (MetaDBusRemoteDesktopSession *skeleton, + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + GError *error = NULL; + ++ if (session->started) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "Already started"); ++ return TRUE; ++ } ++ + if (!check_permission (session, invocation)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, +@@ -293,6 +305,14 @@ handle_stop (MetaDBusRemoteDesktopSession *skeleton, + { + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + ++ if (!session->started) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "Session not started"); ++ return TRUE; ++ } ++ + if (!check_permission (session, invocation)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, +-- +2.26.2 + + +From ccbfc529a11e52a27e8d6751753e82e55319e3c8 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Sat, 16 May 2020 10:46:57 +0200 +Subject: [PATCH 48/49] backends: Make uniform checks on remote desktop input + dbus methods + +They all checked that the remote session service talked with the +correct peer, and some of them did check that there is an associated +screencast session. + +Add a new check for the session being started (as it's state is +decoupled with screencast session availability) and move all checks +to a function that is called from all input-oriented DBus methods. + +Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1254 + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258 +--- + src/backends/meta-remote-desktop-session.c | 145 ++++++++------------- + 1 file changed, 51 insertions(+), 94 deletions(-) + +diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c +index 8d53dc41c..59057fc70 100644 +--- a/src/backends/meta-remote-desktop-session.c ++++ b/src/backends/meta-remote-desktop-session.c +@@ -258,6 +258,37 @@ check_permission (MetaRemoteDesktopSession *session, + g_dbus_method_invocation_get_sender (invocation)) == 0; + } + ++static gboolean ++meta_remote_desktop_session_check_can_notify (MetaRemoteDesktopSession *session, ++ GDBusMethodInvocation *invocation) ++{ ++ if (!session->started) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "Session not started"); ++ return FALSE; ++ } ++ ++ if (!check_permission (session, invocation)) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_ACCESS_DENIED, ++ "Permission denied"); ++ return FALSE; ++ } ++ ++ if (!session->screen_cast_session) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "No screen cast active"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static gboolean + handle_start (MetaDBusRemoteDesktopSession *skeleton, + GDBusMethodInvocation *invocation) +@@ -337,13 +368,8 @@ handle_notify_keyboard_keycode (MetaDBusRemoteDesktopSession *skeleton, + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + ClutterKeyState state; + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + if (pressed) + state = CLUTTER_KEY_STATE_PRESSED; +@@ -369,13 +395,8 @@ handle_notify_keyboard_keysym (MetaDBusRemoteDesktopSession *skeleton, + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + ClutterKeyState state; + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + if (pressed) + state = CLUTTER_KEY_STATE_PRESSED; +@@ -423,13 +444,8 @@ handle_notify_pointer_button (MetaDBusRemoteDesktopSession *skeleton, + uint32_t button; + ClutterButtonState state; + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + button = translate_to_clutter_button (button_code); + +@@ -459,13 +475,8 @@ handle_notify_pointer_axis (MetaDBusRemoteDesktopSession *skeleton, + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE; + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + if (flags & META_REMOTE_DESKTOP_NOTIFY_AXIS_FLAGS_FINISH) + { +@@ -512,13 +523,8 @@ handle_notify_pointer_axis_discrete (MetaDBusRemoteDesktopSession *skeleton, + ClutterScrollDirection direction; + int step_count; + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + if (axis > 1) + { +@@ -563,13 +569,8 @@ handle_notify_pointer_motion_relative (MetaDBusRemoteDesktopSession *skeleton, + { + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + clutter_virtual_input_device_notify_relative_motion (session->virtual_pointer, + CLUTTER_CURRENT_TIME, +@@ -592,21 +593,8 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton, + MetaScreenCastStream *stream; + double abs_x, abs_y; + +- 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 (!session->screen_cast_session) +- { +- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, +- G_DBUS_ERROR_FAILED, +- "No screen cast active"); +- return TRUE; +- } ++ if (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + stream = meta_screen_cast_session_get_stream (session->screen_cast_session, + stream_path); +@@ -642,21 +630,8 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton, + MetaScreenCastStream *stream; + double abs_x, abs_y; + +- 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 (!session->screen_cast_session) +- { +- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, +- G_DBUS_ERROR_FAILED, +- "No screen cast active"); +- return TRUE; +- } ++ if (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + stream = meta_screen_cast_session_get_stream (session->screen_cast_session, + stream_path); +@@ -693,21 +668,8 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton, + MetaScreenCastStream *stream; + double abs_x, abs_y; + +- 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 (!session->screen_cast_session) +- { +- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, +- G_DBUS_ERROR_FAILED, +- "No screen cast active"); +- return TRUE; +- } ++ if (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + stream = meta_screen_cast_session_get_stream (session->screen_cast_session, + stream_path); +@@ -739,13 +701,8 @@ handle_notify_touch_up (MetaDBusRemoteDesktopSession *skeleton, + { + MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton); + +- 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 (!meta_remote_desktop_session_check_can_notify (session, invocation)) ++ return TRUE; + + clutter_virtual_input_device_notify_touch_up (session->virtual_touchscreen, + CLUTTER_CURRENT_TIME, +-- +2.26.2 + + +From 519c86b833f57286e51f2a1514003e9e3461bd7e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 21 Apr 2020 15:44:32 +0200 +Subject: [PATCH 49/49] remote-access-controller: Allow inhibiting remote + access + +Inhibiting remote access means any current remote access session is +terminated, and no new ones can be created, until remote access is +uninhibited. The inhibitation is ref counted, meaning there can be more +than one inhibitor. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1212 +(cherry picked from commit 4300f1f91d726051893146d7b294d8852782f137) +--- + src/backends/meta-backend-types.h | 1 + + src/backends/meta-backend.c | 4 +- + .../meta-remote-access-controller-private.h | 4 ++ + src/backends/meta-remote-access-controller.c | 49 +++++++++++++++++++ + src/backends/meta-remote-desktop.c | 39 +++++++++++++++ + src/backends/meta-remote-desktop.h | 4 ++ + src/backends/meta-screen-cast.c | 34 +++++++++++++ + src/backends/meta-screen-cast.h | 4 ++ + src/meta/meta-remote-access-controller.h | 6 +++ + 9 files changed, 143 insertions(+), 2 deletions(-) + +diff --git a/src/backends/meta-backend-types.h b/src/backends/meta-backend-types.h +index eb982d73e..98cac8b9e 100644 +--- a/src/backends/meta-backend-types.h ++++ b/src/backends/meta-backend-types.h +@@ -49,6 +49,7 @@ typedef struct _MetaTileInfo MetaTileInfo; + typedef struct _MetaRenderer MetaRenderer; + typedef struct _MetaRendererView MetaRendererView; + ++typedef struct _MetaRemoteDesktop MetaRemoteDesktop; + typedef struct _MetaScreenCast MetaScreenCast; + typedef struct _MetaScreenCastSession MetaScreenCastSession; + typedef struct _MetaScreenCastStream MetaScreenCastStream; +diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c +index 72cfbdaf3..750a9248a 100644 +--- a/src/backends/meta-backend.c ++++ b/src/backends/meta-backend.c +@@ -501,12 +501,12 @@ meta_backend_real_post_init (MetaBackend *backend) + priv->input_settings = meta_backend_create_input_settings (backend); + + #ifdef HAVE_REMOTE_DESKTOP +- priv->remote_access_controller = +- g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL); + priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL); + priv->screen_cast = meta_screen_cast_new (backend, + priv->dbus_session_watcher); + priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher); ++ priv->remote_access_controller = ++ meta_remote_access_controller_new (priv->remote_desktop, priv->screen_cast); + #endif /* HAVE_REMOTE_DESKTOP */ + + if (!meta_monitor_manager_is_headless (priv->monitor_manager)) +diff --git a/src/backends/meta-remote-access-controller-private.h b/src/backends/meta-remote-access-controller-private.h +index fce2082bf..444b71a77 100644 +--- a/src/backends/meta-remote-access-controller-private.h ++++ b/src/backends/meta-remote-access-controller-private.h +@@ -21,8 +21,12 @@ + #ifndef META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H + #define META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H + ++#include "backends/meta-backend-types.h" + #include "meta/meta-remote-access-controller.h" + ++MetaRemoteAccessController * meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop, ++ MetaScreenCast *screen_cast); ++ + void meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *controller, + MetaRemoteAccessHandle *handle); + +diff --git a/src/backends/meta-remote-access-controller.c b/src/backends/meta-remote-access-controller.c +index 0e0ebe2bd..e5ae0b5bd 100644 +--- a/src/backends/meta-remote-access-controller.c ++++ b/src/backends/meta-remote-access-controller.c +@@ -22,6 +22,9 @@ + + #include "backends/meta-remote-access-controller-private.h" + ++#include "backends/meta-remote-desktop.h" ++#include "backends/meta-screen-cast.h" ++ + enum + { + HANDLE_STOPPED, +@@ -52,6 +55,9 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaRemoteAccessHandle, + struct _MetaRemoteAccessController + { + GObject parent; ++ ++ MetaRemoteDesktop *remote_desktop; ++ MetaScreenCast *screen_cast; + }; + + G_DEFINE_TYPE (MetaRemoteAccessController, +@@ -94,6 +100,49 @@ meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *con + handle); + } + ++/** ++ * meta_remote_access_controller_inhibit_remote_access: ++ * @controller: a #MetaRemoteAccessController ++ * ++ * Inhibits remote access sessions from being created and running. Any active ++ * remote access session will be terminated. ++ */ ++void ++meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController *controller) ++{ ++ meta_remote_desktop_inhibit (controller->remote_desktop); ++ meta_screen_cast_inhibit (controller->screen_cast); ++} ++ ++/** ++ * meta_remote_access_controller_uninhibit_remote_access: ++ * @controller: a #MetaRemoteAccessController ++ * ++ * Uninhibits remote access sessions from being created and running. If this was ++ * the last inhibitation that was inhibited, new remote access sessions can now ++ * be created. ++ */ ++void ++meta_remote_access_controller_uninhibit_remote_access (MetaRemoteAccessController *controller) ++{ ++ meta_screen_cast_uninhibit (controller->screen_cast); ++ meta_remote_desktop_uninhibit (controller->remote_desktop); ++} ++ ++MetaRemoteAccessController * ++meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop, ++ MetaScreenCast *screen_cast) ++{ ++ MetaRemoteAccessController *remote_access_controller; ++ ++ remote_access_controller = g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, ++ NULL); ++ remote_access_controller->remote_desktop = remote_desktop; ++ remote_access_controller->screen_cast = screen_cast; ++ ++ return remote_access_controller; ++} ++ + static void + meta_remote_access_handle_init (MetaRemoteAccessHandle *handle) + { +diff --git a/src/backends/meta-remote-desktop.c b/src/backends/meta-remote-desktop.c +index d741dccd8..6d87d755b 100644 +--- a/src/backends/meta-remote-desktop.c ++++ b/src/backends/meta-remote-desktop.c +@@ -56,6 +56,8 @@ struct _MetaRemoteDesktop + + int dbus_name_id; + ++ int inhibit_count; ++ + GHashTable *sessions; + + MetaDbusSessionWatcher *session_watcher; +@@ -70,6 +72,34 @@ G_DEFINE_TYPE_WITH_CODE (MetaRemoteDesktop, + G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_REMOTE_DESKTOP, + meta_remote_desktop_init_iface)); + ++void ++meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop) ++{ ++ remote_desktop->inhibit_count++; ++ if (remote_desktop->inhibit_count == 1) ++ { ++ GHashTableIter iter; ++ gpointer key, value; ++ ++ g_hash_table_iter_init (&iter, remote_desktop->sessions); ++ while (g_hash_table_iter_next (&iter, &key, &value)) ++ { ++ MetaRemoteDesktopSession *session = value; ++ ++ g_hash_table_iter_steal (&iter); ++ meta_remote_desktop_session_close (session); ++ } ++ } ++} ++ ++void ++meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop) ++{ ++ g_return_if_fail (remote_desktop->inhibit_count > 0); ++ ++ remote_desktop->inhibit_count--; ++} ++ + GDBusConnection * + meta_remote_desktop_get_connection (MetaRemoteDesktop *remote_desktop) + { +@@ -108,6 +138,15 @@ handle_create_session (MetaDBusRemoteDesktop *skeleton, + char *session_path; + const char *client_dbus_name; + ++ if (remote_desktop->inhibit_count > 0) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_ACCESS_DENIED, ++ "Session creation inhibited"); ++ ++ return TRUE; ++ } ++ + peer_name = g_dbus_method_invocation_get_sender (invocation); + session = meta_remote_desktop_session_new (remote_desktop, + peer_name, +diff --git a/src/backends/meta-remote-desktop.h b/src/backends/meta-remote-desktop.h +index 3eebc13d5..210a84a04 100644 +--- a/src/backends/meta-remote-desktop.h ++++ b/src/backends/meta-remote-desktop.h +@@ -36,6 +36,10 @@ G_DECLARE_FINAL_TYPE (MetaRemoteDesktop, meta_remote_desktop, + META, REMOTE_DESKTOP, + MetaDBusRemoteDesktopSkeleton) + ++void meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop); ++ ++void meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop); ++ + MetaRemoteDesktopSession * meta_remote_desktop_get_session (MetaRemoteDesktop *remote_desktop, + const char *session_id); + +diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c +index 063fffd8e..46bc26838 100644 +--- a/src/backends/meta-screen-cast.c ++++ b/src/backends/meta-screen-cast.c +@@ -40,6 +40,8 @@ struct _MetaScreenCast + + int dbus_name_id; + ++ int inhibit_count; ++ + GList *sessions; + + MetaDbusSessionWatcher *session_watcher; +@@ -54,6 +56,29 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCast, meta_screen_cast, + G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SCREEN_CAST, + meta_screen_cast_init_iface)) + ++void ++meta_screen_cast_inhibit (MetaScreenCast *screen_cast) ++{ ++ screen_cast->inhibit_count++; ++ if (screen_cast->inhibit_count == 1) ++ { ++ while (screen_cast->sessions) ++ { ++ MetaScreenCastSession *session = screen_cast->sessions->data; ++ ++ meta_screen_cast_session_close (session); ++ } ++ } ++} ++ ++void ++meta_screen_cast_uninhibit (MetaScreenCast *screen_cast) ++{ ++ g_return_if_fail (screen_cast->inhibit_count > 0); ++ ++ screen_cast->inhibit_count--; ++} ++ + GDBusConnection * + meta_screen_cast_get_connection (MetaScreenCast *screen_cast) + { +@@ -118,6 +143,15 @@ handle_create_session (MetaDBusScreenCast *skeleton, + char *remote_desktop_session_id = NULL; + MetaScreenCastSessionType session_type; + ++ if (screen_cast->inhibit_count > 0) ++ { ++ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_ACCESS_DENIED, ++ "Session creation inhibited"); ++ ++ return TRUE; ++ } ++ + g_variant_lookup (properties, "remote-desktop-session-id", "s", + &remote_desktop_session_id); + +diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h +index 994c40c53..a3b650cd8 100644 +--- a/src/backends/meta-screen-cast.h ++++ b/src/backends/meta-screen-cast.h +@@ -42,6 +42,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast, + META, SCREEN_CAST, + MetaDBusScreenCastSkeleton) + ++void meta_screen_cast_inhibit (MetaScreenCast *screen_cast); ++ ++void meta_screen_cast_uninhibit (MetaScreenCast *screen_cast); ++ + GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast); + + MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast); +diff --git a/src/meta/meta-remote-access-controller.h b/src/meta/meta-remote-access-controller.h +index e7c707bbc..56f0dcbe2 100644 +--- a/src/meta/meta-remote-access-controller.h ++++ b/src/meta/meta-remote-access-controller.h +@@ -51,4 +51,10 @@ G_DECLARE_FINAL_TYPE (MetaRemoteAccessController, + META, REMOTE_ACCESS_CONTROLLER, + GObject) + ++META_EXPORT ++void meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController *controller); ++ ++META_EXPORT ++void meta_remote_access_controller_uninhibit_remote_access (MetaRemoteAccessController *controller); ++ + #endif /* META_REMOTE_ACCESS_CONTROLLER_H */ +-- +2.26.2 + diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec index 4b99e7a..e168884 100644 --- a/SPECS/mutter.spec +++ b/SPECS/mutter.spec @@ -3,12 +3,12 @@ %global gsettings_desktop_schemas_version 3.21.4 %global json_glib_version 0.12.0 %global libinput_version 1.4 -%global pipewire_version 0.2.2 +%global pipewire_version 0.3.0 %global mutter_api_version 4 Name: mutter Version: 3.32.2 -Release: 26%{?dist} +Release: 44%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -28,17 +28,6 @@ Patch3: covscan-fixes.patch Patch4: 0001-enum-types-Use-basename-in-header-comment.patch Patch5: 0001-workspace-manager-Expose-layout-properties.patch -# Fix corruption on suspend and resume with nvidia (rhbz#1663440) -Patch10001: 0001-cogl-add-new-UNSTABLE_TEXTURES-feature.patch -Patch10002: 0002-backend-switch-to-using-generated-logind-proxy.patch -Patch10003: 0003-backend-add-signals-for-reporting-suspend-and-resume.patch -Patch10004: 0004-wayland-force-X-clients-to-redraw-on-resume.patch -Patch10005: 0005-backends-native-emit-gl-video-memory-purged-when-bec.patch -Patch10006: 0006-backends-native-update-glyph-cache-on-resume.patch -Patch10007: 0007-backends-native-update-cursor-on-resume.patch -Patch10008: 0008-background-purge-all-background-textures-on-suspend.patch -Patch10009: 0009-MetaShapedTexture-save-and-restore-textures-on-suspe.patch - # RHEL 7 downstream patches Patch100: deal-more-gracefully-with-oversized-windows.patch # Work-around for Xvnc resizing (rhbz#1265511) @@ -110,6 +99,57 @@ Patch264: 0001-backends-Always-enable-tap-to-click-drag-on-opaque-W.patch Patch265: 0001-backends-x11-Observe-multiple-pad-mode-switch-button.patch Patch266: 0001-backends-Check-both-input-settings-and-mapper-for-ta.patch Patch267: 0001-core-Let-pad-mode-switch-events-always-go-through-Me.patch +Patch268: 0001-Create-explicit-WacomDevices-for-tablet-touchpad-dev.patch +Patch269: 0001-Skip-wacom-touchpads-when-updating-setting.patch + +# Revert stored-config behavior for VMs (#1365717) +Patch280: 0001-Revert-MetaMonitorManager-ignore-hotplug_mode_update.patch + +# Respect xrandr --panning (#1690170) +Patch281: 0001-crtc-xrandr-Respect-configured-RANDR-panning.patch + +# gnome-shell core dump after connection to docking station (#1809079) +Patch282: handle-hotplug-better.patch + +# Improve performance under load (#1820760) +Patch290: 0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch +Patch291: 0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch +Patch292: 0003-clutter-fix-hole-in-ClutterPaintNode.patch + +# Fix corrupted background after suspend (#1828162) +Patch300: 0001-background-Reload-when-GPU-memory-is-invalidated.patch + +# Backport screen cast and remote desktop improvements (#1837381) +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/623 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/752 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/976 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1022 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1062 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/687 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1086 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1115 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1106 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1129 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1174 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258 +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1212 +Patch400: screen-cast-remote-desktop-improvements.patch +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283 +Patch401: 0001-screen-cast-src-Destroy-hash-dmabuf-table-after-stre.patch +Patch402: 0002-renderer-native-Don-t-leak-DMA-buffer-CoglFramebuffe.patch +Patch403: 0001-renderer-Add-API-to-check-whether-renderer-is-hardwa.patch +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1318 (#1847062) +Patch404: 0001-backend-Add-getter-for-MetaScreenCast.patch +Patch405: 0002-renderer-native-Add-API-to-get-primary-GPU.patch +Patch406: 0003-screen-cast-Move-DMA-buffer-allocation-to-MetaScreen.patch +Patch407: 0004-screen-cast-Disable-DMA-buffer-based-screen-casting-.patch + +# Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages (#1847203) +Patch500: 0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch + +# Don't show widow actor until explictly shown (#1719937) +Patch501: 0001-window-actor-Don-t-show-actor-until-meta_window_acto.patch BuildRequires: chrpath BuildRequires: pango-devel @@ -252,6 +292,78 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop %{_datadir}/mutter-%{mutter_api_version}/tests %changelog +* Thu Jun 25 2020 Jonas Ådahl - 3.32.2-44 +- Don't show widow actor until explictly shown + Resolves: #1719937 + +* Thu Jun 25 2020 Jonas Ådahl - 3.32.2-43 +- Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages + Resolves: #1847203 + +* Tue Jun 16 2020 Jonas Ådahl - 3.32.2-42 +- Don't pass DMA buffers if they can't be mmap():ed + Related: #1847062 + +* Wed Jun 10 2020 Florian Müllner - 3.32.2-41 +- Backport is_rendering_hardware_acclerated() API + Related: #1837381 + +* Wed Jun 03 2020 Jonas Ådahl - 3.32.2-40 +- Fix DMA buffer memory leak + Related: #1837381 + +* Mon May 25 2020 Jonas Ådahl - 3.32.2-39 +- Fix incorrect pipewire dependency version + Related: #1837381 + +* Mon May 25 2020 Jonas Ådahl - 3.32.2-38 +- Backport screen cast and remote desktop improvements + Resolves: #1837381 + +* Tue May 19 2020 Jonas Ådahl - 3.32.2-37 +- Fix corrupted background after suspend + Resolves: #1828162 + +* Wed Apr 08 2020 Florian Müllner - 3.32.2-36 +- Improve performance under IO load + Resolves: #1820760 + +* Mon Mar 23 2020 Jonas Ådahl - 3.32.2-35 +- Drop EGLStream robustness patches + Resolves: #1815430 + +* Thu Mar 05 2020 Jonas Ådahl - 3.32.2-34 +- gnome-shell core dump after connection to docking station + Resolves: #1809079 + +* Mon Feb 24 2020 Jonas Ådahl - 3.32.2-33 +- Respect xrandr --panning + Resolves: #1690170 + +* Mon Feb 24 2020 Jonas Ådahl - 3.32.2-32 +- Revert stored-config behavior for VMs + Resolves: #1365717 + +* Mon Feb 24 2020 Carlos Garnacho - 3.32.2-31 +- Fixup detection of multiple mode switch buttons + Resolves: #1687979 + +* Fri Feb 21 2020 Carlos Garnacho - 3.32.2-30 +- Avoid toggling wacom touchpads on tap-to-click/drag setting updates + Resolves: #1716754 + +* Thu Feb 13 2020 Carlos Garnacho - 3.32.2-29 +- Fixup Wacom pad OSD so it appears on the right monitor + Resolves: #1777556 + +* Thu Feb 13 2020 Carlos Garnacho - 3.32.2-28 +- Fixup automatic enabling of wacom touchpad tapping + Resolves: #1716754 + +* Thu Feb 13 2020 Carlos Garnacho - 3.32.2-27 +- Fixup handling of multiple mode switch buttons in pads + Resolves: #1687979 + * Mon Dec 16 2019 Carlos Garnacho - 3.32.2-26 - Let pad OSD update on mode switching Resolves: #1716774 @@ -276,7 +388,7 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop - Fix mode switch pad buttons without LEDs Resolves: #1666070 -* Mon Dec 01 2019 Tomas Pelka - 3.32.2-20 +* Mon Dec 02 2019 Tomas Pelka - 3.32.2-20 - Need rebuild in correct build target Resolves: #1730891