renderer/native: Don't queue mode set on hotplug power-save on

We need to trigger a mode set when power-save changes to 'on' if it's
purely about power saving, but when they arrive as part of a hotplug
event, we'll handle all that later, in the monitors-changed handling,
that contains the new configuration.

This avoids a crash that happens due to the mode set being queued on now
disabled connectors.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2985
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3233>
This commit is contained in:
Jonas Ådahl 2023-09-01 22:22:34 +02:00 committed by Marge Bot
parent efbb8df611
commit b20d7a5cc4
2 changed files with 105 additions and 1 deletions

View File

@ -2022,7 +2022,8 @@ on_power_save_mode_changed (MetaMonitorManager *monitor_manager,
MetaPowerSave power_save_mode;
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
if (power_save_mode == META_POWER_SAVE_ON)
if (power_save_mode == META_POWER_SAVE_ON &&
reason == META_POWER_SAVE_CHANGE_REASON_MODE_CHANGE)
meta_renderer_native_queue_modes_reset (renderer_native);
else
meta_kms_discard_pending_page_flips (kms);

View File

@ -56,6 +56,12 @@ on_presented (ClutterStage *stage,
*state = PRESENTED;
}
static void
set_true_cb (gboolean *done)
{
*done = TRUE;
}
static void
meta_test_reload (void)
{
@ -324,6 +330,101 @@ meta_test_switch_config (void)
g_signal_handler_disconnect (monitor_manager, monitors_changed_handler_id);
}
static void
set_power_save_mode_via_dbus (MetaPowerSave power_save)
{
g_autoptr (GDBusProxy) proxy = NULL;
g_autoptr (GError) error = NULL;
GVariant *parameters;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.gnome.Mutter.DisplayConfig",
"/org/gnome/Mutter/DisplayConfig",
"org.freedesktop.DBus.Properties",
NULL,
&error);
g_assert_no_error (error);
parameters = g_variant_new ("(ssv)",
"org.gnome.Mutter.DisplayConfig",
"PowerSaveMode",
g_variant_new_int32 (power_save));
g_dbus_proxy_call (proxy,
"Set",
parameters,
G_DBUS_CALL_FLAGS_NO_AUTO_START,
G_MAXINT,
NULL, NULL, NULL);
}
static void
emulate_hotplug (void)
{
MetaBackend *backend = meta_context_get_backend (test_context);
MetaUdev *udev = meta_backend_native_get_udev (META_BACKEND_NATIVE (backend));
g_autoptr (GError) error = NULL;
g_autolist (GObject) udev_devices = NULL;
GUdevDevice *udev_device;
udev_devices = meta_udev_list_drm_devices (udev, &error);
g_assert_cmpuint (g_list_length (udev_devices), ==, 1);
udev_device = g_list_first (udev_devices)->data;
g_signal_emit_by_name (udev, "hotplug", udev_device);
}
static void
meta_test_power_save_implicit_on (void)
{
MetaBackend *backend = meta_context_get_backend (test_context);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
GList *logical_monitors;
gulong power_save_handler_id;
gulong monitors_changed_handler_id;
gboolean power_save_mode_changed;
gboolean monitors_changed;
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
g_assert_cmpuint (g_list_length (logical_monitors), ==, 1);
meta_wait_for_paint (test_context);
power_save_handler_id =
g_signal_connect_swapped (monitor_manager, "power-save-mode-changed",
G_CALLBACK (set_true_cb), &power_save_mode_changed);
set_power_save_mode_via_dbus (META_POWER_SAVE_OFF);
power_save_mode_changed = FALSE;
while (!power_save_mode_changed)
g_main_context_iteration (NULL, TRUE);
power_save_mode_changed = FALSE;
monitors_changed = FALSE;
monitors_changed_handler_id =
g_signal_connect_swapped (monitor_manager, "monitors-changed",
G_CALLBACK (set_true_cb), &monitors_changed);
drm_mock_set_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR,
disconnect_connector_filter, NULL);
emulate_hotplug ();
while (!power_save_mode_changed || !monitors_changed)
g_main_context_iteration (NULL, TRUE);
g_signal_handler_disconnect (monitor_manager, power_save_handler_id);
g_signal_handler_disconnect (monitor_manager, monitors_changed_handler_id);
drm_mock_unset_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR);
emulate_hotplug ();
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
g_assert_cmpuint (g_list_length (logical_monitors), ==, 1);
}
static void
init_tests (void)
{
@ -333,6 +434,8 @@ init_tests (void)
meta_test_disconnect_connect);
g_test_add_func ("/hotplug/switch-config",
meta_test_switch_config);
g_test_add_func ("/hotplug/power-save-implicit-off",
meta_test_power_save_implicit_on);
}
int