Bug 1294232 - Refactor blocklisting on Linux to support the downloadable blocklist. r=jrmuizel
authorAndrew Comminos <andrew@comminos.com>
Fri, 08 Feb 2019 14:36:08 -0500
changeset 506562 8962b8d9b7a673288218ed9087102032d7cf015b
parent 506561 52390d9090fbd8d46b00ea29034e7039511ff8a4
child 506563 fa767271520314149dfa231a5f3e265a533c91db
push id138
push usermtabara@mozilla.com
push dateWed, 20 Mar 2019 18:12:49 +0000
reviewersjrmuizel
bugs1294232
milestone68.0a1
Bug 1294232 - Refactor blocklisting on Linux to support the downloadable blocklist. r=jrmuizel MozReview-Commit-ID: ESJY9kkqXR8 Differential Revision: https://phabricator.services.mozilla.com/D19190
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
toolkit/xre/glxtest.cpp
widget/GfxDriverInfo.cpp
widget/GfxDriverInfo.h
widget/GfxInfoBase.cpp
widget/GfxInfoBase.h
widget/GfxInfoX11.cpp
widget/GfxInfoX11.h
widget/android/GfxInfo.cpp
widget/cocoa/GfxInfo.mm
widget/nsIGfxInfoDebug.idl
widget/windows/GfxInfo.cpp
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -286,16 +286,17 @@ function spoofTheme(aId, aName, aDesc) {
     textcolor: Math.random().toString(),
     accentcolor: Math.random().toString(),
   };
 }
 
 function spoofGfxAdapter() {
   try {
     let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
+    gfxInfo.fireTestProcess();
     gfxInfo.spoofVendorID(GFX_VENDOR_ID);
     gfxInfo.spoofDeviceID(GFX_DEVICE_ID);
   } catch (x) {
     // If we can't test gfxInfo, that's fine, we'll note it later.
   }
 }
 
 function spoofProfileReset() {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabcd");
       gfxInfo.spoofDeviceID("0x9876");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabcd");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2202");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xdcdc");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.1112");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
@@ -26,16 +26,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xdcdc");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.1110");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xdcdc");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.1111");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabab");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabab");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2202");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   gfxInfo.spoofVendorID("0xabcd");
   gfxInfo.spoofDeviceID("0x6666");
 
   // Spoof the OS version so it matches the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabcd");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
@@ -24,16 +24,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   gfxInfo.spoofDriverVersion("8.52.322.2201");
   gfxInfo.spoofVendorID("0xabcd");
   gfxInfo.spoofDeviceID("0x1234");
 
   // Spoof the version of the OS appropriately to test the test file.
   switch (Services.appinfo.OS) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   gfxInfo.spoofDriverVersion("8.52.322.2202");
   gfxInfo.spoofVendorID("0xabcd");
   gfxInfo.spoofDeviceID("0x1234");
 
   // Spoof the version of the OS appropriately to test the test file.
   switch (Services.appinfo.OS) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   gfxInfo.spoofDriverVersion("8.52.322.2201");
   gfxInfo.spoofVendorID("0xabcd");
   gfxInfo.spoofDeviceID("0x1234");
 
   // Spoof the version of the OS appropriately to test the test file.
   switch (Services.appinfo.OS) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
@@ -25,16 +25,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xdcba");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
@@ -24,16 +24,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabcd");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
@@ -29,16 +29,17 @@ async function run_test() {
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
   }
 
   gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug);
