Bug 591057 - Identify active GPU in about:support and crash reports - r=jrmuizel
authorAli Juma <ajuma@mozilla.com>
Wed, 10 Aug 2011 18:25:22 -0400
changeset 74194 02d5f1c5d43846db72e28cb1d59a809a514d2d6e
parent 74193 aac29f0bdd1085e0bf51de92f9f188ee6e6d8c2b
child 74195 9c43ba0259fa1536a8caf18efeb1995a5555ff85
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersjrmuizel
bugs591057
milestone8.0a1
Bug 591057 - Identify active GPU in about:support and crash reports - r=jrmuizel
toolkit/content/aboutSupport.js
toolkit/locales/en-US/chrome/global/aboutSupport.properties
widget/public/nsIGfxInfo.idl
widget/src/android/GfxInfo.cpp
widget/src/android/GfxInfo.h
widget/src/cocoa/GfxInfo.h
widget/src/cocoa/GfxInfo.mm
widget/src/windows/GfxInfo.cpp
widget/src/windows/GfxInfo.h
widget/src/xpwidgets/GfxInfoX11.cpp
widget/src/xpwidgets/GfxInfoX11.h
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -242,16 +242,25 @@ function populateGraphicsSection() {
     pushInfoRow(trGraphics, "adapterVendorID", hexValueToString(gfxInfo.adapterVendorID));
     pushInfoRow(trGraphics, "adapterDeviceID", hexValueToString(gfxInfo.adapterDeviceID));
     pushInfoRow(trGraphics, "adapterRAM", gfxInfo.adapterRAM);
     pushInfoRow(trGraphics, "adapterDrivers", gfxInfo.adapterDriver);
     pushInfoRow(trGraphics, "driverVersion", gfxInfo.adapterDriverVersion);
     pushInfoRow(trGraphics, "driverDate", gfxInfo.adapterDriverDate);
 
 #ifdef XP_WIN
+    pushInfoRow(trGraphics, "adapterDescription2", gfxInfo.adapterDescription2);
+    pushInfoRow(trGraphics, "adapterVendorID2", hexValueToString(gfxInfo.adapterVendorID2));
+    pushInfoRow(trGraphics, "adapterDeviceID2", hexValueToString(gfxInfo.adapterDeviceID2));
+    pushInfoRow(trGraphics, "adapterRAM2", gfxInfo.adapterRAM2);
+    pushInfoRow(trGraphics, "adapterDrivers2", gfxInfo.adapterDriver2);
+    pushInfoRow(trGraphics, "driverVersion2", gfxInfo.adapterDriverVersion2);
+    pushInfoRow(trGraphics, "driverDate2", gfxInfo.adapterDriverDate2);
+    pushInfoRow(trGraphics, "isGPU2Active", gfxInfo.isGPU2Active);
+
     var version = Cc["@mozilla.org/system-info;1"]
                   .getService(Ci.nsIPropertyBag2)
                   .getProperty("version");
     var isWindowsVistaOrHigher = (parseFloat(version) >= 6.0);
     if (isWindowsVistaOrHigher) {
       var d2dEnabled = "false";
       try {
         d2dEnabled = gfxInfo.D2DEnabled;
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.properties
@@ -26,9 +26,17 @@ clearTypeParameters = ClearType Paramete
 clearTypeParametersNotFound = ClearType parameters not found
 adapterDescription = Adapter Description
 adapterVendorID = Vendor ID
 adapterDeviceID = Device ID
 adapterDrivers = Adapter Drivers
 adapterRAM = Adapter RAM
 driverVersion = Driver Version
 driverDate = Driver Date
+adapterDescription2 = Adapter Description (GPU #2) 
+adapterVendorID2 = Vendor ID (GPU #2) 
+adapterDeviceID2 = Device ID (GPU #2)
+adapterDrivers2 = Adapter Drivers (GPU #2)
+adapterRAM2 = Adapter RAM (GPU #2)
+driverVersion2 = Driver Version (GPU #2)
+driverDate2 = Driver Date (GPU #2)
+isGPU2Active = GPU #2 Active
 webglRenderer = WebGL Renderer
--- a/widget/public/nsIGfxInfo.idl
+++ b/widget/public/nsIGfxInfo.idl
@@ -46,37 +46,48 @@ interface nsIGfxInfo : nsISupports
   /*
    * These are win32-specific
    */
   readonly attribute boolean D2DEnabled;
   readonly attribute boolean DWriteEnabled;
   readonly attribute boolean AzureEnabled;
   readonly attribute DOMString DWriteVersion;
   readonly attribute DOMString cleartypeParameters;
-  
+
+  // XXX: Switch to a list of devices, rather than explicitly numbering them. 
+
   /**
    * The name of the display adapter.
    */
   readonly attribute DOMString adapterDescription;
+  readonly attribute DOMString adapterDescription2;
 
   readonly attribute DOMString adapterDriver;
+  readonly attribute DOMString adapterDriver2;
   
   /* These types are inspired by DXGI_ADAPTER_DESC */
   readonly attribute unsigned long adapterVendorID;
+  readonly attribute unsigned long adapterVendorID2;
   
   readonly attribute unsigned long adapterDeviceID;
-  
+  readonly attribute unsigned long adapterDeviceID2;
+
   /**
    * The amount of RAM in MB in the display adapter.
    */
   readonly attribute DOMString adapterRAM;
+  readonly attribute DOMString adapterRAM2;
   
   readonly attribute DOMString adapterDriverVersion;
+  readonly attribute DOMString adapterDriverVersion2;
   
   readonly attribute DOMString adapterDriverDate;
+  readonly attribute DOMString adapterDriverDate2;
+
+  readonly attribute boolean isGPU2Active;
 
   void getFailures(
                [optional] out unsigned long failureCount,
                [retval, array, size_is(failureCount)] out string failures);
 
   [noscript, notxpcom] void logFailure(in ACString failure);
   /*
    * A set of constants for features that we can ask this GfxInfo object
--- a/widget/src/android/GfxInfo.cpp
+++ b/widget/src/android/GfxInfo.cpp
@@ -106,64 +106,120 @@ GfxInfo::GetAdapterDescription(nsAString
       aAdapterDescription.Append(NS_LITERAL_STRING(" "));
       if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str))
         aAdapterDescription.Append(str);
   }
 
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDescription2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterRAM; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
 {
   aAdapterRAM.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterRAM2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriver; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
 {
   aAdapterDriver.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriver2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverVersion; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
 {
   aAdapterDriverVersion.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverVersion2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverDate; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
 {
   aAdapterDriverDate.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverDate2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterVendorID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID(PRUint32 *aAdapterVendorID)
 {
   *aAdapterVendorID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterVendorID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID2(PRUint32 *aAdapterVendorID)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterDeviceID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID(PRUint32 *aAdapterDeviceID)
 {
   *aAdapterDeviceID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterDeviceID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID)
+{
+  return NS_ERROR_FAILURE;
+}
+
+/* readonly attribute boolean isGPU2Active; */
+NS_IMETHODIMP
+GfxInfo::GetIsGPU2Active(PRBool* aIsGPU2Active)
+{
+  return NS_ERROR_FAILURE;
+}
+
 void
 GfxInfo::AddCrashReportAnnotations()
 {
 #if 0
 #if defined(MOZ_CRASHREPORTER)
   nsCAutoString deviceIDString, vendorIDString;
   PRUint32 deviceID, vendorID;
 
--- a/widget/src/android/GfxInfo.h
+++ b/widget/src/android/GfxInfo.h
@@ -59,16 +59,24 @@ public:
   NS_SCRIPTABLE NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID(PRUint32 *aAdapterVendorID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID(PRUint32 *aAdapterDeviceID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID2(PRUint32 *aAdapterVendorID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetIsGPU2Active(PRBool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init();
 
 protected:
 
--- a/widget/src/cocoa/GfxInfo.h
+++ b/widget/src/cocoa/GfxInfo.h
@@ -59,16 +59,24 @@ public:
   NS_SCRIPTABLE NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID(PRUint32 *aAdapterVendorID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID(PRUint32 *aAdapterDeviceID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID2(PRUint32 *aAdapterVendorID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetIsGPU2Active(PRBool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init();
 
 protected:
 
--- a/widget/src/cocoa/GfxInfo.mm
+++ b/widget/src/cocoa/GfxInfo.mm
@@ -129,64 +129,120 @@ GfxInfo::GetCleartypeParameters(nsAStrin
 /* readonly attribute DOMString adapterDescription; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
 {
   aAdapterDescription = mRendererIDsString;
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDescription2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterRAM; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
 {
   aAdapterRAM = mAdapterRAMString;
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterRAM2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriver; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
 {
   aAdapterDriver.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriver2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverVersion; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
 {
   aAdapterDriverVersion.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverVersion2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverDate; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
 {
   aAdapterDriverDate.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverDate2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterVendorID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID(PRUint32 *aAdapterVendorID)
 {
   *aAdapterVendorID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterVendorID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID2(PRUint32 *aAdapterVendorID)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterDeviceID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID(PRUint32 *aAdapterDeviceID)
 {
   *aAdapterDeviceID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterDeviceID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID)
+{
+  return NS_ERROR_FAILURE;
+}
+
+/* readonly attribute boolean isGPU2Active; */
+NS_IMETHODIMP
+GfxInfo::GetIsGPU2Active(PRBool* aIsGPU2Active)
+{
+  return NS_ERROR_FAILURE;
+}
+
 void
 GfxInfo::AddCrashReportAnnotations()
 {
 #if defined(MOZ_CRASHREPORTER)
   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterRendererIDs"),
                                      NS_LossyConvertUTF16toASCII(mRendererIDsString));
 
   /* Add an App Note for now so that we get the data immediately. These
--- a/widget/src/windows/GfxInfo.cpp
+++ b/widget/src/windows/GfxInfo.cpp
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <windows.h>
 #include <setupapi.h>
+#include "d3d9.h"
 #include "gfxWindowsPlatform.h"
 #include "GfxInfo.h"
 #include "GfxInfoWebGL.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/FunctionTimer.h"
 #include "prenv.h"
 #include "prprf.h"
 #include "GfxDriverInfo.h"
@@ -72,17 +73,21 @@ static const PRUint32 vendorAMD = 0x1022
 static const PRUint32 vendorATI = 0x1002;
 
 #define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d)
 
 
 GfxInfo::GfxInfo()
   : mAdapterVendorID(0),
     mAdapterDeviceID(0),
-    mWindowsVersion(0)
+    mAdapterVendorID2(0),
+    mAdapterDeviceID2(0),
+    mWindowsVersion(0),
+    mHasDualGPU(PR_FALSE),
+    mIsGPU2Active(PR_FALSE)
 {
 }
 
 /* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization
  * has occurred because they depend on it for information. (See bug 591561) */
 nsresult
 GfxInfo::GetD2DEnabled(PRBool *aEnabled)
 {
@@ -194,17 +199,52 @@ GfxInfo::GetCleartypeParameters(nsAStrin
 
   if (foundData) {
     aCleartypeParams.Assign(outStr);
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
-/* XXX: GfxInfo doesn't handle multiple GPUs. We should try to do that. Bug #591057 */
+typedef IDirect3D9* (WINAPI*Direct3DCreate9Func) (
+  UINT SDKVersion
+);
+
+// XXX: Blacklisting logic doesn't use the result of this for now. Bug #628129.
+void
+GfxInfo::IdentifyActiveDevice()
+{
+  
+  HMODULE d3d9 = LoadLibraryW(L"d3d9.dll");
+  if (!d3d9) {
+    NS_WARNING("Couldn't load d3d9.dll");
+    return;
+  }
+  
+  Direct3DCreate9Func d3d9Create = (Direct3DCreate9Func) 
+    GetProcAddress(d3d9, "Direct3DCreate9");
+  if (!d3d9Create) {
+    NS_WARNING("Couldn't get Direct3DCreate9 function");
+    return;
+  }
+
+  nsRefPtr<IDirect3D9> d3d9Object = dont_AddRef(d3d9Create(D3D_SDK_VERSION));;
+  if (!d3d9Object) {
+    NS_WARNING("Couldn't create d3d9object");
+    return;
+  }
+
+  D3DADAPTER_IDENTIFIER9 ident;
+  HRESULT result = d3d9Object->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident);
+  
+  if ((result == D3D_OK) && 
+      (mAdapterVendorID2 == ident.VendorId) && (mAdapterDeviceID2 = ident.DeviceId)) {
+    mIsGPU2Active = PR_TRUE;
+  } 
+}
 
 static nsresult GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, nsAString& destString, int type)
 {
   HKEY key;
   DWORD dwcbData;
   DWORD dValue;
   DWORD resultType;
   LONG result;
@@ -404,47 +444,111 @@ GfxInfo::Init()
               dwcbData = sizeof(value);
               result = RegQueryValueExW(key, L"DriverVersion", NULL, NULL, (LPBYTE)value, &dwcbData);
               if (result == ERROR_SUCCESS)
                 mDriverVersion = value;
               dwcbData = sizeof(value);
               result = RegQueryValueExW(key, L"DriverDate", NULL, NULL, (LPBYTE)value, &dwcbData);
               if (result == ERROR_SUCCESS)
                 mDriverDate = value;
-              RegCloseKey(key);
+              RegCloseKey(key); 
+
+              // Check for second adapter:
+              //
+              // A second adapter will have the same driver key as the first adapter except for 
+              // the last character, where '1' will be swapped for '0' or vice-versa.
+              // We know driverKey.Length() > 0 since driverKeyPre is a prefix of driverKey.
+              if (driverKey[driverKey.Length()-1] == '0') {
+                driverKey.SetCharAt('1', driverKey.Length()-1);
+              } else {
+                driverKey.SetCharAt('0', driverKey.Length()-1);
+              }
+              result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.BeginReading(), 0, KEY_QUERY_VALUE, &key);
+              if (result == ERROR_SUCCESS) {
+                mHasDualGPU = PR_TRUE;
+                mDeviceKey2 = driverKey;
+                dwcbData = sizeof(value);
+                result = RegQueryValueExW(key, L"DriverVersion", NULL, NULL, (LPBYTE)value, &dwcbData);
+                if (result == ERROR_SUCCESS)
+                  mDriverVersion2 = value;
+                dwcbData = sizeof(value);
+                result = RegQueryValueExW(key, L"DriverDate", NULL, NULL, (LPBYTE)value, &dwcbData);
+                if (result == ERROR_SUCCESS)
+                  mDriverDate2 = value;
+                dwcbData = sizeof(value);
+                result = RegQueryValueExW(key, L"Device Description", NULL, NULL, (LPBYTE)value, &dwcbData);
+                if (result == ERROR_SUCCESS)
+                  mDeviceString2 = value;
+                dwcbData = sizeof(value);
+                result = RegQueryValueExW(key, L"MatchingDeviceId", NULL, NULL, (LPBYTE)value, &dwcbData);
+                if (result == ERROR_SUCCESS)
+                  mDeviceID2 = value;
+                RegCloseKey(key);
+              }  
               break;
             }
           }
         }
 
         setupDestroyDeviceInfoList(devinfo);
       }
     }
 
     FreeLibrary(setupapi);
   }
 
+  nsAutoString vendor(mDeviceID);
+  ToUpperCase(vendor);
+  PRInt32 start = vendor.Find(NS_LITERAL_CSTRING("VEN_"));
+  if (start != -1) {
+    vendor.Cut(0, start + strlen("VEN_"));
+    vendor.Truncate(4);
+  }
+  nsresult err;
+  mAdapterVendorID = vendor.ToInteger(&err, 16);
+  
+  vendor = mDeviceID2;
+  ToUpperCase(vendor);
+  start = vendor.Find(NS_LITERAL_CSTRING("VEN_"));
+  if (start != -1) {
+    vendor.Cut(0, start + strlen("VEN_"));
+    vendor.Truncate(4);
+  }
+  mAdapterVendorID2 = vendor.ToInteger(&err, 16);
+
+  nsAutoString device(mDeviceID);
+  ToUpperCase(device);
+  start = device.Find(NS_LITERAL_CSTRING("&DEV_"));
+  if (start != -1) {
+    device.Cut(0, start + strlen("&DEV_"));
+    device.Truncate(4);
+  }
+  mAdapterDeviceID = device.ToInteger(&err, 16);
+  
+  device = mDeviceID2;
+  ToUpperCase(device);
+  start = device.Find(NS_LITERAL_CSTRING("&DEV_"));
+  if (start != -1) {
+    device.Cut(0, start + strlen("&DEV_"));
+    device.Truncate(4);
+  }
+  mAdapterDeviceID2 = device.ToInteger(&err, 16);
+  
+  if (mHasDualGPU) {
+    IdentifyActiveDevice();
+  }
+
   const char *spoofedDriverVersionString = PR_GetEnv("MOZ_GFX_SPOOF_DRIVER_VERSION");
   if (spoofedDriverVersionString) {
     mDriverVersion.AssignASCII(spoofedDriverVersionString);
   }
 
   const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_VENDOR_ID");
   if (spoofedVendor) {
      PR_sscanf(spoofedVendor, "%x", &mAdapterVendorID);
-  } else {
-    nsAutoString vendor(mDeviceID);
-    ToUpperCase(vendor);
-    PRInt32 start = vendor.Find(NS_LITERAL_CSTRING("VEN_"));
-    if (start != -1) {
-      vendor.Cut(0, start + strlen("VEN_"));
-      vendor.Truncate(4);
-    }
-    nsresult err;
-    mAdapterVendorID = vendor.ToInteger(&err, 16);
   }
 
   mHasDriverVersionMismatch = PR_FALSE;
   if (mAdapterVendorID == vendorIntel) {
     // we've had big crashers (bugs 590373 and 595364) apparently correlated
     // with bad Intel driver installations where the DriverVersion reported
     // by the registry was not the version of the DLL.
     PRBool is64bitApp = sizeof(void*) == 8;
@@ -463,26 +567,16 @@ GfxInfo::Init()
     // so this test implicitly handles the case where GetDLLVersion failed
     if (dllNumericVersion != driverNumericVersion)
       mHasDriverVersionMismatch = PR_TRUE;
   }
 
   const char *spoofedDevice = PR_GetEnv("MOZ_GFX_SPOOF_DEVICE_ID");
   if (spoofedDevice) {
     PR_sscanf(spoofedDevice, "%x", &mAdapterDeviceID);
-  } else {
-    nsAutoString device(mDeviceID);
-    ToUpperCase(device);
-    PRInt32 start = device.Find(NS_LITERAL_CSTRING("&DEV_"));
-    if (start != -1) {
-      device.Cut(0, start + strlen("&DEV_"));
-      device.Truncate(4);
-    }
-    nsresult err;
-    mAdapterDeviceID = device.ToInteger(&err, 16);
   }
 
   const char *spoofedWindowsVersion = PR_GetEnv("MOZ_GFX_SPOOF_WINDOWS_VERSION");
   if (spoofedWindowsVersion) {
     PR_sscanf(spoofedWindowsVersion, "%x", &mWindowsVersion);
   } else {
     mWindowsVersion = gfxWindowsPlatform::WindowsOSVersion();
   }
@@ -495,66 +589,132 @@ GfxInfo::Init()
 /* readonly attribute DOMString adapterDescription; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
 {
   aAdapterDescription = mDeviceString;
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDescription2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
+{
+  aAdapterDescription = mDeviceString2;
+  return NS_OK;
+}
+
 /* readonly attribute DOMString adapterRAM; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
 {
   if (NS_FAILED(GetKeyValue(mDeviceKey.BeginReading(), L"HardwareInformation.MemorySize", aAdapterRAM, REG_DWORD)))
     aAdapterRAM = L"Unknown";
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterRAM2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
+{
+  if (NS_FAILED(GetKeyValue(mDeviceKey2.BeginReading(), L"HardwareInformation.MemorySize", aAdapterRAM, REG_DWORD)))
+    aAdapterRAM = L"Unknown";
+  return NS_OK;
+}
+
 /* readonly attribute DOMString adapterDriver; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
 {
   if (NS_FAILED(GetKeyValue(mDeviceKey.BeginReading(), L"InstalledDisplayDrivers", aAdapterDriver, REG_MULTI_SZ)))
     aAdapterDriver = L"Unknown";
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriver2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
+{
+  if (NS_FAILED(GetKeyValue(mDeviceKey2.BeginReading(), L"InstalledDisplayDrivers", aAdapterDriver, REG_MULTI_SZ)))
+    aAdapterDriver = L"Unknown";
+  return NS_OK;
+}
+
 /* readonly attribute DOMString adapterDriverVersion; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
 {
   aAdapterDriverVersion = mDriverVersion;
   return NS_OK;
 }
 
 /* readonly attribute DOMString adapterDriverDate; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
 {
   aAdapterDriverDate = mDriverDate;
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverVersion2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
+{
+  aAdapterDriverVersion = mDriverVersion2;
+  return NS_OK;
+}
+
+/* readonly attribute DOMString adapterDriverDate2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
+{
+  aAdapterDriverDate = mDriverDate2;
+  return NS_OK;
+}
+
 /* readonly attribute unsigned long adapterVendorID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID(PRUint32 *aAdapterVendorID)
 {
   *aAdapterVendorID = mAdapterVendorID;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterVendorID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID2(PRUint32 *aAdapterVendorID)
+{
+  *aAdapterVendorID = mAdapterVendorID2;
+  return NS_OK;
+}
+
 /* readonly attribute unsigned long adapterDeviceID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID(PRUint32 *aAdapterDeviceID)
 {
   *aAdapterDeviceID = mAdapterDeviceID;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterDeviceID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID)
+{
+  *aAdapterDeviceID = mAdapterDeviceID2;
+  return NS_OK;
+}
+
+/* readonly attribute boolean isGPU2Active; */
+NS_IMETHODIMP
+GfxInfo::GetIsGPU2Active(PRBool* aIsGPU2Active)
+{
+  *aIsGPU2Active = mIsGPU2Active;
+  return NS_OK;
+}
+
 #if defined(MOZ_CRASHREPORTER)
 /* Cisco's VPN software can cause corruption of the floating point state.
  * Make a note of this in our crash reports so that some weird crashes
  * make more sense */
 static void
 CheckForCiscoVPN() {
   LONG result;
   HKEY key;
@@ -602,16 +762,29 @@ GfxInfo::AddCrashReportAnnotations()
       /* if we didn't find a valid vendorID lets append the mDeviceID string to try to find out why */
       note.Append(", ");
       note.AppendWithConversion(mDeviceID);
       note.Append(", ");
       note.AppendWithConversion(mDeviceKeyDebug);
   }
   note.Append("\n");
 
+  if (mHasDualGPU) {
+    PRUint32 deviceID2, vendorID2;
+    nsAutoString adapterDriverVersionString2;
+
+    note.Append("Has dual GPUs. GPU #2: ");
+    GetAdapterDeviceID2(&deviceID2);
+    GetAdapterVendorID2(&vendorID2);
+    GetAdapterDriverVersion2(adapterDriverVersionString2);
+    note.AppendPrintf("AdapterVendorID2: %04x, ", vendorID2);
+    note.AppendPrintf("AdapterDeviceID2: %04x, ", deviceID2);
+    note.AppendPrintf("AdapterDriverVersion2: ");
+    note.Append(NS_LossyConvertUTF16toASCII(adapterDriverVersionString2));
+  }
   CrashReporter::AppendAppNotesToCrashReport(note);
 
 #endif
 }
 
 #define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d)
 
 static const PRUint32 deviceFamilyIntelGMA500[] = {
--- a/widget/src/windows/GfxInfo.h
+++ b/widget/src/windows/GfxInfo.h
@@ -63,16 +63,24 @@ public:
   NS_SCRIPTABLE NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID(PRUint32 *aAdapterVendorID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID(PRUint32 *aAdapterDeviceID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID2(PRUint32 *aAdapterVendorID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetIsGPU2Active(PRBool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIGFXINFODEBUG
 #endif
@@ -81,24 +89,34 @@ public:
 
 protected:
 
   virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, GfxDriverInfo* aDriverInfo = nsnull);
 
 private:
 
   void AddCrashReportAnnotations();
+  void IdentifyActiveDevice();
   nsString mDeviceString;
   nsString mDeviceID;
   nsString mDriverVersion;
   nsString mDriverDate;
   nsString mDeviceKey;
   nsString mDeviceKeyDebug;
   PRUint32 mAdapterVendorID;
   PRUint32 mAdapterDeviceID;
+  nsString mDeviceString2;
+  nsString mDriverVersion2;
+  nsString mDeviceID2;
+  nsString mDriverDate2;
+  nsString mDeviceKey2;
+  PRUint32 mAdapterVendorID2;
+  PRUint32 mAdapterDeviceID2;
   PRUint32 mWindowsVersion;
+  PRBool mHasDualGPU;
+  PRBool mIsGPU2Active;
   PRBool mHasDriverVersionMismatch;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif /* __mozilla_widget_GfxInfo_h__ */
--- a/widget/src/xpwidgets/GfxInfoX11.cpp
+++ b/widget/src/xpwidgets/GfxInfoX11.cpp
@@ -338,60 +338,116 @@ GfxInfo::GetCleartypeParameters(nsAStrin
 NS_IMETHODIMP
 GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
 {
   GetData();
   AppendASCIItoUTF16(mAdapterDescription, aAdapterDescription);
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDescription2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterRAM; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
 {
   aAdapterRAM.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterRAM2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriver; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
 {
   aAdapterDriver.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriver2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverVersion; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
 {
   GetData();
   CopyASCIItoUTF16(mVersion, aAdapterDriverVersion);
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverVersion2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute DOMString adapterDriverDate; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
 {
   aAdapterDriverDate.AssignLiteral("");
   return NS_OK;
 }
 
+/* readonly attribute DOMString adapterDriverDate2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterVendorID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterVendorID(PRUint32 *aAdapterVendorID)
 {
   *aAdapterVendorID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterVendorID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID2(PRUint32 *aAdapterVendorID)
+{
+  return NS_ERROR_FAILURE;
+}
+
 /* readonly attribute unsigned long adapterDeviceID; */
 NS_IMETHODIMP
 GfxInfo::GetAdapterDeviceID(PRUint32 *aAdapterDeviceID)
 {
   *aAdapterDeviceID = 0;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long adapterDeviceID2; */
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID)
+{
+  return NS_ERROR_FAILURE;
+}
+
+/* readonly attribute boolean isGPU2Active; */
+NS_IMETHODIMP
+GfxInfo::GetIsGPU2Active(PRBool* aIsGPU2Active)
+{
+  return NS_ERROR_FAILURE;
+}
+
 
 } // end namespace widget
 } // end namespace mozilla
--- a/widget/src/xpwidgets/GfxInfoX11.h
+++ b/widget/src/xpwidgets/GfxInfoX11.h
@@ -58,16 +58,24 @@ public:
   NS_SCRIPTABLE NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID(PRUint32 *aAdapterVendorID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID(PRUint32 *aAdapterDeviceID);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion);
   NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterVendorID2(PRUint32 *aAdapterVendorID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDeviceID2(PRUint32 *aAdapterDeviceID);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion);
+  NS_SCRIPTABLE NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
+  NS_SCRIPTABLE NS_IMETHOD GetIsGPU2Active(PRBool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init();
 
 protected: