1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2/* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6#include <OpenGL/OpenGL.h> 7#include <OpenGL/CGLRenderers.h> 8 9#include "mozilla/ArrayUtils.h" 10 11#include "GfxInfo.h" 12#include "nsUnicharUtils.h" 13#include "nsExceptionHandler.h" 14#include "nsCocoaFeatures.h" 15#include "nsICrashReporter.h" 16#include "mozilla/Preferences.h" 17#include <algorithm> 18 19#import <Foundation/Foundation.h> 20#import <IOKit/IOKitLib.h> 21#import <Cocoa/Cocoa.h> 22 23#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" 24 25using namespace mozilla; 26using namespace mozilla::widget; 27 28#ifdef DEBUG 29NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) 30#endif 31 32GfxInfo::GfxInfo() : mOSXVersion{0} 33{ 34} 35 36static OperatingSystem 37OSXVersionToOperatingSystem(uint32_t aOSXVersion) 38{ 39 if (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion) == 10) { 40 switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) { 41 case 6: 42 return OperatingSystem::OSX10_6; 43 case 7: 44 return OperatingSystem::OSX10_7; 45 case 8: 46 return OperatingSystem::OSX10_8; 47 case 9: 48 return OperatingSystem::OSX10_9; 49 case 10: 50 return OperatingSystem::OSX10_10; 51 case 11: 52 return OperatingSystem::OSX10_11; 53 case 12: 54 return OperatingSystem::OSX10_12; 55 case 13: 56 return OperatingSystem::OSX10_13; 57 } 58 } 59 60 return OperatingSystem::Unknown; 61} 62// The following three functions are derived from Chromium code 63static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, 64 CFStringRef propertyName) 65{ 66 return IORegistryEntrySearchCFProperty(dspPort, 67 kIOServicePlane, 68 propertyName, 69 kCFAllocatorDefault, 70 kIORegistryIterateRecursively | 71 kIORegistryIterateParents); 72} 73 74static uint32_t IntValueOfCFData(CFDataRef d) 75{ 76 uint32_t value = 0; 77 78 if (d) { 79 const uint32_t *vp = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(d)); 80 if (vp != NULL) 81 value = *vp; 82 } 83 84 return value; 85} 86 87void 88GfxInfo::GetDeviceInfo() 89{ 90 io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay); 91 CFTypeRef vendor_id_ref = SearchPortForProperty(dsp_port, CFSTR("vendor-id")); 92 if (vendor_id_ref) { 93 mAdapterVendorID.AppendPrintf("0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref)); 94 CFRelease(vendor_id_ref); 95 } 96 CFTypeRef device_id_ref = SearchPortForProperty(dsp_port, CFSTR("device-id")); 97 if (device_id_ref) { 98 mAdapterDeviceID.AppendPrintf("0x%04x", IntValueOfCFData((CFDataRef)device_id_ref)); 99 CFRelease(device_id_ref); 100 } 101} 102 103nsresult 104GfxInfo::Init() 105{ 106 nsresult rv = GfxInfoBase::Init(); 107 108 // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU 109 // even when we don't want to. We'll avoid doing so for now and just 110 // use the device ids. 111 112 GetDeviceInfo(); 113 114 AddCrashReportAnnotations(); 115 116 mOSXVersion = nsCocoaFeatures::OSXVersion(); 117 118 return rv; 119} 120 121NS_IMETHODIMP 122GfxInfo::GetD2DEnabled(bool *aEnabled) 123{ 124 return NS_ERROR_FAILURE; 125} 126 127NS_IMETHODIMP 128GfxInfo::GetDWriteEnabled(bool *aEnabled) 129{ 130 return NS_ERROR_FAILURE; 131} 132 133/* readonly attribute DOMString DWriteVersion; */ 134NS_IMETHODIMP 135GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) 136{ 137 return NS_ERROR_FAILURE; 138} 139 140/* readonly attribute DOMString cleartypeParameters; */ 141NS_IMETHODIMP 142GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) 143{ 144 return NS_ERROR_FAILURE; 145} 146 147/* readonly attribute DOMString adapterDescription; */ 148NS_IMETHODIMP 149GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription) 150{ 151 aAdapterDescription.AssignLiteral(""); 152 return NS_OK; 153} 154 155/* readonly attribute DOMString adapterDescription2; */ 156NS_IMETHODIMP 157GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription) 158{ 159 return NS_ERROR_FAILURE; 160} 161 162/* readonly attribute DOMString adapterRAM; */ 163NS_IMETHODIMP 164GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM) 165{ 166 aAdapterRAM = mAdapterRAMString; 167 return NS_OK; 168} 169 170/* readonly attribute DOMString adapterRAM2; */ 171NS_IMETHODIMP 172GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM) 173{ 174 return NS_ERROR_FAILURE; 175} 176 177/* readonly attribute DOMString adapterDriver; */ 178NS_IMETHODIMP 179GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver) 180{ 181 aAdapterDriver.AssignLiteral(""); 182 return NS_OK; 183} 184 185/* readonly attribute DOMString adapterDriver2; */ 186NS_IMETHODIMP 187GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver) 188{ 189 return NS_ERROR_FAILURE; 190} 191 192/* readonly attribute DOMString adapterDriverVersion; */ 193NS_IMETHODIMP 194GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) 195{ 196 aAdapterDriverVersion.AssignLiteral(""); 197 return NS_OK; 198} 199 200/* readonly attribute DOMString adapterDriverVersion2; */ 201NS_IMETHODIMP 202GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) 203{ 204 return NS_ERROR_FAILURE; 205} 206 207/* readonly attribute DOMString adapterDriverDate; */ 208NS_IMETHODIMP 209GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate) 210{ 211 aAdapterDriverDate.AssignLiteral(""); 212 return NS_OK; 213} 214 215/* readonly attribute DOMString adapterDriverDate2; */ 216NS_IMETHODIMP 217GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate) 218{ 219 return NS_ERROR_FAILURE; 220} 221 222/* readonly attribute DOMString adapterVendorID; */ 223NS_IMETHODIMP 224GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID) 225{ 226 aAdapterVendorID = mAdapterVendorID; 227 return NS_OK; 228} 229 230/* readonly attribute DOMString adapterVendorID2; */ 231NS_IMETHODIMP 232GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID) 233{ 234 return NS_ERROR_FAILURE; 235} 236 237/* readonly attribute DOMString adapterDeviceID; */ 238NS_IMETHODIMP 239GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID) 240{ 241 aAdapterDeviceID = mAdapterDeviceID; 242 return NS_OK; 243} 244 245/* readonly attribute DOMString adapterDeviceID2; */ 246NS_IMETHODIMP 247GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID) 248{ 249 return NS_ERROR_FAILURE; 250} 251 252/* readonly attribute DOMString adapterSubsysID; */ 253NS_IMETHODIMP 254GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID) 255{ 256 return NS_ERROR_FAILURE; 257} 258 259/* readonly attribute DOMString adapterSubsysID2; */ 260NS_IMETHODIMP 261GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID) 262{ 263 return NS_ERROR_FAILURE; 264} 265 266/* readonly attribute boolean isGPU2Active; */ 267NS_IMETHODIMP 268GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) 269{ 270 return NS_ERROR_FAILURE; 271} 272 273void 274GfxInfo::AddCrashReportAnnotations() 275{ 276 nsString deviceID, vendorID, driverVersion; 277 nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion; 278 279 GetAdapterDeviceID(deviceID); 280 CopyUTF16toUTF8(deviceID, narrowDeviceID); 281 GetAdapterVendorID(vendorID); 282 CopyUTF16toUTF8(vendorID, narrowVendorID); 283 GetAdapterDriverVersion(driverVersion); 284 CopyUTF16toUTF8(driverVersion, narrowDriverVersion); 285 286 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), 287 narrowVendorID); 288 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), 289 narrowDeviceID); 290 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), 291 narrowDriverVersion); 292 /* Add an App Note for now so that we get the data immediately. These 293 * can go away after we store the above in the socorro db */ 294 nsAutoCString note; 295 /* AppendPrintf only supports 32 character strings, mrghh. */ 296 note.AppendLiteral("AdapterVendorID: "); 297 note.Append(narrowVendorID); 298 note.AppendLiteral(", AdapterDeviceID: "); 299 note.Append(narrowDeviceID); 300 CrashReporter::AppendAppNotesToCrashReport(note); 301} 302 303// We don't support checking driver versions on Mac. 304#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, ruleId) \ 305 APPEND_TO_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, \ 306 DRIVER_COMPARISON_IGNORED, V(0,0,0,0), ruleId, "") 307 308 309const nsTArray<GfxDriverInfo>& 310GfxInfo::GetGfxDriverInfo() 311{ 312 if (!mDriverInfo->Length()) { 313 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, 314 (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, 315 nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION, "FEATURE_FAILURE_MAC_ATI_NO_MSAA"); 316 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, 317 (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(RadeonX1000), 318 nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D"); 319 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, 320 (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(Geforce7300GT), 321 nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL"); 322 } 323 return *mDriverInfo; 324} 325 326nsresult 327GfxInfo::GetFeatureStatusImpl(int32_t aFeature, 328 int32_t* aStatus, 329 nsAString& aSuggestedDriverVersion, 330 const nsTArray<GfxDriverInfo>& aDriverInfo, 331 nsACString& aFailureId, 332 OperatingSystem* aOS /* = nullptr */) 333{ 334 NS_ENSURE_ARG_POINTER(aStatus); 335 aSuggestedDriverVersion.SetIsVoid(true); 336 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; 337 OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion); 338 if (aOS) 339 *aOS = os; 340 341 if (mShutdownOccurred) { 342 return NS_OK; 343 } 344 345 // Don't evaluate special cases when we're evaluating the downloaded blocklist. 346 if (!aDriverInfo.Length()) { 347 if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) { 348 // Blacklist all ATI cards on OSX, except for 349 // 0x6760 and 0x9488 350 if (mAdapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorATI), nsCaseInsensitiveStringComparator()) && 351 (mAdapterDeviceID.LowerCaseEqualsLiteral("0x6760") || 352 mAdapterDeviceID.LowerCaseEqualsLiteral("0x9488"))) { 353 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; 354 return NS_OK; 355 } 356 } else if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) { 357 // See bug 1249659 358 switch(os) { 359 case OperatingSystem::OSX10_5: 360 case OperatingSystem::OSX10_6: 361 case OperatingSystem::OSX10_7: 362 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION; 363 aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION"; 364 break; 365 default: 366 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; 367 break; 368 } 369 return NS_OK; 370 } 371 } 372 373 return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os); 374} 375 376nsresult 377GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray) 378{ 379 // Getting the refresh rate is a little hard on OS X. We could use 380 // CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little 381 // involved. Ideally we could query it from vsync. For now, we leave it out. 382 int32_t deviceCount = 0; 383 for (NSScreen* screen in [NSScreen screens]) { 384 NSRect rect = [screen frame]; 385 386 JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); 387 388 JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value((int)rect.size.width)); 389 JS_SetProperty(aCx, obj, "screenWidth", screenWidth); 390 391 JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value((int)rect.size.height)); 392 JS_SetProperty(aCx, obj, "screenHeight", screenHeight); 393 394 JS::Rooted<JS::Value> scale(aCx, JS::NumberValue(nsCocoaUtils::GetBackingScaleFactor(screen))); 395 JS_SetProperty(aCx, obj, "scale", scale); 396 397 JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj)); 398 JS_SetElement(aCx, aOutArray, deviceCount++, element); 399 } 400 return NS_OK; 401} 402 403#ifdef DEBUG 404 405// Implement nsIGfxInfoDebug 406 407/* void spoofVendorID (in DOMString aVendorID); */ 408NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID) 409{ 410 mAdapterVendorID = aVendorID; 411 return NS_OK; 412} 413 414/* void spoofDeviceID (in unsigned long aDeviceID); */ 415NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID) 416{ 417 mAdapterDeviceID = aDeviceID; 418 return NS_OK; 419} 420 421/* void spoofDriverVersion (in DOMString aDriverVersion); */ 422NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion) 423{ 424 mDriverVersion = aDriverVersion; 425 return NS_OK; 426} 427 428/* void spoofOSVersion (in unsigned long aVersion); */ 429NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) 430{ 431 mOSXVersion = aVersion; 432 return NS_OK; 433} 434 435#endif 436