michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "GfxInfo.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsCocoaFeatures.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include michael@0: michael@0: #import michael@0: #import michael@0: #import michael@0: michael@0: #if defined(MOZ_CRASHREPORTER) michael@0: #include "nsExceptionHandler.h" michael@0: #include "nsICrashReporter.h" michael@0: #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" michael@0: #endif michael@0: michael@0: #define MAC_OS_X_VERSION_MASK 0x0000FFFF michael@0: #define MAC_OS_X_VERSION_MAJOR_MASK 0x0000FFF0 michael@0: #define MAC_OS_X_VERSION_10_6_HEX 0x00001060 michael@0: #define MAC_OS_X_VERSION_10_7_HEX 0x00001070 michael@0: #define MAC_OS_X_VERSION_10_8_HEX 0x00001080 michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::widget; michael@0: michael@0: #ifdef DEBUG michael@0: NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) michael@0: #endif michael@0: michael@0: GfxInfo::GfxInfo() michael@0: { michael@0: } michael@0: michael@0: static OperatingSystem michael@0: OSXVersionToOperatingSystem(uint32_t aOSXVersion) michael@0: { michael@0: switch (aOSXVersion & MAC_OS_X_VERSION_MAJOR_MASK) { michael@0: case MAC_OS_X_VERSION_10_6_HEX: michael@0: return DRIVER_OS_OS_X_10_6; michael@0: case MAC_OS_X_VERSION_10_7_HEX: michael@0: return DRIVER_OS_OS_X_10_7; michael@0: case MAC_OS_X_VERSION_10_8_HEX: michael@0: return DRIVER_OS_OS_X_10_8; michael@0: } michael@0: michael@0: return DRIVER_OS_UNKNOWN; michael@0: } michael@0: // The following three functions are derived from Chromium code michael@0: static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, michael@0: CFStringRef propertyName) michael@0: { michael@0: return IORegistryEntrySearchCFProperty(dspPort, michael@0: kIOServicePlane, michael@0: propertyName, michael@0: kCFAllocatorDefault, michael@0: kIORegistryIterateRecursively | michael@0: kIORegistryIterateParents); michael@0: } michael@0: michael@0: static uint32_t IntValueOfCFData(CFDataRef d) michael@0: { michael@0: uint32_t value = 0; michael@0: michael@0: if (d) { michael@0: const uint32_t *vp = reinterpret_cast(CFDataGetBytePtr(d)); michael@0: if (vp != NULL) michael@0: value = *vp; michael@0: } michael@0: michael@0: return value; michael@0: } michael@0: michael@0: void michael@0: GfxInfo::GetDeviceInfo() michael@0: { michael@0: io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay); michael@0: CFTypeRef vendor_id_ref = SearchPortForProperty(dsp_port, CFSTR("vendor-id")); michael@0: if (vendor_id_ref) { michael@0: mAdapterVendorID.AppendPrintf("0x%4x", IntValueOfCFData((CFDataRef)vendor_id_ref)); michael@0: CFRelease(vendor_id_ref); michael@0: } michael@0: CFTypeRef device_id_ref = SearchPortForProperty(dsp_port, CFSTR("device-id")); michael@0: if (device_id_ref) { michael@0: mAdapterDeviceID.AppendPrintf("0x%4x", IntValueOfCFData((CFDataRef)device_id_ref)); michael@0: CFRelease(device_id_ref); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: GfxInfo::Init() michael@0: { michael@0: nsresult rv = GfxInfoBase::Init(); michael@0: michael@0: // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU michael@0: // even when we don't want to. We'll avoid doing so for now and just michael@0: // use the device ids. michael@0: michael@0: GetDeviceInfo(); michael@0: michael@0: AddCrashReportAnnotations(); michael@0: michael@0: mOSXVersion = nsCocoaFeatures::OSXVersion(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetD2DEnabled(bool *aEnabled) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetDWriteEnabled(bool *aEnabled) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString DWriteVersion; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString cleartypeParameters; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDescription; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription) michael@0: { michael@0: aAdapterDescription.AssignLiteral(""); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDescription2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterRAM; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM) michael@0: { michael@0: aAdapterRAM = mAdapterRAMString; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterRAM2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriver; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver) michael@0: { michael@0: aAdapterDriver.AssignLiteral(""); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriver2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriverVersion; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) michael@0: { michael@0: aAdapterDriverVersion.AssignLiteral(""); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriverVersion2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriverDate; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate) michael@0: { michael@0: aAdapterDriverDate.AssignLiteral(""); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDriverDate2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterVendorID; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID) michael@0: { michael@0: aAdapterVendorID = mAdapterVendorID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterVendorID2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDeviceID; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID) michael@0: { michael@0: aAdapterDeviceID = mAdapterDeviceID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute DOMString adapterDeviceID2; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute boolean isGPU2Active; */ michael@0: NS_IMETHODIMP michael@0: GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: void michael@0: GfxInfo::AddCrashReportAnnotations() michael@0: { michael@0: #if defined(MOZ_CRASHREPORTER) michael@0: nsString deviceID, vendorID; michael@0: nsAutoCString narrowDeviceID, narrowVendorID; michael@0: michael@0: GetAdapterDeviceID(deviceID); michael@0: CopyUTF16toUTF8(deviceID, narrowDeviceID); michael@0: GetAdapterVendorID(vendorID); michael@0: CopyUTF16toUTF8(vendorID, narrowVendorID); michael@0: michael@0: CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), michael@0: narrowVendorID); michael@0: CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), michael@0: narrowDeviceID); michael@0: /* Add an App Note for now so that we get the data immediately. These michael@0: * can go away after we store the above in the socorro db */ michael@0: nsAutoCString note; michael@0: /* AppendPrintf only supports 32 character strings, mrghh. */ michael@0: note.Append("AdapterVendorID: "); michael@0: note.Append(narrowVendorID); michael@0: note.Append(", AdapterDeviceID: "); michael@0: note.Append(narrowDeviceID); michael@0: CrashReporter::AppendAppNotesToCrashReport(note); michael@0: #endif michael@0: } michael@0: michael@0: // We don't support checking driver versions on Mac. michael@0: #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn) \ michael@0: APPEND_TO_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, \ michael@0: DRIVER_COMPARISON_IGNORED, V(0,0,0,0), "") michael@0: michael@0: michael@0: const nsTArray& michael@0: GfxInfo::GetGfxDriverInfo() michael@0: { michael@0: if (!mDriverInfo->Length()) { michael@0: IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, michael@0: (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, michael@0: nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION); michael@0: IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, michael@0: (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(RadeonX1000), michael@0: nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE); michael@0: IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, michael@0: (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(Geforce7300GT), michael@0: nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE); michael@0: } michael@0: return *mDriverInfo; michael@0: } michael@0: michael@0: nsresult michael@0: GfxInfo::GetFeatureStatusImpl(int32_t aFeature, michael@0: int32_t* aStatus, michael@0: nsAString& aSuggestedDriverVersion, michael@0: const nsTArray& aDriverInfo, michael@0: OperatingSystem* aOS /* = nullptr */) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aStatus); michael@0: aSuggestedDriverVersion.SetIsVoid(true); michael@0: *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; michael@0: OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion); michael@0: if (aOS) michael@0: *aOS = os; michael@0: michael@0: // Don't evaluate special cases when we're evaluating the downloaded blocklist. michael@0: if (!aDriverInfo.Length()) { michael@0: if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) { michael@0: // Blacklist all ATI cards on OSX, except for michael@0: // 0x6760 and 0x9488 michael@0: if (mAdapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorATI), nsCaseInsensitiveStringComparator()) && michael@0: (mAdapterDeviceID.LowerCaseEqualsLiteral("0x6760") || michael@0: mAdapterDeviceID.LowerCaseEqualsLiteral("0x9488"))) { michael@0: *aStatus = nsIGfxInfo::FEATURE_NO_INFO; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: michael@0: // Implement nsIGfxInfoDebug michael@0: michael@0: /* void spoofVendorID (in DOMString aVendorID); */ michael@0: NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID) michael@0: { michael@0: mAdapterVendorID = aVendorID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void spoofDeviceID (in unsigned long aDeviceID); */ michael@0: NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID) michael@0: { michael@0: mAdapterDeviceID = aDeviceID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void spoofDriverVersion (in DOMString aDriverVersion); */ michael@0: NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion) michael@0: { michael@0: mDriverVersion = aDriverVersion; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void spoofOSVersion (in unsigned long aVersion); */ michael@0: NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) michael@0: { michael@0: mOSXVersion = aVersion; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #endif