diff --git a/bin/system-info.c b/bin/system-info.c
index 42fd5b1f0a0f58f2bfe2b70553a9abfe53e99c9c..2be787c1f05fc359dde8aefd05863d3e7a088747 100644
--- a/bin/system-info.c
+++ b/bin/system-info.c
@@ -244,6 +244,29 @@ jsonify_graphics_issues (JsonBuilder *builder,
     json_builder_add_string_value (builder, "software-rendering");
 }
 
+static void
+jsonify_graphics_library_vendor (JsonBuilder *builder,
+                                 SrtGraphicsLibraryVendor vendor)
+{
+  if (vendor == SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN)
+    json_builder_add_string_value (builder, "unknown");
+
+  else if (vendor == SRT_GRAPHICS_LIBRARY_VENDOR_GLVND)
+    json_builder_add_string_value (builder, "glvnd");
+
+  else if (vendor == SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN_NON_GLVND)
+    json_builder_add_string_value (builder, "unknown-non-glvnd");
+
+  else if (vendor == SRT_GRAPHICS_LIBRARY_VENDOR_MESA)
+    json_builder_add_string_value (builder, "mesa");
+
+  else if (vendor == SRT_GRAPHICS_LIBRARY_VENDOR_NVIDIA)
+    json_builder_add_string_value (builder, "nvidia");
+
+  else
+    json_builder_add_string_value (builder, "unexpected-vendor");
+}
+
 static void
 jsonify_steam_issues (JsonBuilder *builder,
                       SrtSteamIssues issues)
