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 defined(__aarch64__)
149 // If we found IOPCI VGA devices, don't look for AGXAccelerator devices
150 if (mNumGPUsDetected > 0) {
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);
174 MOZ_DIAGNOSTIC_ASSERT(mNumGPUsDetected > 0, "Failed to detect any GPUs");
177 nsresult GfxInfo::Init() {
178 nsresult rv = GfxInfoBase::Init();
180 // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
181 // even when we don't want to. We'll avoid doing so for now and just
182 // use the device ids.
186 AddCrashReportAnnotations();
188 mOSXVersion = nsCocoaFeatures::macOSVersion();
194 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
197 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
199 /* readonly attribute bool HasBattery; */
200 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
201 return NS_ERROR_NOT_IMPLEMENTED;
204 /* readonly attribute DOMString DWriteVersion; */
206 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
207 return NS_ERROR_FAILURE;
211 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
212 return NS_ERROR_FAILURE;
215 /* readonly attribute DOMString cleartypeParameters; */
217 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
218 return NS_ERROR_FAILURE;
221 /* readonly attribute DOMString windowProtocol; */
223 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
224 return NS_ERROR_NOT_IMPLEMENTED;
227 /* readonly attribute DOMString testType; */
229 GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
231 /* readonly attribute DOMString adapterDescription; */
233 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
234 aAdapterDescription.AssignLiteral("");
238 /* readonly attribute DOMString adapterDescription2; */
240 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
241 if (mNumGPUsDetected < 2) {
242 return NS_ERROR_FAILURE;
244 aAdapterDescription.AssignLiteral("");
248 /* readonly attribute DOMString adapterRAM; */
250 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
251 *aAdapterRAM = mAdapterRAM[0];
255 /* readonly attribute DOMString adapterRAM2; */
257 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
258 if (mNumGPUsDetected < 2) {
259 return NS_ERROR_FAILURE;
261 *aAdapterRAM = mAdapterRAM[1];
265 /* readonly attribute DOMString adapterDriver; */
267 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
268 aAdapterDriver.AssignLiteral("");
272 /* readonly attribute DOMString adapterDriver2; */
274 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
275 if (mNumGPUsDetected < 2) {
276 return NS_ERROR_FAILURE;
278 aAdapterDriver.AssignLiteral("");
282 /* readonly attribute DOMString adapterDriverVendor; */
284 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
285 aAdapterDriverVendor.AssignLiteral("");
289 /* readonly attribute DOMString adapterDriverVendor2; */
291 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
292 if (mNumGPUsDetected < 2) {
293 return NS_ERROR_FAILURE;
295 aAdapterDriverVendor.AssignLiteral("");
299 /* readonly attribute DOMString adapterDriverVersion; */
301 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
302 aAdapterDriverVersion.AssignLiteral("");
306 /* readonly attribute DOMString adapterDriverVersion2; */
308 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
309 if (mNumGPUsDetected < 2) {
310 return NS_ERROR_FAILURE;
312 aAdapterDriverVersion.AssignLiteral("");
316 /* readonly attribute DOMString adapterDriverDate; */
318 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
319 aAdapterDriverDate.AssignLiteral("");
323 /* readonly attribute DOMString adapterDriverDate2; */
325 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
326 if (mNumGPUsDetected < 2) {
327 return NS_ERROR_FAILURE;
329 aAdapterDriverDate.AssignLiteral("");
333 /* readonly attribute DOMString adapterVendorID; */
335 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
336 aAdapterVendorID = mAdapterVendorID[0];
340 /* readonly attribute DOMString adapterVendorID2; */
342 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
343 if (mNumGPUsDetected < 2) {
344 return NS_ERROR_FAILURE;
346 aAdapterVendorID = mAdapterVendorID[1];
350 /* readonly attribute DOMString adapterDeviceID; */
352 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
353 aAdapterDeviceID = mAdapterDeviceID[0];
357 /* readonly attribute DOMString adapterDeviceID2; */
359 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
360 if (mNumGPUsDetected < 2) {
361 return NS_ERROR_FAILURE;
363 aAdapterDeviceID = mAdapterDeviceID[1];
367 /* readonly attribute DOMString adapterSubsysID; */
369 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
370 return NS_ERROR_FAILURE;
373 /* readonly attribute DOMString adapterSubsysID2; */
375 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
376 return NS_ERROR_FAILURE;
380 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
381 return NS_ERROR_NOT_IMPLEMENTED;
384 /* readonly attribute boolean isGPU2Active; */
386 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
388 void GfxInfo::AddCrashReportAnnotations() {
389 nsString deviceID, vendorID, driverVersion;
390 nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion;
392 GetAdapterDeviceID(deviceID);
393 CopyUTF16toUTF8(deviceID, narrowDeviceID);
394 GetAdapterVendorID(vendorID);
395 CopyUTF16toUTF8(vendorID, narrowVendorID);
396 GetAdapterDriverVersion(driverVersion);
397 CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
399 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
401 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
403 CrashReporter::AnnotateCrashReport(
404 CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
407 // We don't support checking driver versions on Mac.
408 #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
409 APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, \
410 DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
413 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
414 if (!sDriverInfo->Length()) {
415 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
416 OperatingSystem::OSX, DeviceFamily::RadeonX1000,
417 nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
418 "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
419 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
420 OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
421 nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
422 "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
423 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
424 OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
425 nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
426 "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
427 // We block texture swizzling everwhere on mac because it's broken in some
428 // configurations and we want to support GPU switching.
429 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
430 OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
431 nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
432 "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
434 // Older generation Intel devices do not perform well with WebRender.
435 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
436 OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
437 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
438 "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
440 // Intel HD3000 disabled due to bug 1661505
441 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
442 OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
443 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
444 "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
446 // wgpu doesn't safely support OOB behavior on Metal yet.
447 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
448 OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
449 nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
450 "FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
455 OperatingSystem GfxInfo::GetOperatingSystem() {
456 return OSXVersionToOperatingSystem(mOSXVersion);
459 nsresult GfxInfo::GetFeatureStatusImpl(
460 int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
461 const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
462 OperatingSystem* aOS /* = nullptr */) {
463 NS_ENSURE_ARG_POINTER(aStatus);
464 aSuggestedDriverVersion.SetIsVoid(true);
465 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
466 OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
469 if (sShutdownOccurred) {
473 // Don't evaluate special cases when we're evaluating the downloaded
475 if (!aDriverInfo.Length()) {
476 if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
479 case OperatingSystem::OSX10_5:
480 case OperatingSystem::OSX10_6:
481 case OperatingSystem::OSX10_7:
482 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
483 aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
486 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
490 } else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER &&
491 nsCocoaFeatures::ProcessIsRosettaTranslated()) {
492 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
493 aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC_ROSETTA";
498 return GfxInfoBase::GetFeatureStatusImpl(
499 aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
504 // Implement nsIGfxInfoDebug
506 /* void spoofVendorID (in DOMString aVendorID); */
507 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
508 mAdapterVendorID[0] = aVendorID;
512 /* void spoofDeviceID (in unsigned long aDeviceID); */
513 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
514 mAdapterDeviceID[0] = aDeviceID;
518 /* void spoofDriverVersion (in DOMString aDriverVersion); */
519 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
520 mDriverVersion[0] = aDriverVersion;
524 /* void spoofOSVersion (in unsigned long aVersion); */
525 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
526 mOSXVersion = aVersion;