+  gfxInfo.fireTestProcess();
 
   // Set the vendor/device ID, etc, to match the test file.
   switch (Services.appinfo.OS) {
     case "WINNT":
       gfxInfo.spoofVendorID("0xabcd");
       gfxInfo.spoofDeviceID("0x1234");
       gfxInfo.spoofDriverVersion("8.52.322.2201");
       // Windows 7
--- a/toolkit/xre/glxtest.cpp
+++ b/toolkit/xre/glxtest.cpp
@@ -53,16 +53,30 @@ typedef XID GLXPbuffer;
 
 // stuff from gl.h
 typedef uint8_t GLubyte;
 typedef uint32_t GLenum;
 #define GL_VENDOR 0x1F00
 #define GL_RENDERER 0x1F01
 #define GL_VERSION 0x1F02
 
+// GLX_MESA_query_renderer
+#define GLX_RENDERER_VENDOR_ID_MESA                            0x8183
+#define GLX_RENDERER_DEVICE_ID_MESA                            0x8184
+#define GLX_RENDERER_VERSION_MESA                              0x8185
+#define GLX_RENDERER_ACCELERATED_MESA                          0x8186
+#define GLX_RENDERER_VIDEO_MEMORY_MESA                         0x8187
+#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA          0x8188
+#define GLX_RENDERER_PREFERRED_PROFILE_MESA                    0x8189
+#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA          0x818A
+#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
+#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA            0x818C
+#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA           0x818D
+#define GLX_RENDERER_ID_MESA                                   0x818E
+
 namespace mozilla {
 namespace widget {
 // the read end of the pipe, which will be used by GfxInfo
 extern int glxtest_pipe;
 // the PID of the glxtest process, to pass to waitpid()
 extern pid_t glxtest_pid;
 }  // namespace widget
 }  // namespace mozilla
@@ -196,32 +210,72 @@ void glxtest() {
   ///// Get a GL context and make it current //////
   GLXContext context = glXCreateContext(dpy, vInfo, nullptr, True);
   glXMakeCurrent(dpy, window, context);
 
   ///// Look for this symbol to determine texture_from_pixmap support /////
   void *glXBindTexImageEXT = glXGetProcAddress("glXBindTexImageEXT");
 
   ///// Get GL vendor/renderer/versions strings /////
-  enum { bufsize = 1024 };
+  enum { bufsize = 2048 };
   char buf[bufsize];
-  const GLubyte *vendorString = glGetString(GL_VENDOR);
-  const GLubyte *rendererString = glGetString(GL_RENDERER);
-  const GLubyte *versionString = glGetString(GL_VERSION);
+  const GLubyte* versionString = glGetString(GL_VERSION);
+  const GLubyte* vendorString = glGetString(GL_VENDOR);
+  const GLubyte* rendererString = glGetString(GL_RENDERER);
 
-  if (!vendorString || !rendererString || !versionString)
+  if (!versionString || !vendorString || !rendererString)
     fatal_error("glGetString returned null");
 
   int length =
       snprintf(buf, bufsize, "VENDOR\n%s\nRENDERER\n%s\nVERSION\n%s\nTFP\n%s\n",
                vendorString, rendererString, versionString,
                glXBindTexImageEXT ? "TRUE" : "FALSE");
   if (length >= bufsize)
     fatal_error("GL strings length too large for buffer size");
 
+  // If GLX_MESA_query_renderer is available, populate additional data.
+  typedef Bool (*PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int* value);
+  PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glXQueryCurrentRendererIntegerMESAProc =
+    cast<PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC>(glXGetProcAddress("glXQueryCurrentRendererIntegerMESA"));
+  if (glXQueryCurrentRendererIntegerMESAProc) {
+    unsigned int vendorId, deviceId, accelerated, videoMemoryMB;
+    glXQueryCurrentRendererIntegerMESAProc(GLX_RENDERER_VENDOR_ID_MESA, &vendorId);
+    glXQueryCurrentRendererIntegerMESAProc(GLX_RENDERER_DEVICE_ID_MESA, &deviceId);
+    glXQueryCurrentRendererIntegerMESAProc(GLX_RENDERER_ACCELERATED_MESA, &accelerated);
+    glXQueryCurrentRendererIntegerMESAProc(GLX_RENDERER_VIDEO_MEMORY_MESA, &videoMemoryMB);
+
+    // Truncate IDs to 4 digits- that's all PCI IDs are.
+    vendorId &= 0xFFFF;
+    deviceId &= 0xFFFF;
+
+    length += snprintf(buf + length, bufsize,
+                       "MESA_VENDOR_ID\n0x%04x\n"
+                       "MESA_DEVICE_ID\n0x%04x\n"
+                       "MESA_ACCELERATED\n%s\n"
+                       "MESA_VRAM\n%dMB\n",
+                       vendorId, deviceId, accelerated ? "TRUE" : "FALSE",
+                       videoMemoryMB);
+
+    if (length >= bufsize)
+      fatal_error("GL strings length too large for buffer size");
+  }
+
+  // From Mesa's GL/internal/dri_interface.h, to be used by DRI clients.
+  typedef const char * (* PFNGLXGETSCREENDRIVERPROC) (Display *dpy, int scrNum);
+  PFNGLXGETSCREENDRIVERPROC glXGetScreenDriverProc =
+    cast<PFNGLXGETSCREENDRIVERPROC>(glXGetProcAddress("glXGetScreenDriver"));
+  if (glXGetScreenDriverProc) {
+    const char* driDriver = glXGetScreenDriverProc(dpy, DefaultScreen(dpy));
+    if (driDriver) {
+      length += snprintf(buf + length, bufsize, "DRI_DRIVER\n%s\n", driDriver);
+      if (length >= bufsize)
+        fatal_error("GL strings length too large for buffer size");
+    }
+  }
+
   ///// Clean up. Indeed, the parent process might fail to kill us (e.g. if it
   ///// doesn't need to check GL info) so we might be staying alive for longer
   ///// than expected, so it's important to consume as little memory as
   ///// possible. Also we want to check that we're able to do that too without
   ///// generating X errors.
   glXMakeCurrent(dpy, None,
                  nullptr);  // must release the GL context before destroying it
   glXDestroyContext(dpy, context);
--- a/widget/GfxDriverInfo.cpp
+++ b/widget/GfxDriverInfo.cpp
@@ -376,14 +376,19 @@ const nsAString& GfxDriverInfo::GetDevic
     DECLARE_VENDOR_ID(VendorNVIDIA, "0x10de");
     DECLARE_VENDOR_ID(VendorAMD, "0x1022");
     DECLARE_VENDOR_ID(VendorATI, "0x1002");
     DECLARE_VENDOR_ID(VendorMicrosoft, "0x1414");
     DECLARE_VENDOR_ID(VendorParallels, "0x1ab8");
     // Choose an arbitrary Qualcomm PCI VENdor ID for now.
     // TODO: This should be "QCOM" when Windows device ID parsing is reworked.
     DECLARE_VENDOR_ID(VendorQualcomm, "0x5143");
+    DECLARE_VENDOR_ID(VendorMesaAll, "mesa/all");
+    DECLARE_VENDOR_ID(VendorMesaLLVMPipe, "mesa/llvmpipe");
+    DECLARE_VENDOR_ID(VendorMesaSoftPipe, "mesa/softpipe");
+    DECLARE_VENDOR_ID(VendorMesaSWRast, "mesa/swrast");
+    DECLARE_VENDOR_ID(VendorMesaUnknown, "mesa/unknown");
     // Suppress a warning.
     DECLARE_VENDOR_ID(DeviceVendorMax, "");
   }
 
   return *sDeviceVendors[id];
 }
