Bug 1892041 - Part 3: Update test exclusions. r=spidermonkey-reviewers,dminor
[gecko.git] / widget / android / GfxInfo.cpp
blob267beaf330478ab4abaf2d25916a89dc95eeae76
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 "GfxInfo.h"
7 #include "AndroidBuild.h"
8 #include "GLContext.h"
9 #include "GLContextProvider.h"
10 #include "nsUnicharUtils.h"
11 #include "prenv.h"
12 #include "nsExceptionHandler.h"
13 #include "nsHashKeys.h"
14 #include "nsVersionComparator.h"
15 #include "nsServiceManagerUtils.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/java/GeckoAppShellWrappers.h"
19 #include "mozilla/java/HardwareCodecCapabilityUtilsWrappers.h"
21 namespace mozilla {
22 namespace widget {
24 class GfxInfo::GLStrings {
25 nsCString mVendor;
26 nsCString mRenderer;
27 nsCString mVersion;
28 nsTArray<nsCString> mExtensions;
29 bool mReady;
31 public:
32 GLStrings() : mReady(false) {}
34 const nsCString& Vendor() {
35 EnsureInitialized();
36 return mVendor;
39 // This spoofed value wins, even if the environment variable
40 // MOZ_GFX_SPOOF_GL_VENDOR was set.
41 void SpoofVendor(const nsCString& s) { mVendor = s; }
43 const nsCString& Renderer() {
44 EnsureInitialized();
45 return mRenderer;
48 // This spoofed value wins, even if the environment variable
49 // MOZ_GFX_SPOOF_GL_RENDERER was set.
50 void SpoofRenderer(const nsCString& s) { mRenderer = s; }
52 const nsCString& Version() {
53 EnsureInitialized();
54 return mVersion;
57 // This spoofed value wins, even if the environment variable
58 // MOZ_GFX_SPOOF_GL_VERSION was set.
59 void SpoofVersion(const nsCString& s) { mVersion = s; }
61 const nsTArray<nsCString>& Extensions() {
62 EnsureInitialized();
63 return mExtensions;
66 void EnsureInitialized() {
67 if (mReady) {
68 return;
71 RefPtr<gl::GLContext> gl;
72 nsCString discardFailureId;
73 gl = gl::GLContextProvider::CreateHeadless(
74 {gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE}, &discardFailureId);
76 if (!gl) {
77 // Setting mReady to true here means that we won't retry. Everything will
78 // remain blocklisted forever. Ideally, we would like to update that once
79 // any GLContext is successfully created, like the compositor's GLContext.
80 mReady = true;
81 return;
84 gl->MakeCurrent();
86 if (mVendor.IsEmpty()) {
87 const char* spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
88 if (spoofedVendor) {
89 mVendor.Assign(spoofedVendor);
90 } else {
91 mVendor.Assign((const char*)gl->fGetString(LOCAL_GL_VENDOR));
95 if (mRenderer.IsEmpty()) {
96 const char* spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
97 if (spoofedRenderer) {
98 mRenderer.Assign(spoofedRenderer);
99 } else {
100 mRenderer.Assign((const char*)gl->fGetString(LOCAL_GL_RENDERER));
104 if (mVersion.IsEmpty()) {
105 const char* spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
106 if (spoofedVersion) {
107 mVersion.Assign(spoofedVersion);
108 } else {
109 mVersion.Assign((const char*)gl->fGetString(LOCAL_GL_VERSION));
113 if (mExtensions.IsEmpty()) {
114 nsCString rawExtensions;
115 rawExtensions.Assign((const char*)gl->fGetString(LOCAL_GL_EXTENSIONS));
116 rawExtensions.Trim(" ");
118 for (auto extension : rawExtensions.Split(' ')) {
119 mExtensions.AppendElement(extension);
123 mReady = true;
127 #ifdef DEBUG
128 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
129 #endif
131 GfxInfo::GfxInfo()
132 : mInitialized(false),
133 mGLStrings(new GLStrings),
134 mOSVersionInteger(0),
135 mSDKVersion(0) {}
137 GfxInfo::~GfxInfo() {}
139 /* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after
140 * gfxPlatform initialization has occurred because they depend on it for
141 * information. (See bug 591561) */
142 nsresult GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
144 nsresult GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
146 nsresult GfxInfo::GetHasBattery(bool* aHasBattery) {
147 return NS_ERROR_NOT_IMPLEMENTED;
150 NS_IMETHODIMP
151 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
152 return NS_ERROR_FAILURE;
155 NS_IMETHODIMP
156 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
157 return NS_ERROR_FAILURE;
160 NS_IMETHODIMP
161 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
162 return NS_ERROR_FAILURE;
165 NS_IMETHODIMP
166 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
167 return NS_ERROR_NOT_IMPLEMENTED;
170 NS_IMETHODIMP
171 GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
173 void GfxInfo::EnsureInitialized() {
174 if (mInitialized) return;
176 if (!jni::IsAvailable()) {
177 gfxWarning() << "JNI missing during initialization";
178 return;
181 jni::String::LocalRef model = java::sdk::Build::MODEL();
182 mModel = model->ToString();
183 mAdapterDescription.AppendPrintf("Model: %s",
184 NS_LossyConvertUTF16toASCII(mModel).get());
186 jni::String::LocalRef product = java::sdk::Build::PRODUCT();
187 mProduct = product->ToString();
188 mAdapterDescription.AppendPrintf(", Product: %s",
189 NS_LossyConvertUTF16toASCII(mProduct).get());
191 jni::String::LocalRef manufacturer =
192 mozilla::java::sdk::Build::MANUFACTURER();
193 mManufacturer = manufacturer->ToString();
194 mAdapterDescription.AppendPrintf(
195 ", Manufacturer: %s", NS_LossyConvertUTF16toASCII(mManufacturer).get());
197 mSDKVersion = java::sdk::Build::VERSION::SDK_INT();
198 jni::String::LocalRef hardware = java::sdk::Build::HARDWARE();
199 mHardware = hardware->ToString();
200 mAdapterDescription.AppendPrintf(
201 ", Hardware: %s", NS_LossyConvertUTF16toASCII(mHardware).get());
203 jni::String::LocalRef release = java::sdk::Build::VERSION::RELEASE();
204 mOSVersion = release->ToCString();
206 mOSVersionInteger = 0;
207 char a[5], b[5], c[5], d[5];
208 SplitDriverVersion(mOSVersion.get(), a, b, c, d);
209 uint8_t na = atoi(a);
210 uint8_t nb = atoi(b);
211 uint8_t nc = atoi(c);
212 uint8_t nd = atoi(d);
214 mOSVersionInteger = (uint32_t(na) << 24) | (uint32_t(nb) << 16) |
215 (uint32_t(nc) << 8) | uint32_t(nd);
217 mAdapterDescription.AppendPrintf(
218 ", OpenGL: %s -- %s -- %s", mGLStrings->Vendor().get(),
219 mGLStrings->Renderer().get(), mGLStrings->Version().get());
221 AddCrashReportAnnotations();
222 mInitialized = true;
225 NS_IMETHODIMP
226 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
227 EnsureInitialized();
228 aAdapterDescription = NS_ConvertASCIItoUTF16(mAdapterDescription);
229 return NS_OK;
232 NS_IMETHODIMP
233 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
234 EnsureInitialized();
235 return NS_ERROR_FAILURE;
238 NS_IMETHODIMP
239 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
240 EnsureInitialized();
241 *aAdapterRAM = 0;
242 return NS_OK;
245 NS_IMETHODIMP
246 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
247 EnsureInitialized();
248 return NS_ERROR_FAILURE;
251 NS_IMETHODIMP
252 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
253 EnsureInitialized();
254 aAdapterDriver.Truncate();
255 return NS_OK;
258 NS_IMETHODIMP
259 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
260 EnsureInitialized();
261 return NS_ERROR_FAILURE;
264 NS_IMETHODIMP
265 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
266 EnsureInitialized();
267 aAdapterDriverVendor.Truncate();
268 return NS_OK;
271 NS_IMETHODIMP
272 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
273 EnsureInitialized();
274 return NS_ERROR_FAILURE;
277 NS_IMETHODIMP
278 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
279 EnsureInitialized();
280 aAdapterDriverVersion = NS_ConvertASCIItoUTF16(mGLStrings->Version());
281 return NS_OK;
284 NS_IMETHODIMP
285 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
286 EnsureInitialized();
287 return NS_ERROR_FAILURE;
290 NS_IMETHODIMP
291 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
292 EnsureInitialized();
293 aAdapterDriverDate.Truncate();
294 return NS_OK;
297 NS_IMETHODIMP
298 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
299 EnsureInitialized();
300 return NS_ERROR_FAILURE;
303 NS_IMETHODIMP
304 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
305 EnsureInitialized();
306 aAdapterVendorID = NS_ConvertASCIItoUTF16(mGLStrings->Vendor());
307 return NS_OK;
310 NS_IMETHODIMP
311 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
312 EnsureInitialized();
313 return NS_ERROR_FAILURE;
316 NS_IMETHODIMP
317 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
318 EnsureInitialized();
319 aAdapterDeviceID = NS_ConvertASCIItoUTF16(mGLStrings->Renderer());
320 return NS_OK;
323 NS_IMETHODIMP
324 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
325 EnsureInitialized();
326 return NS_ERROR_FAILURE;
329 NS_IMETHODIMP
330 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
331 EnsureInitialized();
332 return NS_ERROR_FAILURE;
335 NS_IMETHODIMP
336 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
337 EnsureInitialized();
338 return NS_ERROR_FAILURE;
341 NS_IMETHODIMP
342 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) {
343 EnsureInitialized();
344 return NS_ERROR_FAILURE;
347 NS_IMETHODIMP
348 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
349 return NS_ERROR_NOT_IMPLEMENTED;
352 void GfxInfo::AddCrashReportAnnotations() {
353 CrashReporter::RecordAnnotationNSCString(
354 CrashReporter::Annotation::AdapterVendorID, mGLStrings->Vendor());
355 CrashReporter::RecordAnnotationNSCString(
356 CrashReporter::Annotation::AdapterDeviceID, mGLStrings->Renderer());
357 CrashReporter::RecordAnnotationNSCString(
358 CrashReporter::Annotation::AdapterDriverVersion, mGLStrings->Version());
361 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
362 if (sDriverInfo->IsEmpty()) {
363 APPEND_TO_DRIVER_BLOCKLIST2(
364 OperatingSystem::Android, DeviceFamily::All,
365 nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK,
366 DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions,
367 "FEATURE_OK_FORCE_OPENGL");
370 return *sDriverInfo;
373 nsresult GfxInfo::GetFeatureStatusImpl(
374 int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
375 const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
376 OperatingSystem* aOS /* = nullptr */) {
377 NS_ENSURE_ARG_POINTER(aStatus);
378 aSuggestedDriverVersion.SetIsVoid(true);
379 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
380 OperatingSystem os = OperatingSystem::Android;
381 if (aOS) *aOS = os;
383 if (sShutdownOccurred) {
384 return NS_OK;
387 // OpenGL layers are never blocklisted on Android.
388 // This early return is so we avoid potentially slow
389 // GLStrings initialization on startup when we initialize GL layers.
390 if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS) {
391 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
392 return NS_OK;
395 EnsureInitialized();
397 if (mGLStrings->Vendor().IsEmpty() || mGLStrings->Renderer().IsEmpty()) {
398 if (OnlyAllowFeatureOnKnownConfig(aFeature)) {
399 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
400 aFailureId = "FEATURE_FAILURE_EMPTY_VENDOR_OR_RENDERER";
401 } else {
402 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
404 return NS_OK;
407 // Don't evaluate special cases when evaluating the downloaded blocklist.
408 if (aDriverInfo.IsEmpty()) {
409 if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
410 if (mGLStrings->Renderer().Find("Vivante GC1000") != -1) {
411 // Blocklist Vivante GC1000. See bug 1248183.
412 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
413 aFailureId = "FEATURE_FAILED_CANVAS_2D_HW";
414 } else {
415 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
417 return NS_OK;
420 if (aFeature == FEATURE_WEBGL_OPENGL) {
421 if (mGLStrings->Renderer().Find("Adreno 200") != -1 ||
422 mGLStrings->Renderer().Find("Adreno 205") != -1) {
423 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
424 aFailureId = "FEATURE_FAILURE_ADRENO_20x";
425 return NS_OK;
428 if (mHardware.EqualsLiteral("ville")) {
429 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
430 aFailureId = "FEATURE_FAILURE_VILLE";
431 return NS_OK;
435 if (aFeature == FEATURE_STAGEFRIGHT) {
436 NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer);
437 NS_LossyConvertUTF16toASCII cModel(mModel);
438 NS_LossyConvertUTF16toASCII cHardware(mHardware);
440 if (cHardware.EqualsLiteral("antares") ||
441 cHardware.EqualsLiteral("harmony") ||
442 cHardware.EqualsLiteral("picasso") ||
443 cHardware.EqualsLiteral("picasso_e") ||
444 cHardware.EqualsLiteral("ventana") ||
445 cHardware.EqualsLiteral("rk30board")) {
446 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
447 aFailureId = "FEATURE_FAILURE_STAGE_HW";
448 return NS_OK;
451 if (CompareVersions(mOSVersion.get(), "4.1.0") < 0) {
452 // Whitelist:
453 // All Samsung ICS devices, except for:
454 // Samsung SGH-I717 (Bug 845729)
455 // Samsung SGH-I727 (Bug 845729)
456 // Samsung SGH-I757 (Bug 845729)
457 // All Galaxy nexus ICS devices
458 // Sony Xperia Ion (LT28) ICS devices
459 bool isWhitelisted =
460 cModel.Equals("LT28h", nsCaseInsensitiveCStringComparator) ||
461 cManufacturer.Equals("samsung",
462 nsCaseInsensitiveCStringComparator) ||
463 cModel.Equals(
464 "galaxy nexus",
465 nsCaseInsensitiveCStringComparator); // some Galaxy Nexus
466 // have
467 // manufacturer=amazon
469 if (cModel.LowerCaseFindASCII("sgh-i717") != -1 ||
470 cModel.LowerCaseFindASCII("sgh-i727") != -1 ||
471 cModel.LowerCaseFindASCII("sgh-i757") != -1) {
472 isWhitelisted = false;
475 if (!isWhitelisted) {
476 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
477 aFailureId = "FEATURE_FAILURE_4_1_HW";
478 return NS_OK;
480 } else if (CompareVersions(mOSVersion.get(), "4.2.0") < 0) {
481 // Whitelist:
482 // All JB phones except for those in blocklist below
483 // Blocklist:
484 // Samsung devices from bug 812881 and 853522.
485 // Motorola XT890 from bug 882342.
486 bool isBlocklisted = cModel.LowerCaseFindASCII("gt-p3100") != -1 ||
487 cModel.LowerCaseFindASCII("gt-p3110") != -1 ||
488 cModel.LowerCaseFindASCII("gt-p3113") != -1 ||
489 cModel.LowerCaseFindASCII("gt-p5100") != -1 ||
490 cModel.LowerCaseFindASCII("gt-p5110") != -1 ||
491 cModel.LowerCaseFindASCII("gt-p5113") != -1 ||
492 cModel.LowerCaseFindASCII("xt890") != -1;
494 if (isBlocklisted) {
495 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
496 aFailureId = "FEATURE_FAILURE_4_2_HW";
497 return NS_OK;
499 } else if (CompareVersions(mOSVersion.get(), "4.3.0") < 0) {
500 // Blocklist all Sony devices
501 if (cManufacturer.LowerCaseFindASCII("sony") != -1) {
502 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
503 aFailureId = "FEATURE_FAILURE_4_3_SONY";
504 return NS_OK;
509 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) {
510 if (jni::IsAvailable()) {
511 *aStatus = WebRtcHwVp8EncodeSupported();
512 aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE";
513 return NS_OK;
516 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) {
517 if (jni::IsAvailable()) {
518 *aStatus = WebRtcHwVp8DecodeSupported();
519 aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE";
520 return NS_OK;
523 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_H264) {
524 if (jni::IsAvailable()) {
525 *aStatus = WebRtcHwH264Supported();
526 aFailureId = "FEATURE_FAILURE_WEBRTC_H264";
527 return NS_OK;
530 if (aFeature == FEATURE_VP8_HW_DECODE ||
531 aFeature == FEATURE_VP9_HW_DECODE) {
532 NS_LossyConvertUTF16toASCII model(mModel);
533 bool isBlocked =
534 // GIFV crash, see bug 1232911.
535 model.Equals("GT-N8013", nsCaseInsensitiveCStringComparator);
537 if (isBlocked) {
538 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
539 aFailureId = "FEATURE_FAILURE_VPx";
540 } else {
541 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
543 return NS_OK;
546 if (aFeature == FEATURE_WEBRENDER) {
547 const bool isMali4xx =
548 mGLStrings->Renderer().LowerCaseFindASCII("mali-4") >= 0;
550 const bool isPowerVrG6110 =
551 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6110") >= 0;
553 const bool isVivanteGC7000UL =
554 mGLStrings->Renderer().LowerCaseFindASCII("vivante gc7000ul") >= 0;
556 const bool isPowerVrFenceSyncCrash =
557 (mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6200") >=
558 0 ||
559 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6430") >=
560 0 ||
561 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue gx6250") >=
562 0) &&
563 (mGLStrings->Version().Find("3283119") >= 0 ||
564 mGLStrings->Version().Find("3443629") >= 0 ||
565 mGLStrings->Version().Find("3573678") >= 0 ||
566 mGLStrings->Version().Find("3830101") >= 0);
568 if (isMali4xx) {
569 // Mali 4xx does not support GLES 3.
570 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
571 aFailureId = "FEATURE_FAILURE_NO_GLES_3";
572 } else if (isPowerVrG6110) {
573 // Blocked on PowerVR Rogue G6110 due to bug 1742986 and bug 1717863.
574 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
575 aFailureId = "FEATURE_FAILURE_POWERVR_G6110";
576 } else if (isVivanteGC7000UL) {
577 // Blocked on Vivante GC7000UL due to bug 1719327.
578 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
579 aFailureId = "FEATURE_FAILURE_VIVANTE_GC7000UL";
580 } else if (isPowerVrFenceSyncCrash) {
581 // Blocked on various PowerVR GPUs due to bug 1773128.
582 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
583 aFailureId = "FEATURE_FAILURE_POWERVR_FENCE_SYNC_CRASH";
584 } else {
585 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
587 return NS_OK;
590 if (aFeature == FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS) {
591 // Emulator with SwiftShader is buggy when attempting to clear picture
592 // cache textures with a scissor rect set.
593 const bool isEmulatorSwiftShader =
594 mGLStrings->Renderer().Find(
595 "Android Emulator OpenGL ES Translator (Google SwiftShader)") >=
597 if (isEmulatorSwiftShader) {
598 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
599 aFailureId = "FEATURE_FAILURE_BUG_1603515";
600 } else {
601 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
603 return NS_OK;
606 if (aFeature == FEATURE_WEBRENDER_SHADER_CACHE) {
607 // Program binaries are known to be buggy on Adreno 3xx. While we haven't
608 // encountered any correctness or stability issues with them, loading them
609 // fails more often than not, so is a waste of time. Better to just not
610 // even attempt to cache them. See bug 1615574.
611 const bool isAdreno3xx =
612 mGLStrings->Renderer().LowerCaseFindASCII("adreno (tm) 3") >= 0;
613 if (isAdreno3xx) {
614 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
615 aFailureId = "FEATURE_FAILURE_ADRENO_3XX";
616 } else {
617 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
621 if (aFeature == FEATURE_WEBRENDER_OPTIMIZED_SHADERS) {
622 // Optimized shaders result in completely broken rendering on some Mali-T
623 // devices. We have seen this on T6xx, T7xx, and T8xx on android versions
624 // up to 5.1, and on T6xx on versions up to android 7.1. As a precaution
625 // disable for all Mali-T regardless of version. See bug 1689064 and bug
626 // 1707283 for details.
627 const bool isMaliT =
628 mGLStrings->Renderer().LowerCaseFindASCII("mali-t") >= 0;
629 if (isMaliT) {
630 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
631 aFailureId = "FEATURE_FAILURE_BUG_1689064";
632 } else {
633 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
635 return NS_OK;
638 if (aFeature == FEATURE_WEBRENDER_PARTIAL_PRESENT) {
639 // Block partial present on some devices due to rendering issues.
640 // On Mali-Txxx due to bug 1680087 and bug 1707815.
641 // On Adreno 3xx GPUs due to bug 1695771.
642 const bool isMaliT =
643 mGLStrings->Renderer().LowerCaseFindASCII("mali-t") >= 0;
644 const bool isAdreno3xx =
645 mGLStrings->Renderer().LowerCaseFindASCII("adreno (tm) 3") >= 0;
646 if (isMaliT || isAdreno3xx) {
647 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
648 aFailureId = "FEATURE_FAILURE_BUG_1680087_1695771_1707815";
649 } else {
650 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
652 return NS_OK;
656 if (aFeature == FEATURE_GL_SWIZZLE) {
657 // Swizzling appears to be buggy on PowerVR Rogue devices with webrender.
658 // See bug 1704783.
659 const bool isPowerVRRogue =
660 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue") >= 0;
661 if (isPowerVRRogue) {
662 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
663 aFailureId = "FEATURE_FAILURE_POWERVR_ROGUE";
664 } else {
665 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
667 return NS_OK;
670 if (aFeature == FEATURE_WEBGPU) {
671 // Ensure WebGPU is disabled by default on Android until it is better
672 // tested.
673 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
674 aFailureId = "FEATURE_FAILURE_WEBGPU_ANDROID";
675 return NS_OK;
678 return GfxInfoBase::GetFeatureStatusImpl(
679 aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
682 static nsCString FeatureCacheOsVerPrefName(int32_t aFeature) {
683 nsCString osPrefName;
684 osPrefName.AppendASCII("gfxinfo.cache.");
685 osPrefName.AppendInt(aFeature);
686 osPrefName.AppendASCII(".osver");
687 return osPrefName;
690 static nsCString FeatureCacheAppVerPrefName(int32_t aFeature) {
691 nsCString osPrefName;
692 osPrefName.AppendASCII("gfxinfo.cache.");
693 osPrefName.AppendInt(aFeature);
694 osPrefName.AppendASCII(".appver");
695 return osPrefName;
698 static nsCString FeatureCacheValuePrefName(int32_t aFeature) {
699 nsCString osPrefName;
700 osPrefName.AppendASCII("gfxinfo.cache.");
701 osPrefName.AppendInt(aFeature);
702 osPrefName.AppendASCII(".value");
703 return osPrefName;
706 static bool GetCachedFeatureVal(int32_t aFeature, uint32_t aExpectedOsVer,
707 const nsCString& aCurrentAppVer,
708 int32_t& aOutStatus) {
709 uint32_t osVer = 0;
710 nsresult rv =
711 Preferences::GetUint(FeatureCacheOsVerPrefName(aFeature).get(), &osVer);
712 if (NS_FAILED(rv) || osVer != aExpectedOsVer) {
713 return false;
715 // Bug 1804287 requires we invalidate cached values for new builds to allow
716 // for code changes to modify the features support.
717 nsAutoCString cachedAppVersion;
718 rv = Preferences::GetCString(FeatureCacheAppVerPrefName(aFeature).get(),
719 cachedAppVersion);
720 if (NS_FAILED(rv) || !aCurrentAppVer.Equals(cachedAppVersion)) {
721 return false;
723 int32_t status = 0;
724 rv = Preferences::GetInt(FeatureCacheValuePrefName(aFeature).get(), &status);
725 if (NS_FAILED(rv)) {
726 return false;
728 aOutStatus = status;
729 return true;
732 static void SetCachedFeatureVal(int32_t aFeature, uint32_t aOsVer,
733 const nsCString& aCurrentAppVer,
734 int32_t aStatus) {
735 // Ignore failures; not much we can do anyway.
736 Preferences::SetUint(FeatureCacheOsVerPrefName(aFeature).get(), aOsVer);
737 Preferences::SetCString(FeatureCacheAppVerPrefName(aFeature).get(),
738 aCurrentAppVer);
739 Preferences::SetInt(FeatureCacheValuePrefName(aFeature).get(), aStatus);
742 int32_t GfxInfo::WebRtcHwVp8EncodeSupported() {
743 MOZ_ASSERT(jni::IsAvailable());
745 // The Android side of this calculation is very slow, so we cache the result
746 // in preferences, invalidating if the OS version changes.
748 int32_t status = 0;
749 const auto& currentAppVersion = GfxInfoBase::GetApplicationVersion();
750 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
751 mOSVersionInteger, currentAppVersion, status)) {
752 return status;
755 status = java::GeckoAppShell::HasHWVP8Encoder()
756 ? nsIGfxInfo::FEATURE_STATUS_OK
757 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
759 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, mOSVersionInteger,
760 currentAppVersion, status);
762 return status;
765 int32_t GfxInfo::WebRtcHwVp8DecodeSupported() {
766 MOZ_ASSERT(jni::IsAvailable());
768 // The Android side of this caclulation is very slow, so we cache the result
769 // in preferences, invalidating if the OS version changes.
771 int32_t status = 0;
772 const auto& appVersion = GfxInfoBase::GetApplicationVersion();
773 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
774 mOSVersionInteger, appVersion, status)) {
775 return status;
778 status = java::GeckoAppShell::HasHWVP8Decoder()
779 ? nsIGfxInfo::FEATURE_STATUS_OK
780 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
782 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, mOSVersionInteger,
783 appVersion, status);
785 return status;
788 int32_t GfxInfo::WebRtcHwH264Supported() {
789 MOZ_ASSERT(jni::IsAvailable());
791 // The Android side of this calculation is very slow, so we cache the result
792 // in preferences, invalidating if the OS version changes.
794 int32_t status = 0;
795 const auto& currentAppVersion = GfxInfoBase::GetApplicationVersion();
796 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264,
797 mOSVersionInteger, currentAppVersion, status)) {
798 return status;
801 status = java::HardwareCodecCapabilityUtils::HasHWH264()
802 ? nsIGfxInfo::FEATURE_STATUS_OK
803 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
805 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264, mOSVersionInteger,
806 currentAppVersion, status);
808 return status;
811 #ifdef DEBUG
813 // Implement nsIGfxInfoDebug
815 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
816 mGLStrings->SpoofVendor(NS_LossyConvertUTF16toASCII(aVendorID));
817 return NS_OK;
820 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
821 mGLStrings->SpoofRenderer(NS_LossyConvertUTF16toASCII(aDeviceID));
822 return NS_OK;
825 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
826 mGLStrings->SpoofVersion(NS_LossyConvertUTF16toASCII(aDriverVersion));
827 return NS_OK;
830 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
831 EnsureInitialized();
832 mOSVersion = aVersion;
833 return NS_OK;
836 #endif
838 nsString GfxInfo::Model() {
839 EnsureInitialized();
840 return mModel;
843 nsString GfxInfo::Hardware() {
844 EnsureInitialized();
845 return mHardware;
848 nsString GfxInfo::Product() {
849 EnsureInitialized();
850 return mProduct;
853 nsString GfxInfo::Manufacturer() {
854 EnsureInitialized();
855 return mManufacturer;
858 uint32_t GfxInfo::OperatingSystemVersion() {
859 EnsureInitialized();
860 return mOSVersionInteger;
863 } // namespace widget
864 } // namespace mozilla