diff options
Diffstat (limited to '')
-rw-r--r-- | tools/gnome-session-check-accelerated.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/tools/gnome-session-check-accelerated.c b/tools/gnome-session-check-accelerated.c new file mode 100644 index 0000000..31f0a52 --- /dev/null +++ b/tools/gnome-session-check-accelerated.c @@ -0,0 +1,312 @@ +/* -*- mode:c; c-basic-offset: 8; indent-tabs-mode: nil; -*- */ +/* Tool to set the property _GNOME_SESSION_ACCELERATED on the root window */ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: + * Colin Walters <walters@verbum.org> + */ + +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include <gtk/gtk.h> +#include <epoxy/gl.h> +#include <gdk/gdkx.h> +#include <X11/Xatom.h> +#include <sys/wait.h> + +#include "gnome-session-check-accelerated-common.h" + +/* Wait up to this long for a running check to finish */ +#define PROPERTY_CHANGE_TIMEOUT 5000 + +/* Values used for the _GNOME_SESSION_ACCELERATED root window property */ +#define NO_ACCEL 0 +#define HAVE_ACCEL 1 +#define ACCEL_CHECK_RUNNING 2 + +static Atom is_accelerated_atom; +static Atom is_software_rendering_atom; +static Atom renderer_atom; +static gboolean property_changed; + +static gboolean +on_property_notify_timeout (gpointer data) +{ + gtk_main_quit (); + return FALSE; +} + +static GdkFilterReturn +property_notify_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XPropertyEvent *ev = xevent; + + if (ev->type == PropertyNotify && ev->atom == is_accelerated_atom) { + property_changed = TRUE; + gtk_main_quit (); + } + + return GDK_FILTER_CONTINUE; +} + +static gboolean +wait_for_property_notify (void) +{ + GdkDisplay *display; + GdkScreen *screen; + GdkWindow *root; + Window rootwin; + + property_changed = FALSE; + + display = gdk_display_get_default (); + screen = gdk_display_get_default_screen (display); + root = gdk_screen_get_root_window (screen); + rootwin = gdk_x11_window_get_xid (root); + + XSelectInput (GDK_DISPLAY_XDISPLAY (display), rootwin, PropertyChangeMask); + gdk_window_add_filter (root, property_notify_filter, NULL); + g_timeout_add (PROPERTY_CHANGE_TIMEOUT, on_property_notify_timeout, NULL); + + gtk_main (); + + return property_changed; +} + +static char * +get_gtk_gles_renderer (void) +{ + GtkWidget *win; + GdkGLContext *context; + char *renderer = NULL; + + win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_realize (win); + context = gdk_window_create_gl_context (gtk_widget_get_window (win), NULL); + if (!context) + return NULL; + gdk_gl_context_make_current (context); + renderer = g_strdup ((char *) glGetString (GL_RENDERER)); + gdk_gl_context_clear_current (); + g_object_unref (context); + + return renderer; +} + +static gboolean +is_discrete_gpu_check (void) +{ + const char *dri_prime; + + dri_prime = g_getenv ("DRI_PRIME"); + if (!dri_prime) + return FALSE; + if (*dri_prime != '1') + return FALSE; + return TRUE; +} + +int +main (int argc, char **argv) +{ + GdkDisplay *display = NULL; + int estatus; + char *gl_helper_argv[] = { LIBEXECDIR "/gnome-session-check-accelerated-gl-helper", "--print-renderer", NULL }; + char *gles_helper_argv[] = { LIBEXECDIR "/gnome-session-check-accelerated-gles-helper", "--print-renderer", NULL }; + char *renderer_string = NULL; + char *gl_renderer_string = NULL, *gles_renderer_string = NULL; + gboolean gl_software_rendering = FALSE, gles_software_rendering = FALSE; + Window rootwin; + glong is_accelerated, is_software_rendering; + GError *gl_error = NULL, *gles_error = NULL; + + gtk_init (NULL, NULL); + + /* gnome-session-check-accelerated gets run before X is started in the wayland + * case, and it currently requires X. Until we have that working, just always + * assume wayland will work. + * Also make sure that we don't read cached information about the first GPU + * when requesting information about the second. + */ + if (is_discrete_gpu_check () || g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "x11") != 0) { + renderer_string = get_gtk_gles_renderer (); + if (renderer_string) { + g_print ("%s", renderer_string); + return 0; + } + return 1; + } + + display = gdk_display_get_default (); + /* when running on X11 with a nested wayland GDK will default to wayland + * so looking for X11 atoms will not work (and crash). + */ + if (!GDK_IS_X11_DISPLAY (display)) { + g_printerr ("gnome-session-check-accelerated: no X11 display found\n"); + return 1; + } + + rootwin = gdk_x11_get_default_root_xwindow (); + + is_accelerated_atom = gdk_x11_get_xatom_by_name_for_display (display, "_GNOME_SESSION_ACCELERATED"); + is_software_rendering_atom = gdk_x11_get_xatom_by_name_for_display (display, "_GNOME_IS_SOFTWARE_RENDERING"); + renderer_atom = gdk_x11_get_xatom_by_name_for_display (display, "_GNOME_SESSION_RENDERER"); + + { + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + guchar *data; + + read: + gdk_x11_display_error_trap_push (display); + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), rootwin, + is_accelerated_atom, + 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, + &bytes_after, &data); + gdk_x11_display_error_trap_pop_ignored (display); + + if (type == XA_CARDINAL) { + glong *is_accelerated_ptr = (glong*) data; + + if (*is_accelerated_ptr == ACCEL_CHECK_RUNNING) { + /* Test in progress, wait */ + if (wait_for_property_notify ()) + goto read; + /* else fall through and do the check ourselves */ + + } else { + gdk_x11_display_error_trap_push (display); + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), rootwin, + renderer_atom, + 0, G_MAXLONG, False, XA_STRING, &type, &format, &nitems, + &bytes_after, &data); + gdk_x11_display_error_trap_pop_ignored (display); + + if (type == XA_STRING) { + g_print ("%s", data); + } + + return (*is_accelerated_ptr == 0 ? 1 : 0); + } + } + } + + /* We don't have the property or it's the wrong type. + * Try to compute it now. + */ + + /* First indicate that a test is in progress */ + is_accelerated = ACCEL_CHECK_RUNNING; + is_software_rendering = FALSE; + estatus = 1; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + rootwin, + is_accelerated_atom, + XA_CARDINAL, 32, PropModeReplace, (guchar *) &is_accelerated, 1); + + gdk_display_sync (display); + + /* First, try the GL helper */ + if (g_spawn_sync (NULL, (char **) gl_helper_argv, NULL, 0, + NULL, NULL, &gl_renderer_string, NULL, &estatus, &gl_error)) { + is_accelerated = (WEXITSTATUS(estatus) == HELPER_ACCEL); + gl_software_rendering = (WEXITSTATUS(estatus) == HELPER_SOFTWARE_RENDERING); + if (is_accelerated) { + renderer_string = gl_renderer_string; + goto finish; + } + + g_printerr ("gnome-session-check-accelerated: GL Helper exited with code %d\n", estatus); + } + + /* Then, try the GLES helper */ + if (g_spawn_sync (NULL, (char **) gles_helper_argv, NULL, 0, + NULL, NULL, &gles_renderer_string, NULL, &estatus, &gles_error)) { + is_accelerated = (WEXITSTATUS(estatus) == HELPER_ACCEL); + gles_software_rendering = (WEXITSTATUS(estatus) == HELPER_SOFTWARE_RENDERING); + if (is_accelerated) { + renderer_string = gles_renderer_string; + goto finish; + } + + g_printerr ("gnome-session-check-accelerated: GLES Helper exited with code %d\n", estatus); + } + + /* If we got here, GL software rendering is our best bet */ + if (gl_software_rendering || gles_software_rendering) { + is_software_rendering = TRUE; + is_accelerated = TRUE; + + if (gl_software_rendering) + renderer_string = gl_renderer_string; + else if (gles_software_rendering) + renderer_string = gles_renderer_string; + + goto finish; + } + + /* Both helpers failed; print their error messages */ + if (gl_error != NULL) { + g_printerr ("gnome-session-check-accelerated: Failed to run GL helper: %s\n", gl_error->message); + g_clear_error (&gl_error); + } + + if (gles_error != NULL) { + g_printerr ("gnome-session-check-accelerated: Failed to run GLES helper: %s\n", gles_error->message); + g_clear_error (&gles_error); + } + + finish: + if (is_accelerated) { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + rootwin, + is_accelerated_atom, + XA_CARDINAL, 32, PropModeReplace, (guchar *) &is_accelerated, 1); + } + + if (is_software_rendering) { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + rootwin, + is_software_rendering_atom, + XA_CARDINAL, 32, PropModeReplace, (guchar *) &is_software_rendering, 1); + } + + if (renderer_string != NULL) { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + rootwin, + renderer_atom, + XA_STRING, 8, PropModeReplace, (guchar *) renderer_string, strlen (renderer_string)); + + /* Print the renderer */ + g_print ("%s", renderer_string); + } + + gdk_display_sync (display); + + g_free (gl_renderer_string); + g_free (gles_renderer_string); + + return is_accelerated ? 0 : 1; +} |