--- a/widget/GfxDriverInfo.h
+++ b/widget/GfxDriverInfo.h
@@ -122,16 +122,28 @@ enum DeviceVendor {
   VendorAll,  // There is an assumption that this is the first enum
   VendorIntel,
   VendorNVIDIA,
   VendorAMD,
   VendorATI,
   VendorMicrosoft,
   VendorParallels,
   VendorQualcomm,
+
+  // Wildcard for all Mesa drivers.
+  VendorMesaAll,
+  // Note that the following list of Mesa drivers is not comprehensive; we pull
+  // the DRI driver at runtime. These drivers are provided for convenience when
+  // populating the local blocklist.
+  VendorMesaLLVMPipe,
+  VendorMesaSoftPipe,
+  VendorMesaSWRast,
+  // A generic ID to be provided when we can't determine the DRI driver on Mesa.
+  VendorMesaUnknown,
+
   DeviceVendorMax
 };
 
 /* Array of devices to match, or an empty array for all devices */
 typedef nsTArray<nsString> GfxDeviceFamily;
 
 struct GfxDriverInfo {
   // If |ownDevices| is true, you are transferring ownership of the devices
@@ -271,17 +283,17 @@ inline void PadDriverDecimal(char *aStri
   }
   aString[4] = 0;
 }
 
 inline bool ParseDriverVersion(const nsAString &aVersion,
                                uint64_t *aNumericVersion) {
   *aNumericVersion = 0;
 
-#if defined(XP_WIN)
+#if defined(XP_WIN) || defined(MOZ_X11)
   int a, b, c, d;
   char aStr[8], bStr[8], cStr[8], dStr[8];
   /* honestly, why do I even bother */
   if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr,
                           bStr, cStr, dStr))
     return false;
 
   PadDriverDecimal(bStr);
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -690,17 +690,17 @@ int32_t GfxInfoBase::FindBlocklistedDevi
       (NS_FAILED(GetAdapterVendorID2(adapterVendorID[1])) ||
        NS_FAILED(GetAdapterDeviceID2(adapterDeviceID[1])) ||
        NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString[1])));
   // No point in going on if we don't have adapter info
   if (adapterInfoFailed[0] && adapterInfoFailed[1]) {
     return 0;
   }
 
-#if defined(XP_WIN) || defined(ANDROID)
+#if defined(XP_WIN) || defined(ANDROID) || defined(MOZ_X11)
   uint64_t driverVersion[2] = {0, 0};
   if (!adapterInfoFailed[0]) {
     ParseDriverVersion(adapterDriverVersionString[0], &driverVersion[0]);
   }
   if (!adapterInfoFailed[1]) {
     ParseDriverVersion(adapterDriverVersionString[1], &driverVersion[1]);
   }
 #endif
@@ -723,21 +723,17 @@ int32_t GfxInfoBase::FindBlocklistedDevi
       continue;
     }
 
     if (info[i].mOperatingSystemVersion &&
         info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
       continue;
     }
 
-    if (!info[i].mAdapterVendor.Equals(
-            GfxDriverInfo::GetDeviceVendor(VendorAll),
-            nsCaseInsensitiveStringComparator()) &&
-        !info[i].mAdapterVendor.Equals(adapterVendorID[infoIndex],
-                                       nsCaseInsensitiveStringComparator())) {
+    if (!DoesVendorMatch(info[i].mAdapterVendor, adapterVendorID[infoIndex])) {
       continue;
     }
 
     if (info[i].mDevices != GfxDriverInfo::allDevices &&
         info[i].mDevices->Length()) {
       bool deviceMatches = false;
       for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
         if ((*info[i].mDevices)[j].Equals(
@@ -764,17 +760,17 @@ int32_t GfxInfoBase::FindBlocklistedDevi
     if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
       continue;
     }
     if (!info[i].mManufacturer.IsEmpty() &&
         !info[i].mManufacturer.Equals(Manufacturer())) {
       continue;
     }
 
-#if defined(XP_WIN) || defined(ANDROID)
+#if defined(XP_WIN) || defined(ANDROID) || defined(MOZ_X11)
     switch (info[i].mComparisonOp) {
       case DRIVER_LESS_THAN:
         match = driverVersion[infoIndex] < info[i].mDriverVersion;
         break;
       case DRIVER_BUILD_ID_LESS_THAN:
         match = (driverVersion[infoIndex] & 0xFFFF) < info[i].mDriverVersion;
         break;
       case DRIVER_LESS_THAN_OR_EQUAL:
@@ -878,16 +874,24 @@ int32_t GfxInfoBase::FindBlocklistedDevi
 }
 
 void GfxInfoBase::SetFeatureStatus(
     const nsTArray<dom::GfxInfoFeatureStatus>& aFS) {
   MOZ_ASSERT(!sFeatureStatus);
   sFeatureStatus = new nsTArray<dom::GfxInfoFeatureStatus>(aFS);
 }
 
+bool GfxInfoBase::DoesVendorMatch(const nsAString& aBlocklistVendor,
+                                  const nsAString& aAdapterVendor) {
+  return aBlocklistVendor.Equals(aAdapterVendor,
+                                 nsCaseInsensitiveStringComparator()) ||
+         aBlocklistVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll),
+                                 nsCaseInsensitiveStringComparator());
+}
+
 nsresult GfxInfoBase::GetFeatureStatusImpl(
     int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedVersion,
     const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
     OperatingSystem* aOS /* = nullptr */) {
   if (aFeature <= 0) {
     gfxWarning() << "Invalid feature <= 0";
     return NS_OK;
   }
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -120,16 +120,20 @@ class GfxInfoBase : public nsIGfxInfo,
       const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
       OperatingSystem* aOS = nullptr);
 
   // Gets the driver info table. Used by GfxInfoBase to check for general cases
   // (while subclasses check for more specific ones).
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() = 0;
 
   virtual void DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> obj);