@@ -405,6 +428,7 @@ print_graphics_details(JsonBuilder *builder,
     {
       gchar *parameters = srt_graphics_dup_parameters_string (g->data);
       const char *messages;
+      SrtGraphicsLibraryVendor library_vendor;
 
       json_builder_set_member_name (builder, parameters);
       json_builder_begin_object (builder);
@@ -421,6 +445,12 @@ print_graphics_details(JsonBuilder *builder,
       json_builder_add_string_value (builder, srt_graphics_get_renderer_string (g->data));
       json_builder_set_member_name (builder, "version");
       json_builder_add_string_value (builder, srt_graphics_get_version_string (g->data));
+      if (srt_graphics_get_rendering_interface (g->data) != SRT_RENDERING_INTERFACE_VULKAN)
+        {
+          json_builder_set_member_name (builder, "library-vendor");
+          srt_graphics_library_is_vendor_neutral (g->data, &library_vendor);
+          jsonify_graphics_library_vendor (builder, library_vendor);
+        }
 
       if (srt_graphics_get_issues (g->data) != SRT_GRAPHICS_ISSUES_NONE)
         {
diff --git a/steam-runtime-tools/graphics-internal.h b/steam-runtime-tools/graphics-internal.h
index 421587a9a65b4a1fa77768b591c7ca9601f072d9..a4a5c67df1a599f5c4d09f4832dd12a4a2acf61b 100644
--- a/steam-runtime-tools/graphics-internal.h
+++ b/steam-runtime-tools/graphics-internal.h
@@ -46,6 +46,7 @@
 static inline SrtGraphics *_srt_graphics_new (const char *multiarch_tuple,
                                               SrtWindowSystem window_system,
                                               SrtRenderingInterface rendering_interface,
+                                              SrtGraphicsLibraryVendor library_vendor,
                                               const gchar *renderer_string,
                                               const gchar *version_string,
                                               SrtGraphicsIssues issues,
@@ -77,6 +78,7 @@ static inline SrtGraphics *
 _srt_graphics_new (const char *multiarch_tuple,
                    SrtWindowSystem window_system,
                    SrtRenderingInterface rendering_interface,
+                   SrtGraphicsLibraryVendor library_vendor,
                    const gchar *renderer_string,
                    const gchar *version_string,
                    SrtGraphicsIssues issues,
@@ -86,6 +88,7 @@ _srt_graphics_new (const char *multiarch_tuple,
   return g_object_new (SRT_TYPE_GRAPHICS,
                        "multiarch-tuple", multiarch_tuple,
                        "issues", issues,
+                       "library-vendor", library_vendor,
                        "window-system", window_system,
                        "rendering-interface", rendering_interface,
                        "renderer-string", renderer_string,
diff --git a/steam-runtime-tools/graphics.c b/steam-runtime-tools/graphics.c
index 558c53e38a4ea41914ad8ff2b6ab556854cc33eb..9c63a9206c67c012e839643d73989f18969235a8 100644
--- a/steam-runtime-tools/graphics.c
+++ b/steam-runtime-tools/graphics.c
@@ -71,6 +71,7 @@ struct _SrtGraphics
   SrtWindowSystem window_system;
   SrtRenderingInterface rendering_interface;
   SrtGraphicsIssues issues;
+  SrtGraphicsLibraryVendor library_vendor;
   gchar *messages;
   gchar *renderer_string;
   gchar *version_string;
@@ -85,6 +86,7 @@ struct _SrtGraphicsClass
 enum {
   PROP_0,
   PROP_ISSUES,
+  PROP_LIBRARY_VENDOR,
   PROP_MESSAGES,
   PROP_MULTIARCH_TUPLE,
   PROP_WINDOW_SYSTEM,
@@ -115,6 +117,10 @@ srt_graphics_get_property (GObject *object,
         g_value_set_flags (value, self->issues);
         break;
 
+      case PROP_LIBRARY_VENDOR:
+        g_value_set_enum (value, self->library_vendor);
+        break;
+
       case PROP_MESSAGES:
         g_value_set_string (value, self->messages);
         break;
@@ -161,6 +167,12 @@ srt_graphics_set_property (GObject *object,
         self->issues = g_value_get_flags (value);
         break;
 
+      case PROP_LIBRARY_VENDOR:
+        /* Construct-only */
+        g_return_if_fail (self->library_vendor == 0);
+        self->library_vendor = g_value_get_enum (value);
+        break;
+
       case PROP_MESSAGES:
         /* Construct-only */
         g_return_if_fail (self->messages == NULL);
@@ -240,6 +252,12 @@ srt_graphics_class_init (SrtGraphicsClass *cls)
                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                         G_PARAM_STATIC_STRINGS);
 
+  properties[PROP_LIBRARY_VENDOR] =
+    g_param_spec_enum ("library-vendor", "Library vendor", "Which library vendor is currently in use.",
+                        SRT_TYPE_GRAPHICS_LIBRARY_VENDOR, SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN,
+                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS);
+
   properties[PROP_MESSAGES] =
     g_param_spec_string ("messages", "Messages",
                          "Diagnostic messages produced while checking this "
@@ -541,7 +559,6 @@ _argv_for_graphics_test (const char *helpers_path,
   return argv;
 }
 
-
 static GPtrArray *
 _argv_for_check_vulkan (const char *helpers_path,
                         SrtTestFlags test_flags,
@@ -576,6 +593,94 @@ _argv_for_check_vulkan (const char *helpers_path,
   return argv;
 }
 
+/**
+ * _srt_check_library_vendor:
+ * @multiarch_tuple: A multiarch tuple to check e.g. i386-linux-gnu
+ * @window_system: The window system to check.
+ * @rendering_interface: The graphics renderer to check.
+ *
+ * Return whether the entry-point library for this graphics stack is vendor-neutral or
+ * vendor-specific, and if vendor-specific, attempt to guess the vendor.
+ *
+ * For newer GLX and EGL graphics stacks (since 2017-2018) the entry-point library is
+ * provided by GLVND, a vendor-neutral dispatch library that loads vendor-specific ICDs.
+ * This function returns %SRT_GRAPHICS_DRIVER_VENDOR_GLVND.
+ *
+ * For older GLX and EGL graphics stacks, the entry-point library libGL.so.1 or libEGL.so.1
+ * is part of a particular vendor's graphics library, usually Mesa or NVIDIA. This function
+ * attempts to determine which one.
+ *
+ * For Vulkan the entry-point library libvulkan.so.1 is always vendor-neutral
+ * (similar to GLVND), so this function is not useful. It always returns
+ * %SRT_GRAPHICS_DRIVER_VENDOR_UNKNOWN.
+ *
+ * Returns: the graphics library vendor currently in use, or
+ *  %SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN if the rendering interface is
+ *  %SRT_RENDERING_INTERFACE_VULKAN or if there was a problem loading the library.
+ */
+static SrtGraphicsLibraryVendor
+_srt_check_library_vendor (const char *multiarch_tuple,
+                           SrtWindowSystem window_system,
+                           SrtRenderingInterface rendering_interface)
+{
+  SrtGraphicsLibraryVendor library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN;
+  const gchar *soname = NULL;
+  SrtLibrary *library = NULL;
+  SrtLibraryIssues issues;
+  const char * const *dependencies;
+
+  /* Vulkan is always vendor-neutral, so it doesn't make sense to check it. We simply return
+   * SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN */
+  if (rendering_interface == SRT_RENDERING_INTERFACE_VULKAN)
+    goto out;
+
+  switch (window_system)
+    {
+      case SRT_WINDOW_SYSTEM_GLX:
+      case SRT_WINDOW_SYSTEM_X11:
+        soname = "libGL.so.1";
+        break;
+
+      case SRT_WINDOW_SYSTEM_EGL_X11:
+        soname = "libEGL.so.1";
+        break;
+
+      default:
+        g_return_val_if_reached (SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN);
+    }
+
+  issues = srt_check_library_presence (soname, multiarch_tuple, NULL, SRT_LIBRARY_SYMBOLS_FORMAT_PLAIN, &library);
+
+  if ((issues & SRT_LIBRARY_ISSUES_CANNOT_LOAD) != 0)
+    goto out;
+
+  dependencies = srt_library_get_dependencies (library);
+  library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN_NON_GLVND;
+
+  for (gsize i = 0; dependencies[i] != NULL; i++)
+    {
+      if (strstr (dependencies[i], "/libGLdispatch.so.") != NULL)
+        {
+          library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_GLVND;
+          break;
+        }
+      if (strstr (dependencies[i], "/libglapi.so.") != NULL)
+        {
+          library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_MESA;
+          break;
+        }
+      if (strstr (dependencies[i], "/libnvidia-") != NULL)
+        {
+          library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_NVIDIA;
+          break;
+        }
+    }
+
+out:
+  g_clear_pointer (&library, g_object_unref);
+  return library_vendor;
+}
+
 /**
  * _srt_check_graphics:
  * @helpers_path: An optional path to find wflinfo helpers, PATH is used if null.
@@ -611,6 +716,7 @@ _srt_check_graphics (const char *helpers_path,
   GStrv my_environ = NULL;
   const gchar *ld_preload;
   gchar *filtered_preload = NULL;
+  SrtGraphicsLibraryVendor library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN;
   gboolean parse_wflinfo = (rendering_interface != SRT_RENDERING_INTERFACE_VULKAN);
 
   g_return_val_if_fail (details_out == NULL || *details_out == NULL, SRT_GRAPHICS_ISSUES_INTERNAL_ERROR);
@@ -637,6 +743,8 @@ _srt_check_graphics (const char *helpers_path,
       my_environ = g_environ_setenv (my_environ, "LD_PRELOAD", filtered_preload, TRUE);
     }
 
+  library_vendor = _srt_check_library_vendor (multiarch_tuple, window_system, rendering_interface);
+
   if (!g_spawn_sync (NULL,    /* working directory */
                      (gchar **) argv->pdata,
                      my_environ,    /* envp */
@@ -747,6 +855,7 @@ out:
     *details_out = _srt_graphics_new (multiarch_tuple,
                                       window_system,
                                       rendering_interface,
+                                      library_vendor,
                                       renderer_string,
                                       version_string,
                                       issues,
@@ -781,6 +890,31 @@ srt_graphics_get_issues (SrtGraphics *self)
   return self->issues;
 }
 
+/**
+ * srt_graphics_library_is_vendor_neutral:
+ * @self: A #SrtGraphics object
+ * @vendor_out: (out) (optional): Used to return a #SrtGraphicsLibraryVendor object
+ *  representing whether the entry-point library for this graphics stack is vendor-neutral
+ *  or vendor-specific, and if vendor-specific, attempt to guess the vendor
+ *
+ * Return whether the entry-point library for this graphics stack is vendor-neutral or vendor-specific.
+ * Vulkan is always vendor-neutral, so this function will always return %TRUE for it.
+ *
+ * Returns: %TRUE if the graphics library is vendor-neutral, %FALSE otherwise.
+ */
+gboolean
+srt_graphics_library_is_vendor_neutral (SrtGraphics *self,
+                                        SrtGraphicsLibraryVendor *vendor_out)
+{
+  g_return_val_if_fail (SRT_IS_GRAPHICS (self), FALSE);
+
+  if (vendor_out != NULL)
+    *vendor_out = self->library_vendor;
+
+  return (self->rendering_interface == SRT_RENDERING_INTERFACE_VULKAN ||
+          self->library_vendor == SRT_GRAPHICS_LIBRARY_VENDOR_GLVND);
+}
+
 /**
  * srt_graphics_get_multiarch_tuple:
  * @self: a graphics object
diff --git a/steam-runtime-tools/graphics.h b/steam-runtime-tools/graphics.h
index d241e6c9d370180ae8e77d15646cad5a1b9b3a1e..8465a9987e90cc40aebf79a55ff478aa87a6c8aa 100644
--- a/steam-runtime-tools/graphics.h
+++ b/steam-runtime-tools/graphics.h
@@ -71,6 +71,24 @@ typedef enum
   SRT_GRAPHICS_ISSUES_CANNOT_DRAW = (1 << 4)
 } SrtGraphicsIssues;
 
+/**
+ * SrtGraphicsLibraryVendor:
+ * @SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN: Unable to check the graphics driver vendor
+ * @SRT_GRAPHICS_LIBRARY_VENDOR_GLVND: The graphics driver is the vendor-neutral GLVND
+ * @SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN_NON_GLVND: The graphics driver is non-GLVND,
+ *  but the exact vendor is unknown
+ * @SRT_GRAPHICS_LIBRARY_VENDOR_MESA: The graphics driver is the mesa non-GLVND
+ * @SRT_GRAPHICS_LIBRARY_VENDOR_NVIDIA: The graphics driver is the Nvidia non-GLVND
+ */
+typedef enum
+{
+  SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN,
+  SRT_GRAPHICS_LIBRARY_VENDOR_GLVND,
+  SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN_NON_GLVND,
+  SRT_GRAPHICS_LIBRARY_VENDOR_MESA,
+  SRT_GRAPHICS_LIBRARY_VENDOR_NVIDIA,
+} SrtGraphicsLibraryVendor;
+
 /**
  * SrtWindowSystem:
  * @SRT_WINDOW_SYSTEM_X11: X11 window system, with GL: equivalent to GLX; with GLES: equivalent to EGL_X11; with Vulkan: use X11
@@ -104,6 +122,8 @@ typedef enum
 
 const char *srt_graphics_get_multiarch_tuple (SrtGraphics *self);
 SrtGraphicsIssues srt_graphics_get_issues (SrtGraphics *self);
+gboolean srt_graphics_library_is_vendor_neutral (SrtGraphics *self,
+                                                 SrtGraphicsLibraryVendor *vendor_out);
 SrtWindowSystem srt_graphics_get_window_system (SrtGraphics *self);
 SrtRenderingInterface srt_graphics_get_rendering_interface (SrtGraphics *self);
 const char *srt_graphics_get_version_string (SrtGraphics *self);
diff --git a/tests/graphics.c b/tests/graphics.c
index 2ea2482476d15f146d030a9ed724e7a0a5c8fc89..3cd18da32d5fbb920e162f1e4589326c1304f7eb 100644
--- a/tests/graphics.c
+++ b/tests/graphics.c
@@ -194,6 +194,8 @@ test_object (Fixture *f,
 {
   SrtGraphics *graphics;
   SrtGraphicsIssues issues;
+  SrtGraphicsLibraryVendor library_vendor;
+  gboolean vendor_neutral;
   gchar *messages;
   gchar *tuple;
   gchar *renderer;
@@ -202,6 +204,7 @@ test_object (Fixture *f,
   graphics = _srt_graphics_new("mock-good",
                                SRT_WINDOW_SYSTEM_GLX,
                                SRT_RENDERING_INTERFACE_GL,
+                               SRT_GRAPHICS_LIBRARY_VENDOR_GLVND,
                                SRT_TEST_GOOD_GRAPHICS_RENDERER,
                                SRT_TEST_GOOD_GRAPHICS_VERSION,
                                SRT_GRAPHICS_ISSUES_NONE,
@@ -215,14 +218,19 @@ test_object (Fixture *f,
   g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==,
                    SRT_TEST_GOOD_GRAPHICS_VERSION);
   g_assert_cmpstr (srt_graphics_get_messages (graphics), ==, NULL);
+  vendor_neutral = srt_graphics_library_is_vendor_neutral (graphics, &library_vendor);
+  g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_GLVND);
+  g_assert_true (vendor_neutral);
   g_object_get (graphics,
                 "messages", &messages,
                 "multiarch-tuple", &tuple,
                 "issues", &issues,
+                "library-vendor", &library_vendor,
                 "renderer-string", &renderer,
                 "version-string", &version,
                 NULL);
   g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_NONE);
+  g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_GLVND);
   g_assert_cmpstr (messages, ==, NULL);
   g_assert_cmpstr (tuple, ==, "mock-good");
   g_assert_cmpstr (renderer, ==, SRT_TEST_GOOD_GRAPHICS_RENDERER);
@@ -287,6 +295,8 @@ test_bad_graphics (Fixture *f,
 {
   SrtGraphics *graphics = NULL;
   SrtGraphicsIssues issues;
+  SrtGraphicsLibraryVendor library_vendor;
+  gboolean vendor_neutral;
   gchar *messages;
   gchar *tuple;
   gchar *renderer;
@@ -307,14 +317,22 @@ test_bad_graphics (Fixture *f,
                    NULL);
   g_assert_cmpstr (srt_graphics_get_messages (graphics), ==,
                    "Waffle error: 0x2 WAFFLE_ERROR_UNKNOWN: XOpenDisplay failed\n");
+  /* We used "mock-bad" for the architecture so, when checking the library vendor,
+   * we will not be able to call the helper `mock-bad-check-library`.
+   * For this reason we expect %SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN */
+  vendor_neutral = srt_graphics_library_is_vendor_neutral (graphics, &library_vendor);
+  g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN);
+  g_assert_false (vendor_neutral);
   g_object_get (graphics,
                 "messages", &messages,
                 "multiarch-tuple", &tuple,
                 "issues", &issues,
+                "library-vendor", &library_vendor,
                 "renderer-string", &renderer,
                 "version-string", &version,
                 NULL);
   g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_CANNOT_LOAD);
+  g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN);
   g_assert_cmpstr (messages, ==,
                    "Waffle error: 0x2 WAFFLE_ERROR_UNKNOWN: XOpenDisplay failed\n");
   g_assert_cmpstr (tuple, ==, "mock-bad");