info: Fix Graphics text with NVidia drivers or >2 GPUs

Use switcheroo-control to get the list of GPUs. For each one of the GPUs
listed, switcheroo-control will give us environment variable we should
set before running our helper to be able to get the renderer from it.

This means that it will finally work when one of the GPUs is driven
with the NVidia drivers, as switcheroo-control sets the correct envvars
for this driver, and that we also support more than 2 GPUs.

Closes: https://gitlab.gnome.org/GNOME/gnome-control-center/merge_requests/601
This commit is contained in:
Bastien Nocera 2019-10-28 16:50:49 +01:00 committed by Robert Ancell
parent 212e406d7f
commit 2e17bc7516

View file

@ -232,8 +232,10 @@ get_renderer_from_session (void)
return renderer;
}
/* @env is an array of strings with each pair of strings being the
* key followed by the value */
static char *
get_renderer_from_helper (gboolean discrete_gpu)
get_renderer_from_helper (const char **env)
{
int status;
char *argv[] = { GNOME_SESSION_DIR "/gnome-session-check-accelerated", NULL };
@ -241,17 +243,27 @@ get_renderer_from_helper (gboolean discrete_gpu)
g_autofree char *renderer = NULL;
g_autoptr(GError) error = NULL;
if (discrete_gpu)
g_debug ("About to launch '%s'", argv[0]);
if (env != NULL)
{
guint i;
g_debug ("With environment:");
envp = g_get_environ ();
envp = g_environ_setenv (envp, "DRI_PRIME", "1", TRUE);
for (i = 0; env[i] != NULL; i = i + 2)
{
g_debug (" %s = %s", env[i], env[i+1]);
envp = g_environ_setenv (envp, env[i], env[i+1], TRUE);
}
}
else
{
g_debug ("No additional environment variables");
}
if (!g_spawn_sync (NULL, (char **) argv, envp, 0, NULL, NULL, &renderer, NULL, &status, &error))
{
g_debug ("Failed to get %s GPU: %s",
discrete_gpu ? "discrete" : "integrated",
error->message);
g_debug ("Failed to get GPU: %s", error->message);
return NULL;
}
@ -264,13 +276,40 @@ get_renderer_from_helper (gboolean discrete_gpu)
return info_cleanup (renderer);
}
static gboolean
has_dual_gpu (void)
typedef struct {
char *name;
gboolean is_default;
} GpuData;
static int
gpu_data_sort (gconstpointer a, gconstpointer b)
{
GpuData *gpu_a = (GpuData *) a;
GpuData *gpu_b = (GpuData *) b;
if (gpu_a->is_default)
return 1;
if (gpu_b->is_default)
return -1;
return 0;
}
static void
gpu_data_free (GpuData *data)
{
g_free (data->name);
g_free (data);
}
static char *
get_renderer_from_switcheroo (void)
{
g_autoptr(GDBusProxy) switcheroo_proxy = NULL;
g_autoptr(GVariant) dualgpu_variant = NULL;
gboolean ret;
g_autoptr(GVariant) variant = NULL;
g_autoptr(GError) error = NULL;
GString *renderers_string;
guint i, num_children;
GSList *renderers, *l;
switcheroo_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
@ -283,23 +322,72 @@ has_dual_gpu (void)
{
g_debug ("Unable to connect to create a proxy for net.hadess.SwitcherooControl: %s",
error->message);
return FALSE;
return NULL;
}
dualgpu_variant = g_dbus_proxy_get_cached_property (switcheroo_proxy, "HasDualGpu");
variant = g_dbus_proxy_get_cached_property (switcheroo_proxy, "GPUs");
if (!dualgpu_variant)
if (!variant)
{
g_debug ("Unable to retrieve net.hadess.SwitcherooControl.HasDualGpu property, the daemon is likely not running");
return FALSE;
g_debug ("Unable to retrieve net.hadess.SwitcherooControl.GPUs property, the daemon is likely not running");
return NULL;
}
ret = g_variant_get_boolean (dualgpu_variant);
renderers_string = g_string_new (NULL);
num_children = g_variant_n_children (variant);
renderers = NULL;
for (i = 0; i < num_children; i++)
{
g_autoptr(GVariant) gpu;
g_autoptr(GVariant) name = NULL;
g_autoptr(GVariant) env = NULL;
g_autoptr(GVariant) is_default = NULL;
const char *name_s;
g_autofree const char **env_s = NULL;
g_autofree char *renderer = NULL;
GpuData *gpu_data;
if (ret)
g_debug ("Dual-GPU machine detected");
gpu = g_variant_get_child_value (variant, i);
if (!gpu ||
!g_variant_is_of_type (gpu, G_VARIANT_TYPE ("a{s*}")))
continue;
return ret;
name = g_variant_lookup_value (gpu, "Name", NULL);
env = g_variant_lookup_value (gpu, "Environment", NULL);
if (!name || !env)
continue;
name_s = g_variant_get_string (name, NULL);
g_debug ("Getting renderer from helper for GPU '%s'", name_s);
env_s = g_variant_get_strv (env, NULL);
renderer = get_renderer_from_helper (env_s);
/* We could give up if we don't have a renderer, but that
* might just mean gnome-session isn't installed. We fall back
* to the device name in udev instead, which is better than nothing */
gpu_data = g_new0 (GpuData, 1);
gpu_data->name = g_strdup (renderer ? renderer : name_s);
gpu_data->is_default = is_default ? g_variant_get_boolean (is_default) : FALSE;
renderers = g_slist_prepend (renderers, gpu_data);
}
renderers = g_slist_sort (renderers, gpu_data_sort);
for (l = renderers; l != NULL; l = l->next)
{
GpuData *data = l->data;
if (renderers_string->len > 0)
g_string_append (renderers_string, " / ");
g_string_append (renderers_string, data->name);
}
g_slist_free_full (renderers, (GDestroyNotify) gpu_data_free);
if (renderers_string->len == 0)
{
g_string_free (renderers_string, TRUE);
return NULL;
}
return g_string_free (renderers_string, FALSE);
}
static gchar *
@ -308,22 +396,14 @@ get_graphics_hardware_string (void)
g_autofree char *discrete_renderer = NULL;
g_autofree char *renderer = NULL;
renderer = get_renderer_from_session ();
renderer = get_renderer_from_switcheroo ();
if (!renderer)
renderer = get_renderer_from_helper (FALSE);
if (has_dual_gpu ())
discrete_renderer = get_renderer_from_helper (TRUE);
if (renderer != NULL)
{
if (discrete_renderer != NULL)
return g_strdup_printf ("%s / %s",
renderer,
discrete_renderer);
return g_strdup (renderer);
}
return g_strdup (_("Unknown"));
renderer = get_renderer_from_session ();
if (!renderer)
renderer = get_renderer_from_helper (NULL);
if (!renderer)
return g_strdup (_("Unknown"));
return g_strdup (renderer);
}
static char *