+
+  virtual bool DoesVendorMatch(const nsAString& aBlocklistVendor,
+                               const nsAString& aAdapterVendor);
+
   bool InitFeatureObject(JSContext* aCx, JS::Handle<JSObject*> aContainer,
                          const char* aName,
                          mozilla::gfx::FeatureStatus& aKnownStatus,
                          JS::MutableHandle<JSObject*> aOutObj);
 
   NS_IMETHOD ControlGPUProcessForXPCShell(bool aEnable, bool* _retval) override;
 
  private:
--- a/widget/GfxInfoX11.cpp
+++ b/widget/GfxInfoX11.cpp
@@ -9,53 +9,52 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <errno.h>
 #include <sys/utsname.h>
 #include "nsCRTGlue.h"
 #include "nsExceptionHandler.h"
 #include "nsICrashReporter.h"
 #include "prenv.h"
+#include "nsPrintfCString.h"
+#include "nsWhitespaceTokenizer.h"
 
 #include "GfxInfoX11.h"
 
+#ifdef DEBUG
+bool fire_glxtest_process();
+#endif
+
 namespace mozilla {
 namespace widget {
 
 #ifdef DEBUG
 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
 #endif
 
 // these global variables will be set when firing the glxtest process
 int glxtest_pipe = -1;
 pid_t glxtest_pid = 0;
 
 nsresult GfxInfo::Init() {
   mGLMajorVersion = 0;
-  mMajorVersion = 0;
-  mMinorVersion = 0;
-  mRevisionVersion = 0;
+  mGLMinorVersion = 0;
+  mHasTextureFromPixmap = false;
   mIsMesa = false;
-  mIsNVIDIA = false;
-  mIsFGLRX = false;
-  mIsNouveau = false;
-  mIsIntel = false;
-  mIsOldSwrast = false;
-  mIsLlvmpipe = false;
-  mHasTextureFromPixmap = false;
+  mIsAccelerated = true;
   return GfxInfoBase::Init();
 }
 
 void GfxInfo::AddCrashReportAnnotations() {
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
-                                     mVendor);
+                                     mVendorId);
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
-                                     mRenderer);
+                                     mDeviceId);
   CrashReporter::AnnotateCrashReport(
-      CrashReporter::Annotation::AdapterDriverVersion, mVersion);
+      CrashReporter::Annotation::AdapterDriverVersion, mDriverVersion);
 }
 
 void GfxInfo::GetData() {
   // to understand this function, see bug 639842. We retrieve the OpenGL driver
   // information in a separate process to protect against bad drivers.
 
   // if glxtest_pipe == -1, that means that we already read the information
   if (glxtest_pipe == -1) return;
@@ -103,60 +102,81 @@ void GfxInfo::GetData() {
                                 WIFEXITED(glxtest_status) &&
                                 WEXITSTATUS(glxtest_status) != EXIT_SUCCESS;
   bool received_signal =
       !waiting_for_glxtest_process_failed && WIFSIGNALED(glxtest_status);
 
   bool error = waiting_for_glxtest_process_failed || exited_with_error_code ||
                received_signal;
 
+  nsCString glVendor;
+  nsCString glRenderer;
+  nsCString glVersion;
   nsCString textureFromPixmap;
+
+  // Available if GLX_MESA_query_renderer is supported.
+  nsCString mesaVendor;
+  nsCString mesaDevice;
+  nsCString mesaAccelerated;
+  // Available if using a DRI-based libGL stack.
+  nsCString driDriver;
+
   nsCString *stringToFill = nullptr;
   char *bufptr = buf;
   if (!error) {
     while (true) {
       char *line = NS_strtok("\n", &bufptr);
       if (!line) break;
       if (stringToFill) {
         stringToFill->Assign(line);
         stringToFill = nullptr;
       } else if (!strcmp(line, "VENDOR"))
-        stringToFill = &mVendor;
+        stringToFill = &glVendor;
       else if (!strcmp(line, "RENDERER"))
-        stringToFill = &mRenderer;
+        stringToFill = &glRenderer;
       else if (!strcmp(line, "VERSION"))
-        stringToFill = &mVersion;
+        stringToFill = &glVersion;
       else if (!strcmp(line, "TFP"))
         stringToFill = &textureFromPixmap;
+      else if (!strcmp(line, "MESA_VENDOR_ID"))
+        stringToFill = &mesaVendor;
+      else if (!strcmp(line, "MESA_DEVICE_ID"))
+        stringToFill = &mesaDevice;
+      else if (!strcmp(line, "MESA_ACCELERATED"))
+        stringToFill = &mesaAccelerated;
+      else if (!strcmp(line, "MESA_VRAM"))
+        stringToFill = &mAdapterRAM;
+      else if (!strcmp(line, "DRI_DRIVER"))
+        stringToFill = &driDriver;
     }
   }
 
   if (!strcmp(textureFromPixmap.get(), "TRUE")) mHasTextureFromPixmap = true;
 
   // only useful for Linux kernel version check for FGLRX driver.
   // assumes X client == X server, which is sad.
   struct utsname unameobj;
   if (uname(&unameobj) >= 0) {
     mOS.Assign(unameobj.sysname);
     mOSRelease.Assign(unameobj.release);
   }
 
   const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
-  if (spoofedVendor) mVendor.Assign(spoofedVendor);
+  if (spoofedVendor) glVendor.Assign(spoofedVendor);
   const char *spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
-  if (spoofedRenderer) mRenderer.Assign(spoofedRenderer);
+  if (spoofedRenderer) glRenderer.Assign(spoofedRenderer);
   const char *spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
-  if (spoofedVersion) mVersion.Assign(spoofedVersion);
+  if (spoofedVersion) glVersion.Assign(spoofedVersion);
   const char *spoofedOS = PR_GetEnv("MOZ_GFX_SPOOF_OS");
   if (spoofedOS) mOS.Assign(spoofedOS);
   const char *spoofedOSRelease = PR_GetEnv("MOZ_GFX_SPOOF_OS_RELEASE");
   if (spoofedOSRelease) mOSRelease.Assign(spoofedOSRelease);
 
-  if (error || mVendor.IsEmpty() || mRenderer.IsEmpty() || mVersion.IsEmpty() ||
-      mOS.IsEmpty() || mOSRelease.IsEmpty()) {
+  if (error || glVendor.IsEmpty() || glRenderer.IsEmpty() ||
+      glVersion.IsEmpty() || mOS.IsEmpty() || mOSRelease.IsEmpty()) {
     mAdapterDescription.AppendLiteral("GLXtest process failed");
     if (waiting_for_glxtest_process_failed)
       mAdapterDescription.AppendPrintf(
           " (waitpid failed with errno=%d for pid %d)", waitpid_errno,
           glxtest_pid);
     if (exited_with_error_code)
       mAdapterDescription.AppendPrintf(" (exited with status %d)",
                                        WEXITSTATUS(glxtest_status));
@@ -168,93 +188,144 @@ void GfxInfo::GetData() {
       mAdapterDescription.Append(nsDependentCString(buf));
       mAdapterDescription.Append('\n');
     }
 
     CrashReporter::AppendAppNotesToCrashReport(mAdapterDescription);
     return;
   }
 
-  mAdapterDescription.Append(mVendor);
-  mAdapterDescription.AppendLiteral(" -- ");
-  mAdapterDescription.Append(mRenderer);
-
-  AddCrashReportAnnotations();
-
-  // determine the major OpenGL version. That's the first integer in the version
-  // string.
-  mGLMajorVersion = strtol(mVersion.get(), 0, 10);
-
-  // determine driver type (vendor) and where in the version string
-  // the actual driver version numbers should be expected to be found
-  // (whereToReadVersionNumbers)
-  const char *whereToReadVersionNumbers = nullptr;
-  const char *Mesa_in_version_string = strstr(mVersion.get(), "Mesa");
-  if (Mesa_in_version_string) {
-    mIsMesa = true;
-    // with Mesa, the version string contains "Mesa major.minor" and that's all
-    // the version information we get: there is no actual driver version info.
-    whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa");
-    if (strcasestr(mVendor.get(), "nouveau")) mIsNouveau = true;
-    if (strcasestr(mRenderer.get(),
-                   "intel"))  // yes, intel is in the renderer string
-      mIsIntel = true;
-    if (strcasestr(mRenderer.get(), "llvmpipe")) mIsLlvmpipe = true;
-    if (strcasestr(mRenderer.get(), "software rasterizer")) mIsOldSwrast = true;
-  } else if (strstr(mVendor.get(), "NVIDIA Corporation")) {
-    mIsNVIDIA = true;
-    // with the NVIDIA driver, the version string contains "NVIDIA major.minor"
-    // note that here the vendor and version strings behave differently, that's
-    // why we don't put this above alongside Mesa_in_version_string.
-    const char *NVIDIA_in_version_string = strstr(mVersion.get(), "NVIDIA");
-    if (NVIDIA_in_version_string)
-      whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA");
-  } else if (strstr(mVendor.get(), "ATI Technologies Inc")) {
-    mIsFGLRX = true;
-    // with the FGLRX driver, the version string only gives a OpenGL version :/
-    // so let's return that. that can at least give a rough idea of how old the
-    // driver is.
-    whereToReadVersionNumbers = mVersion.get();
-  }
-
-  // read major.minor version numbers of the driver (not to be confused with the
-  // OpenGL version)
-  if (whereToReadVersionNumbers) {
-    // copy into writable buffer, for tokenization
-    strncpy(buf, whereToReadVersionNumbers, buf_size);
-    bufptr = buf;
-
-    // now try to read major.minor version numbers. In case of failure,
-    // gracefully exit: these numbers have been initialized as 0 anyways
-    char *token = NS_strtok(".", &bufptr);
-    if (token) {
-      mMajorVersion = strtol(token, 0, 10);
-      token = NS_strtok(".", &bufptr);
-      if (token) {
-        mMinorVersion = strtol(token, 0, 10);
-        token = NS_strtok(".", &bufptr);
-        if (token) mRevisionVersion = strtol(token, 0, 10);
+  // Scan the GL_VERSION string for the GL and driver versions.
+  nsCWhitespaceTokenizer tokenizer(glVersion);
+  while (tokenizer.hasMoreTokens()) {
+    nsCString token(tokenizer.nextToken());
+    unsigned int major = 0, minor = 0, revision = 0, patch = 0;
+    if (sscanf(token.get(), "%u.%u.%u.%u", &major, &minor, &revision, &patch) >=
+        2) {
+      // A survey of GL_VENDOR strings indicates that the first version is
+      // always the GL version, the second is usually the driver version.
+      if (mGLMajorVersion == 0) {
+        mGLMajorVersion = major;
+        mGLMinorVersion = minor;
+      } else if (mDriverVersion.IsEmpty()) {  // Not already spoofed.
+        mDriverVersion =
+            nsPrintfCString("%u.%u.%u.%u", major, minor, revision, patch);
       }
     }
   }
-}
+
+  if (mGLMajorVersion == 0) {
+    NS_WARNING("Failed to parse GL version!");
+    return;
+  }
+
+  // Mesa always exposes itself in the GL_VERSION string, but not always the
+  // GL_VENDOR string.
+  mIsMesa = glVersion.Find("Mesa") != -1;
 
-static inline uint64_t version(uint32_t major, uint32_t minor,
-                               uint32_t revision = 0) {
-  return (uint64_t(major) << 32) + (uint64_t(minor) << 16) + uint64_t(revision);
+  // We need to use custom vendor IDs for mesa so we can treat them
+  // differently than the proprietary drivers.
+  if (mIsMesa) {
+    mIsAccelerated = !mesaAccelerated.Equals("FALSE");
+    // Process software rasterizers before the DRI driver string; we may be
+    // forcing software rasterization on a DRI-accelerated X server by using
+    // LIBGL_ALWAYS_SOFTWARE or a similar restriction.
+    if (strcasestr(glRenderer.get(), "llvmpipe")) {
+      CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorMesaLLVMPipe),
+                      mVendorId);
+      mIsAccelerated = false;
+    } else if (strcasestr(glRenderer.get(), "softpipe")) {
+      CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorMesaSoftPipe),
+                      mVendorId);
+      mIsAccelerated = false;
+    } else if (strcasestr(glRenderer.get(), "software rasterizer") ||
+               !mIsAccelerated) {
+      // Fallback to reporting swrast if GLX_MESA_query_renderer tells us
+      // we're using an unaccelerated context.
+      CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorMesaSWRast),
+                      mVendorId);
+      mIsAccelerated = false;
+    } else if (!driDriver.IsEmpty()) {
+      mVendorId = nsPrintfCString("mesa/%s", driDriver.get());
+    } else {
+      // Some other mesa configuration where we couldn't get enough info.
+      NS_WARNING("Failed to detect Mesa driver being used!");
+      CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorMesaUnknown),
+                      mVendorId);
+    }
+
+    if (!mesaDevice.IsEmpty()) {
+      mDeviceId = mesaDevice;
+    } else {
+      NS_WARNING(
+          "Failed to get Mesa device ID! GLX_MESA_query_renderer unsupported?");
+    }
+  } else if (glVendor.EqualsLiteral("NVIDIA Corporation")) {
+    CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), mVendorId);
+    // TODO: Use NV-CONTROL X11 extension to query Device ID and VRAM.
+  } else if (glVendor.EqualsLiteral("ATI Technologies Inc.")) {
+    CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorATI), mVendorId);
+    // TODO: Look into ways to find the device ID on FGLRX.
+  } else {
+    NS_WARNING("Failed to detect GL vendor!");
+  }
+
+  // Fallback to GL_VENDOR and GL_RENDERER.
+  if (mVendorId.IsEmpty()) {
+    mVendorId.Assign(glVendor.get());
+  }
+  if (mDeviceId.IsEmpty()) {
+    mDeviceId.Assign(glRenderer.get());
+  }
+
+  mAdapterDescription.Assign(glRenderer);
+
+  AddCrashReportAnnotations();
 }
 
 const nsTArray<GfxDriverInfo> &GfxInfo::GetGfxDriverInfo() {
-  // Nothing here yet.
-  // if (!sDriverInfo->Length()) {
-  //
-  //}
+  if (!sDriverInfo->Length()) {
+    // Mesa 10.0 provides the GLX_MESA_query_renderer extension, which allows us
+    // to query device IDs backing a GL context for blacklisting.
+    APPEND_TO_DRIVER_BLOCKLIST(
+        OperatingSystem::Linux,
+        (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorMesaAll),
+        GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures,
+        nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
+        V(10, 0, 0, 0), "FEATURE_FAILURE_OLD_MESA", "Mesa 10.0");
+
+    // NVIDIA baseline (ported from old blocklist)
+    APPEND_TO_DRIVER_BLOCKLIST(
+        OperatingSystem::Linux,
+        (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA),
+        GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures,
+        nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
+        V(257, 21, 0, 0), "FEATURE_FAILURE_OLD_NVIDIA", "NVIDIA 257.21");
+
+    // fglrx baseline (chosen arbitrarily as 2013-07-22 release).
+    APPEND_TO_DRIVER_BLOCKLIST(
+        OperatingSystem::Linux,
+        (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorATI),
+        GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures,
+        nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
+        V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX", "fglrx 13.15.100.1");
+  }
   return *sDriverInfo;
 }
 
+bool GfxInfo::DoesVendorMatch(const nsAString &aBlocklistVendor,
+                              const nsAString &aAdapterVendor) {
+  if (mIsMesa &&
+      aBlocklistVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorMesaAll),
+                              nsCaseInsensitiveStringComparator())) {
+    return true;
+  }
+  return GfxInfoBase::DoesVendorMatch(aBlocklistVendor, aAdapterVendor);
+}
+
 nsresult GfxInfo::GetFeatureStatusImpl(
     int32_t aFeature, int32_t *aStatus, nsAString &aSuggestedDriverVersion,
     const nsTArray<GfxDriverInfo> &aDriverInfo, nsACString &aFailureId,
     OperatingSystem *aOS /* = nullptr */)
 
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
@@ -263,122 +334,39 @@ nsresult GfxInfo::GetFeatureStatusImpl(
   if (aOS) *aOS = os;
 
   if (sShutdownOccurred) {
     return NS_OK;
   }
 
   GetData();
 
+  if (mGLMajorVersion == 0) {
+    // If we failed to get a GL version, glxtest failed.
+    *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+    aFailureId = "FEATURE_FAILURE_GLXTEST_FAILED";
+    return NS_OK;
+  }
+
   if (mGLMajorVersion == 1) {
     // We're on OpenGL 1. In most cases that indicates really old hardware.
     // We better block them, rather than rely on them to fail gracefully,
     // because they don't! see bug 696636
     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
     aFailureId = "FEATURE_FAILURE_OPENGL_1";
     return NS_OK;
   }
 
-  // Don't evaluate any special cases if we're checking the downloaded
-  // blocklist.
-  if (!aDriverInfo.Length()) {
-    // Blacklist software GL implementations from using layers acceleration.
-    // On the test infrastructure, we'll force-enable layers acceleration.
-    if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS &&
-        (mIsLlvmpipe || mIsOldSwrast) &&
-        !PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL")) {
-      *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
-      aFailureId = "FEATURE_FAILURE_SOFTWARE_GL";
-      return NS_OK;
-    }
-
-    if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER) {
-      *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
-      aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_LINUX";
-      return NS_OK;
-    }
-
-    // Only check features relevant to Linux.
-    if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS ||
-        aFeature == nsIGfxInfo::FEATURE_WEBGL_OPENGL ||
-        aFeature == nsIGfxInfo::FEATURE_WEBGL2 ||
-        aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) {
-      // whitelist the linux test slaves' current configuration.
-      // this is necessary as they're still using the slightly outdated 190.42
-      // driver. this isn't a huge risk, as at least this is the exact setting
-      // in which we do continuous testing, and this only affects GeForce 9400
-      // cards on linux on this precise driver version, which is very few users.
-      // We do the same thing on Windows XP, see in widget/windows/GfxInfo.cpp
-      if (mIsNVIDIA && !strcmp(mRenderer.get(), "GeForce 9400/PCI/SSE2") &&
-          !strcmp(mVersion.get(), "3.2.0 NVIDIA 190.42")) {
-        *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
-        return NS_OK;
-      }
-
-      if (mIsMesa) {
-        if (mIsNouveau &&
-            version(mMajorVersion, mMinorVersion) < version(8, 0)) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_MESA_1";
-          aSuggestedDriverVersion.AssignLiteral("Mesa 8.0");
-        } else if (version(mMajorVersion, mMinorVersion, mRevisionVersion) <
-                   version(7, 10, 3)) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_MESA_2";
-          aSuggestedDriverVersion.AssignLiteral("Mesa 7.10.3");
-        } else if (mIsOldSwrast) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_SW_RAST";
-        } else if (mIsLlvmpipe &&
-                   version(mMajorVersion, mMinorVersion) < version(9, 1)) {
-          // bug 791905, Mesa bug 57733, fixed in Mesa 9.1 according to
-          // https://bugs.freedesktop.org/show_bug.cgi?id=57733#c3
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_MESA_3";
-        } else if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) {
-          if (mIsIntel &&
-              version(mMajorVersion, mMinorVersion) < version(8, 1)) {
-            *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-            aFailureId = "FEATURE_FAILURE_MESA_4";
-            aSuggestedDriverVersion.AssignLiteral("Mesa 8.1");
-          }
-        }
-
-      } else if (mIsNVIDIA) {
-        if (version(mMajorVersion, mMinorVersion, mRevisionVersion) <
-            version(257, 21)) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_OLD_NV";
-          aSuggestedDriverVersion.AssignLiteral("NVIDIA 257.21");
-        }
-      } else if (mIsFGLRX) {
-        // FGLRX does not report a driver version number, so we have the OpenGL
-        // version instead. by requiring OpenGL 3, we effectively require recent
-        // drivers.
-        if (version(mMajorVersion, mMinorVersion, mRevisionVersion) <
-            version(3, 0)) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-          aFailureId = "FEATURE_FAILURE_OLD_FGLRX";
-          aSuggestedDriverVersion.AssignLiteral("<Something recent>");
-        }
-        // Bug 724640: FGLRX + Linux 2.6.32 is a crashy combo
-        bool unknownOS = mOS.IsEmpty() || mOSRelease.IsEmpty();
-        bool badOS =
-            mOS.Find("Linux", true) != -1 && mOSRelease.Find("2.6.32") != -1;
-        if (unknownOS || badOS) {
-          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
-          aFailureId = "FEATURE_FAILURE_OLD_OS";
-        }
-      } else {
-        // like on windows, let's block unknown vendors. Think of virtual
-        // machines. Also, this case is hit whenever the GLXtest probe failed to
-        // get driver info or crashed.
-        *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
-      }
-    }
+  // Blacklist software GL implementations from using layers acceleration.
+  // On the test infrastructure, we'll force-enable layers acceleration.
+  if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS && !mIsAccelerated &&
+      !PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL")) {
+    *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+    aFailureId = "FEATURE_FAILURE_SOFTWARE_GL";
+    return NS_OK;
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(
       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
 }
 
 NS_IMETHODIMP
 GfxInfo::GetD2DEnabled(bool *aEnabled) { return NS_ERROR_FAILURE; }
