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/. */
6 #include <OpenGL/OpenGL.h>
7 #include <OpenGL/CGLRenderers.h>
9 #include "mozilla/ArrayUtils.h"
12 #include "nsUnicharUtils.h"
13 #include "nsExceptionHandler.h"
14 #include "nsCocoaFeatures.h"
15 #include "nsCocoaUtils.h"
16 #include "mozilla/Preferences.h"
17 #include "js/PropertyAndElement.h" // JS_SetElement, JS_SetProperty
21 #import <Foundation/Foundation.h>
22 #import <IOKit/IOKitLib.h>
23 #import <Cocoa/Cocoa.h>
27 using namespace mozilla;
28 using namespace mozilla::widget;
31 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
34 GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} {
35 mAdapterRAM[0] = mAdapterRAM[1] = 0;
38 static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
39 switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
41 switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
43 return OperatingSystem::OSX10_6;
45 return OperatingSystem::OSX10_7;
47 return OperatingSystem::OSX10_8;
49 return OperatingSystem::OSX10_9;
51 return OperatingSystem::OSX10_10;
53 return OperatingSystem::OSX10_11;
55 return OperatingSystem::OSX10_12;
57 return OperatingSystem::OSX10_13;
59 return OperatingSystem::OSX10_14;
61 return OperatingSystem::OSX10_15;
63 // Depending on the SDK version, we either get 10.16 or 11.0.
64 // Normalize this to 11.0.
65 return OperatingSystem::OSX11_0;
71 switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
73 return OperatingSystem::OSX11_0;
80 return OperatingSystem::Unknown;
82 // The following three functions are derived from Chromium code
83 static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
84 CFStringRef propertyName) {
85 return IORegistryEntrySearchCFProperty(
86 dspPort, kIOServicePlane, propertyName, kCFAllocatorDefault,
87 kIORegistryIterateRecursively | kIORegistryIterateParents);
90 static uint32_t IntValueOfCFData(CFDataRef d) {
94 const uint32_t* vp = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(d));
95 if (vp != NULL) value = *vp;
101 void GfxInfo::GetDeviceInfo() {
102 mNumGPUsDetected = 0;
104 CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
105 io_iterator_t io_iter;
106 if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict,
107 &io_iter) != kIOReturnSuccess) {
108 MOZ_DIAGNOSTIC_ASSERT(
110 "Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
114 io_registry_entry_t entry = IO_OBJECT_NULL;
115 while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
116 constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
117 CFTypeRef class_code_ref =
118 SearchPortForProperty(entry, CFSTR("class-code"));
119 if (class_code_ref) {
120 const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
121 CFRelease(class_code_ref);
123 if (class_code == kClassCodeDisplayVGA) {
124 CFTypeRef vendor_id_ref =
125 SearchPortForProperty(entry, CFSTR("vendor-id"));
127 mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
128 "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
129 CFRelease(vendor_id_ref);
131 CFTypeRef device_id_ref =
132 SearchPortForProperty(entry, CFSTR("device-id"));
134 mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
135 "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
136 CFRelease(device_id_ref);
141 IOObjectRelease(entry);
142 if (mNumGPUsDetected == 2) {
146 IOObjectRelease(io_iter);
148 // If we found IOPCI VGA devices, don't look for other devices
149 if (mNumGPUsDetected > 0) {
153 #if defined(__aarch64__)
154 CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
155 if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict,
156 &io_iter) == kIOReturnSuccess) {
157 io_registry_entry_t entry = IO_OBJECT_NULL;
158 while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
159 CFTypeRef vendor_id_ref =
160 SearchPortForProperty(entry, CFSTR("vendor-id"));
162 mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
163 "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
164 CFRelease(vendor_id_ref);
167 IOObjectRelease(entry);
170 IOObjectRelease(io_iter);
173 // If we found an AGXAccelerator, don't look for an AppleParavirtGPU
174 if (mNumGPUsDetected > 0) {
179 CFMutableDictionaryRef apv_dev_dict = IOServiceMatching("AppleParavirtGPU");
180 if (IOServiceGetMatchingServices(kIOMasterPortDefault, apv_dev_dict,
181 &io_iter) == kIOReturnSuccess) {
182 io_registry_entry_t entry = IO_OBJECT_NULL;
183 while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
184 CFTypeRef vendor_id_ref =
185 SearchPortForProperty(entry, CFSTR("vendor-id"));
187 mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
188 "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
189 CFRelease(vendor_id_ref);
192 CFTypeRef device_id_ref =
193 SearchPortForProperty(entry, CFSTR("device-id"));
195 mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
196 "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
197 CFRelease(device_id_ref);
200 IOObjectRelease(entry);
203 IOObjectRelease(io_iter);
206 MOZ_DIAGNOSTIC_ASSERT(mNumGPUsDetected > 0, "Failed to detect any GPUs");
209 nsresult GfxInfo::Init() {
210 nsresult rv = GfxInfoBase::Init();
212 // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
213 // even when we don't want to. We'll avoid doing so for now and just
214 // use the device ids.
218 AddCrashReportAnnotations();
220 mOSXVersion = nsCocoaFeatures::macOSVersion();
226 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
229 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
231 /* readonly attribute bool HasBattery; */
232 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
233 return NS_ERROR_NOT_IMPLEMENTED;
236 /* readonly attribute DOMString DWriteVersion; */
238 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
239 return NS_ERROR_FAILURE;
243 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
244 return NS_ERROR_FAILURE;
247 /* readonly attribute DOMString cleartypeParameters; */
249 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
250 return NS_ERROR_FAILURE;
253 /* readonly attribute DOMString windowProtocol; */
255 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
256 return NS_ERROR_NOT_IMPLEMENTED;
259 /* readonly attribute DOMString testType; */
261 GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
263 /* readonly attribute DOMString adapterDescription; */
265 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
266 aAdapterDescription.AssignLiteral("");
270 /* readonly attribute DOMString adapterDescription2; */
272 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
273 if (mNumGPUsDetected < 2) {
274 return NS_ERROR_FAILURE;
276 aAdapterDescription.AssignLiteral("");
280 /* readonly attribute DOMString adapterRAM; */
282 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
283 *aAdapterRAM = mAdapterRAM[0];
287 /* readonly attribute DOMString adapterRAM2; */
289 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
290 if (mNumGPUsDetected < 2) {
291 return NS_ERROR_FAILURE;
293 *aAdapterRAM = mAdapterRAM[1];
297 /* readonly attribute DOMString adapterDriver; */
299 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
300 aAdapterDriver.AssignLiteral("");
304 /* readonly attribute DOMString adapterDriver2; */
306 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
307 if (mNumGPUsDetected < 2) {
308 return NS_ERROR_FAILURE;
310 aAdapterDriver.AssignLiteral("");
314 /* readonly attribute DOMString adapterDriverVendor; */
316 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
317 aAdapterDriverVendor.AssignLiteral("");
321 /* readonly attribute DOMString adapterDriverVendor2; */
323 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
324 if (mNumGPUsDetected < 2) {
325 return NS_ERROR_FAILURE;
327 aAdapterDriverVendor.AssignLiteral("");
331 /* readonly attribute DOMString adapterDriverVersion; */
333 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
334 aAdapterDriverVersion.AssignLiteral("");
338 /* readonly attribute DOMString adapterDriverVersion2; */
340 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
341 if (mNumGPUsDetected < 2) {
342 return NS_ERROR_FAILURE;
344 aAdapterDriverVersion.AssignLiteral("");
348 /* readonly attribute DOMString adapterDriverDate; */
350 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
351 aAdapterDriverDate.AssignLiteral("");
355 /* readonly attribute DOMString adapterDriverDate2; */
357 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
358 if (mNumGPUsDetected < 2) {
359 return NS_ERROR_FAILURE;
361 aAdapterDriverDate.AssignLiteral("");
365 /* readonly attribute DOMString adapterVendorID; */
367 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
368 aAdapterVendorID = mAdapterVendorID[0];
372 /* readonly attribute DOMString adapterVendorID2; */
374 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
375 if (mNumGPUsDetected < 2) {
376 return NS_ERROR_FAILURE;
378 aAdapterVendorID = mAdapterVendorID[1];
382 /* readonly attribute DOMString adapterDeviceID; */
384 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
385 aAdapterDeviceID = mAdapterDeviceID[0];
389 /* readonly attribute DOMString adapterDeviceID2; */
391 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
392 if (mNumGPUsDetected < 2) {
393 return NS_ERROR_FAILURE;
395 aAdapterDeviceID = mAdapterDeviceID[1];
399 /* readonly attribute DOMString adapterSubsysID; */
401 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
402 return NS_ERROR_FAILURE;
405 /* readonly attribute DOMString adapterSubsysID2; */
407 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
408 return NS_ERROR_FAILURE;
412 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
413 return NS_ERROR_NOT_IMPLEMENTED;
416 /* readonly attribute boolean isGPU2Active; */
418 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
420 void GfxInfo::AddCrashReportAnnotations() {
421 nsString deviceID, vendorID, driverVersion;
423 GetAdapterDeviceID(deviceID);
424 GetAdapterVendorID(vendorID);
425 GetAdapterDriverVersion(driverVersion);
427 CrashReporter::RecordAnnotationNSString(
428 CrashReporter::Annotation::AdapterVendorID, vendorID);
429 CrashReporter::RecordAnnotationNSString(
430 CrashReporter::Annotation::AdapterDeviceID, deviceID);
431 CrashReporter::RecordAnnotationNSString(
432 CrashReporter::Annotation::AdapterDriverVersion, driverVersion);
435 // We don't support checking driver versions on Mac.
436 #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
437 APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, \
438 DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
441 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
442 if (!sDriverInfo->Length()) {
443 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
444 OperatingSystem::OSX, DeviceFamily::RadeonX1000,
445 nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
446 "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
447 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
448 OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
449 nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
450 "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
451 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
452 OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
453 nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
454 "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
455 // We block texture swizzling everwhere on mac because it's broken in some
456 // configurations and we want to support GPU switching.
457 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
458 OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
459 nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
460 "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
462 // Older generation Intel devices do not perform well with WebRender.
463 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
464 OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
465 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
466 "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
468 // Intel HD3000 disabled due to bug 1661505
469 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
470 OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
471 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
472 "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
477 OperatingSystem GfxInfo::GetOperatingSystem() {
478 return OSXVersionToOperatingSystem(mOSXVersion);
481 nsresult GfxInfo::GetFeatureStatusImpl(
482 int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
483 const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
484 OperatingSystem* aOS /* = nullptr */) {
485 NS_ENSURE_ARG_POINTER(aStatus);
486 aSuggestedDriverVersion.SetIsVoid(true);
487 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
488 OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
491 if (sShutdownOccurred) {
495 // Don't evaluate special cases when we're evaluating the downloaded
497 if (!aDriverInfo.Length()) {
498 if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
501 case OperatingSystem::OSX10_5:
502 case OperatingSystem::OSX10_6:
503 case OperatingSystem::OSX10_7:
504 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
505 aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
508 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
512 } else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER &&
513 nsCocoaFeatures::ProcessIsRosettaTranslated()) {
514 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
515 aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC_ROSETTA";
520 return GfxInfoBase::GetFeatureStatusImpl(
521 aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
526 // Implement nsIGfxInfoDebug
528 /* void spoofVendorID (in DOMString aVendorID); */
529 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
530 mAdapterVendorID[0] = aVendorID;
534 /* void spoofDeviceID (in unsigned long aDeviceID); */
535 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
536 mAdapterDeviceID[0] = aDeviceID;
540 /* void spoofDriverVersion (in DOMString aDriverVersion); */
541 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
542 mDriverVersion[0] = aDriverVersion;
546 /* void spoofOSVersion (in unsigned long aVersion); */
547 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
548 mOSXVersion = aVersion;