@@ -405,17 +393,18 @@ GfxInfo::GetAdapterDescription(nsAString
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDescription2(nsAString &aAdapterDescription) {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM(nsAString &aAdapterRAM) {
-  aAdapterRAM.Truncate();
+  GetData();
+  CopyUTF8toUTF16(mAdapterRAM, aAdapterRAM);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM2(nsAString &aAdapterRAM) { return NS_ERROR_FAILURE; }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver(nsAString &aAdapterDriver) {
@@ -426,17 +415,17 @@ GfxInfo::GetAdapterDriver(nsAString &aAd
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver2(nsAString &aAdapterDriver) {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion(nsAString &aAdapterDriverVersion) {
   GetData();
-  CopyASCIItoUTF16(mVersion, aAdapterDriverVersion);
+  CopyASCIItoUTF16(mDriverVersion, aAdapterDriverVersion);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion2(nsAString &aAdapterDriverVersion) {
   return NS_ERROR_FAILURE;
 }
 
@@ -449,29 +438,29 @@ GfxInfo::GetAdapterDriverDate(nsAString 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverDate2(nsAString &aAdapterDriverDate) {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID(nsAString &aAdapterVendorID) {
   GetData();
-  CopyUTF8toUTF16(mVendor, aAdapterVendorID);
+  CopyUTF8toUTF16(mVendorId, aAdapterVendorID);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID2(nsAString &aAdapterVendorID) {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID(nsAString &aAdapterDeviceID) {
   GetData();
-  CopyUTF8toUTF16(mRenderer, aAdapterDeviceID);
+  CopyUTF8toUTF16(mDeviceId, aAdapterDeviceID);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID2(nsAString &aAdapterDeviceID) {
   return NS_ERROR_FAILURE;
 }
 
@@ -489,31 +478,47 @@ NS_IMETHODIMP
 GfxInfo::GetIsGPU2Active(bool *aIsGPU2Active) { return NS_ERROR_FAILURE; }
 
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
 // We don't support spoofing anything on Linux
 
 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString &aVendorID) {
-  CopyUTF16toUTF8(aVendorID, mVendor);
+  GetData();
+  CopyUTF16toUTF8(aVendorID, mVendorId);
+  mIsAccelerated = !(mVendorId.EqualsLiteral("mesa/llvmpipe") ||
+                     mVendorId.EqualsLiteral("mesa/softpipe") ||
+                     mVendorId.EqualsLiteral("mesa/swrast"));
   return NS_OK;
 }
 
 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString &aDeviceID) {
-  CopyUTF16toUTF8(aDeviceID, mRenderer);
+  GetData();
+  CopyUTF16toUTF8(aDeviceID, mDeviceId);
   return NS_OK;
 }
 
 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString &aDriverVersion) {
-  CopyUTF16toUTF8(aDriverVersion, mVersion);
+  GetData();
+  CopyUTF16toUTF8(aDriverVersion, mDriverVersion);
   return NS_OK;
 }
 
 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
   // We don't support OS versioning on Linux. There's just "Linux".
   return NS_OK;
 }
 
+NS_IMETHODIMP GfxInfo::FireTestProcess() {
+  // If the pid is zero, then we have never run the test process to query for
+  // driver information. This would normally be run on startup, but we need to
+  // manually invoke it for XPC shell tests.
+  if (glxtest_pid == 0) {
+    fire_glxtest_process();
+  }
+  return NS_OK;
+}
+
 #endif
 
 }  // end namespace widget
 }  // end namespace mozilla
--- a/widget/GfxInfoX11.h
+++ b/widget/GfxInfoX11.h
@@ -4,16 +4,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __GfxInfoX11_h__
 #define __GfxInfoX11_h__
 
 #include "GfxInfoBase.h"
+#include "nsString.h"
 
 namespace mozilla {
 namespace widget {
 
 class GfxInfo final : public GfxInfoBase {
  public:
   // We only declare the subset of nsIGfxInfo that we actually implement. The
   // rest is brought forward from GfxInfoBase.
@@ -55,27 +56,31 @@ class GfxInfo final : public GfxInfoBase
   ~GfxInfo() {}
 
   virtual nsresult GetFeatureStatusImpl(
       int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
       const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
       OperatingSystem* aOS = nullptr) override;
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
 
+  virtual bool DoesVendorMatch(const nsAString& aBlocklistVendor,
+                               const nsAString& aAdapterVendor) override;
+
  private:
-  nsCString mVendor;
-  nsCString mRenderer;
-  nsCString mVersion;
+  nsCString mVendorId;
+  nsCString mDeviceId;
+  nsCString mDriverVersion;
   nsCString mAdapterDescription;
+  nsCString mAdapterRAM;
   nsCString mOS;
   nsCString mOSRelease;
-  bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau, mIsIntel, mIsOldSwrast,
-      mIsLlvmpipe;
   bool mHasTextureFromPixmap;
-  int mGLMajorVersion, mMajorVersion, mMinorVersion, mRevisionVersion;
+  unsigned int mGLMajorVersion, mGLMinorVersion;
+  bool mIsMesa;
+  bool mIsAccelerated;
 
   void AddCrashReportAnnotations();
 };
 
 }  // namespace widget
 }  // namespace mozilla
 
 #endif /* __GfxInfoX11_h__ */
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -528,16 +528,20 @@ NS_IMETHODIMP GfxInfo::SpoofDriverVersio
 }
 
 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
   EnsureInitialized();
   mOSVersion = aVersion;
   return NS_OK;
 }
 
+NS_IMETHODIMP GfxInfo::FireTestProcess() {
+  return NS_OK;
+}
+
 #endif
 
 nsString GfxInfo::Model() {
   EnsureInitialized();
   return mModel;
 }
 
 nsString GfxInfo::Hardware() {
--- a/widget/cocoa/GfxInfo.mm
+++ b/widget/cocoa/GfxInfo.mm
@@ -349,9 +349,14 @@ NS_IMETHODIMP GfxInfo::SpoofDriverVersio
 }
 
 /* void spoofOSVersion (in unsigned long aVersion); */
 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
   mOSXVersion = aVersion;
   return NS_OK;
 }
 
+/* void fireTestProcess (); */
+NS_IMETHODIMP GfxInfo::FireTestProcess() {
+  return NS_OK;
+}
+
 #endif
--- a/widget/nsIGfxInfoDebug.idl
+++ b/widget/nsIGfxInfoDebug.idl
@@ -11,9 +11,14 @@
 interface nsIGfxInfoDebug : nsISupports
 {
   void spoofVendorID(in AString aVendorID);
   void spoofDeviceID(in AString aDeviceID);
   
   void spoofDriverVersion(in AString aDriverVersion);
 
   void spoofOSVersion(in unsigned long aVersion);
+
+  /* Manually invoke any test processes required to query for driver
+     information. This is used by XPC shell tests which do not run these queries
+     by default. */
+  void fireTestProcess();
 };
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -1822,9 +1822,13 @@ NS_IMETHODIMP GfxInfo::SpoofDriverVersio
   return NS_OK;
 }
 
 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
   mWindowsVersion = aVersion;
   return NS_OK;
 }
 
+NS_IMETHODIMP GfxInfo::FireTestProcess() {
+  return NS_OK;
+}
+
 #endif