Bug 1794292 - [ANGLE] cherry-pick init-gl-point-size. r=gfx-reviewers,bradwerth
[gecko.git] / widget / android / GfxInfo.cpp
blobf895fabc67d4c0e3b3294cb8a1ed28bd59dc57af
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 // the HARDWARE field isn't available on Android SDK < 8, but we require 9+
199 // anyway.
200 MOZ_ASSERT(mSDKVersion >= 8);
201 jni::String::LocalRef hardware = java::sdk::Build::HARDWARE();
202 mHardware = hardware->ToString();
203 mAdapterDescription.AppendPrintf(
204 ", Hardware: %s", NS_LossyConvertUTF16toASCII(mHardware).get());
206 jni::String::LocalRef release = java::sdk::Build::VERSION::RELEASE();
207 mOSVersion = release->ToCString();
209 mOSVersionInteger = 0;
210 char a[5], b[5], c[5], d[5];
211 SplitDriverVersion(mOSVersion.get(), a, b, c, d);
212 uint8_t na = atoi(a);
213 uint8_t nb = atoi(b);
214 uint8_t nc = atoi(c);
215 uint8_t nd = atoi(d);
217 mOSVersionInteger = (uint32_t(na) << 24) | (uint32_t(nb) << 16) |
218 (uint32_t(nc) << 8) | uint32_t(nd);
220 mAdapterDescription.AppendPrintf(
221 ", OpenGL: %s -- %s -- %s", mGLStrings->Vendor().get(),
222 mGLStrings->Renderer().get(), mGLStrings->Version().get());
224 AddCrashReportAnnotations();
225 mInitialized = true;
228 NS_IMETHODIMP
229 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
230 EnsureInitialized();
231 aAdapterDescription = NS_ConvertASCIItoUTF16(mAdapterDescription);
232 return NS_OK;
235 NS_IMETHODIMP
236 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
237 EnsureInitialized();
238 return NS_ERROR_FAILURE;
241 NS_IMETHODIMP
242 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
243 EnsureInitialized();
244 *aAdapterRAM = 0;
245 return NS_OK;
248 NS_IMETHODIMP
249 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
250 EnsureInitialized();
251 return NS_ERROR_FAILURE;
254 NS_IMETHODIMP
255 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
256 EnsureInitialized();
257 aAdapterDriver.Truncate();
258 return NS_OK;
261 NS_IMETHODIMP
262 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
263 EnsureInitialized();
264 return NS_ERROR_FAILURE;
267 NS_IMETHODIMP
268 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
269 EnsureInitialized();
270 aAdapterDriverVendor.Truncate();
271 return NS_OK;
274 NS_IMETHODIMP
275 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
276 EnsureInitialized();
277 return NS_ERROR_FAILURE;
280 NS_IMETHODIMP
281 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
282 EnsureInitialized();
283 aAdapterDriverVersion = NS_ConvertASCIItoUTF16(mGLStrings->Version());
284 return NS_OK;
287 NS_IMETHODIMP
288 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
289 EnsureInitialized();
290 return NS_ERROR_FAILURE;
293 NS_IMETHODIMP
294 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
295 EnsureInitialized();
296 aAdapterDriverDate.Truncate();
297 return NS_OK;
300 NS_IMETHODIMP
301 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
302 EnsureInitialized();
303 return NS_ERROR_FAILURE;
306 NS_IMETHODIMP
307 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
308 EnsureInitialized();
309 aAdapterVendorID = NS_ConvertASCIItoUTF16(mGLStrings->Vendor());
310 return NS_OK;
313 NS_IMETHODIMP
314 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
315 EnsureInitialized();
316 return NS_ERROR_FAILURE;
319 NS_IMETHODIMP
320 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
321 EnsureInitialized();
322 aAdapterDeviceID = NS_ConvertASCIItoUTF16(mGLStrings->Renderer());
323 return NS_OK;
326 NS_IMETHODIMP
327 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
328 EnsureInitialized();
329 return NS_ERROR_FAILURE;
332 NS_IMETHODIMP
333 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
334 EnsureInitialized();
335 return NS_ERROR_FAILURE;
338 NS_IMETHODIMP
339 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
340 EnsureInitialized();
341 return NS_ERROR_FAILURE;
344 NS_IMETHODIMP
345 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) {
346 EnsureInitialized();
347 return NS_ERROR_FAILURE;
350 NS_IMETHODIMP
351 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
352 return NS_ERROR_NOT_IMPLEMENTED;
355 void GfxInfo::AddCrashReportAnnotations() {
356 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
357 mGLStrings->Vendor());
358 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
359 mGLStrings->Renderer());
360 CrashReporter::AnnotateCrashReport(
361 CrashReporter::Annotation::AdapterDriverVersion, mGLStrings->Version());
364 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
365 if (sDriverInfo->IsEmpty()) {
366 APPEND_TO_DRIVER_BLOCKLIST2(
367 OperatingSystem::Android, DeviceFamily::All,
368 nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK,
369 DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions,
370 "FEATURE_OK_FORCE_OPENGL");
373 return *sDriverInfo;
376 nsresult GfxInfo::GetFeatureStatusImpl(
377 int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
378 const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
379 OperatingSystem* aOS /* = nullptr */) {
380 NS_ENSURE_ARG_POINTER(aStatus);
381 aSuggestedDriverVersion.SetIsVoid(true);
382 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
383 OperatingSystem os = OperatingSystem::Android;
384 if (aOS) *aOS = os;
386 if (sShutdownOccurred) {
387 return NS_OK;
390 // OpenGL layers are never blocklisted on Android.
391 // This early return is so we avoid potentially slow
392 // GLStrings initialization on startup when we initialize GL layers.
393 if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS) {
394 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
395 return NS_OK;
398 EnsureInitialized();
400 if (mGLStrings->Vendor().IsEmpty() || mGLStrings->Renderer().IsEmpty()) {
401 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
402 return NS_OK;
405 // Don't evaluate special cases when evaluating the downloaded blocklist.
406 if (aDriverInfo.IsEmpty()) {
407 if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
408 if (mSDKVersion < 11) {
409 // It's slower than software due to not having a compositing fast path
410 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
411 aFailureId = "FEATURE_FAILURE_CANVAS_2D_SDK";
412 } else if (mGLStrings->Renderer().Find("Vivante GC1000") != -1) {
413 // Blocklist Vivante GC1000. See bug 1248183.
414 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
415 aFailureId = "FEATURE_FAILED_CANVAS_2D_HW";
416 } else {
417 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
419 return NS_OK;
422 if (aFeature == FEATURE_WEBGL_OPENGL) {
423 if (mGLStrings->Renderer().Find("Adreno 200") != -1 ||
424 mGLStrings->Renderer().Find("Adreno 205") != -1) {
425 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
426 aFailureId = "FEATURE_FAILURE_ADRENO_20x";
427 return NS_OK;
430 if (mSDKVersion <= 17) {
431 if (mGLStrings->Renderer().Find("Adreno (TM) 3") != -1) {
432 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
433 aFailureId = "FEATURE_FAILURE_ADRENO_3xx";
435 return NS_OK;
438 if (mHardware.EqualsLiteral("ville")) {
439 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
440 aFailureId = "FEATURE_FAILURE_VILLE";
441 return NS_OK;
445 if (aFeature == FEATURE_STAGEFRIGHT) {
446 NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer);
447 NS_LossyConvertUTF16toASCII cModel(mModel);
448 NS_LossyConvertUTF16toASCII cHardware(mHardware);
450 if (cHardware.EqualsLiteral("antares") ||
451 cHardware.EqualsLiteral("harmony") ||
452 cHardware.EqualsLiteral("picasso") ||
453 cHardware.EqualsLiteral("picasso_e") ||
454 cHardware.EqualsLiteral("ventana") ||
455 cHardware.EqualsLiteral("rk30board")) {
456 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
457 aFailureId = "FEATURE_FAILURE_STAGE_HW";
458 return NS_OK;
461 if (CompareVersions(mOSVersion.get(), "4.1.0") < 0) {
462 // Whitelist:
463 // All Samsung ICS devices, except for:
464 // Samsung SGH-I717 (Bug 845729)
465 // Samsung SGH-I727 (Bug 845729)
466 // Samsung SGH-I757 (Bug 845729)
467 // All Galaxy nexus ICS devices
468 // Sony Xperia Ion (LT28) ICS devices
469 bool isWhitelisted =
470 cModel.Equals("LT28h", nsCaseInsensitiveCStringComparator) ||
471 cManufacturer.Equals("samsung",
472 nsCaseInsensitiveCStringComparator) ||
473 cModel.Equals(
474 "galaxy nexus",
475 nsCaseInsensitiveCStringComparator); // some Galaxy Nexus
476 // have
477 // manufacturer=amazon
479 if (cModel.LowerCaseFindASCII("sgh-i717") != -1 ||
480 cModel.LowerCaseFindASCII("sgh-i727") != -1 ||
481 cModel.LowerCaseFindASCII("sgh-i757") != -1) {
482 isWhitelisted = false;
485 if (!isWhitelisted) {
486 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
487 aFailureId = "FEATURE_FAILURE_4_1_HW";
488 return NS_OK;
490 } else if (CompareVersions(mOSVersion.get(), "4.2.0") < 0) {
491 // Whitelist:
492 // All JB phones except for those in blocklist below
493 // Blocklist:
494 // Samsung devices from bug 812881 and 853522.
495 // Motorola XT890 from bug 882342.
496 bool isBlocklisted = cModel.LowerCaseFindASCII("gt-p3100") != -1 ||
497 cModel.LowerCaseFindASCII("gt-p3110") != -1 ||
498 cModel.LowerCaseFindASCII("gt-p3113") != -1 ||
499 cModel.LowerCaseFindASCII("gt-p5100") != -1 ||
500 cModel.LowerCaseFindASCII("gt-p5110") != -1 ||
501 cModel.LowerCaseFindASCII("gt-p5113") != -1 ||
502 cModel.LowerCaseFindASCII("xt890") != -1;
504 if (isBlocklisted) {
505 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
506 aFailureId = "FEATURE_FAILURE_4_2_HW";
507 return NS_OK;
509 } else if (CompareVersions(mOSVersion.get(), "4.3.0") < 0) {
510 // Blocklist all Sony devices
511 if (cManufacturer.LowerCaseFindASCII("sony") != -1) {
512 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
513 aFailureId = "FEATURE_FAILURE_4_3_SONY";
514 return NS_OK;
519 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) {
520 if (jni::IsAvailable()) {
521 *aStatus = WebRtcHwVp8EncodeSupported();
522 aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE";
523 return NS_OK;
526 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) {
527 if (jni::IsAvailable()) {
528 *aStatus = WebRtcHwVp8DecodeSupported();
529 aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE";
530 return NS_OK;
533 if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_H264) {
534 if (jni::IsAvailable()) {
535 *aStatus = WebRtcHwH264Supported();
536 aFailureId = "FEATURE_FAILURE_WEBRTC_H264";
537 return NS_OK;
540 if (aFeature == FEATURE_VP8_HW_DECODE ||
541 aFeature == FEATURE_VP9_HW_DECODE) {
542 NS_LossyConvertUTF16toASCII model(mModel);
543 bool isBlocked =
544 // GIFV crash, see bug 1232911.
545 model.Equals("GT-N8013", nsCaseInsensitiveCStringComparator);
547 if (isBlocked) {
548 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
549 aFailureId = "FEATURE_FAILURE_VPx";
550 } else {
551 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
553 return NS_OK;
556 if (aFeature == FEATURE_WEBRENDER) {
557 const bool isMali4xx =
558 mGLStrings->Renderer().LowerCaseFindASCII("mali-4") >= 0;
560 const bool isPowerVrG6110 =
561 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6110") >= 0;
563 const bool isVivanteGC7000UL =
564 mGLStrings->Renderer().LowerCaseFindASCII("vivante gc7000ul") >= 0;
566 const bool isPowerVrFenceSyncCrash =
567 (mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6200") >=
568 0 ||
569 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue g6430") >=
570 0 ||
571 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue gx6250") >=
572 0) &&
573 (mGLStrings->Version().Find("3283119") >= 0 ||
574 mGLStrings->Version().Find("3443629") >= 0 ||
575 mGLStrings->Version().Find("3573678") >= 0 ||
576 mGLStrings->Version().Find("3830101") >= 0);
578 if (isMali4xx) {
579 // Mali 4xx does not support GLES 3.
580 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
581 aFailureId = "FEATURE_FAILURE_NO_GLES_3";
582 } else if (isPowerVrG6110) {
583 // Blocked on PowerVR Rogue G6110 due to bug 1742986 and bug 1717863.
584 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
585 aFailureId = "FEATURE_FAILURE_POWERVR_G6110";
586 } else if (isVivanteGC7000UL) {
587 // Blocked on Vivante GC7000UL due to bug 1719327.
588 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
589 aFailureId = "FEATURE_FAILURE_VIVANTE_GC7000UL";
590 } else if (isPowerVrFenceSyncCrash) {
591 // Blocked on various PowerVR GPUs due to bug 1773128.
592 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
593 aFailureId = "FEATURE_FAILURE_POWERVR_FENCE_SYNC_CRASH";
594 } else {
595 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
597 return NS_OK;
600 if (aFeature == FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS) {
601 // Emulator with SwiftShader is buggy when attempting to clear picture
602 // cache textures with a scissor rect set.
603 const bool isEmulatorSwiftShader =
604 mGLStrings->Renderer().Find(
605 "Android Emulator OpenGL ES Translator (Google SwiftShader)") >=
607 if (isEmulatorSwiftShader) {
608 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
609 aFailureId = "FEATURE_FAILURE_BUG_1603515";
610 } else {
611 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
613 return NS_OK;
616 if (aFeature == FEATURE_WEBRENDER_SHADER_CACHE) {
617 // Program binaries are known to be buggy on Adreno 3xx. While we haven't
618 // encountered any correctness or stability issues with them, loading them
619 // fails more often than not, so is a waste of time. Better to just not
620 // even attempt to cache them. See bug 1615574.
621 const bool isAdreno3xx =
622 mGLStrings->Renderer().LowerCaseFindASCII("adreno (tm) 3") >= 0;
623 if (isAdreno3xx) {
624 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
625 aFailureId = "FEATURE_FAILURE_ADRENO_3XX";
626 } else {
627 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
631 if (aFeature == FEATURE_WEBRENDER_OPTIMIZED_SHADERS) {
632 // Optimized shaders result in completely broken rendering on some Mali-T
633 // devices. We have seen this on T6xx, T7xx, and T8xx on android versions
634 // up to 5.1, and on T6xx on versions up to android 7.1. As a precaution
635 // disable for all Mali-T regardless of version. See bug 1689064 and bug
636 // 1707283 for details.
637 const bool isMaliT =
638 mGLStrings->Renderer().LowerCaseFindASCII("mali-t") >= 0;
639 if (isMaliT) {
640 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
641 aFailureId = "FEATURE_FAILURE_BUG_1689064";
642 } else {
643 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
645 return NS_OK;
648 if (aFeature == FEATURE_WEBRENDER_PARTIAL_PRESENT) {
649 // Block partial present on some devices due to rendering issues.
650 // On Mali-Txxx due to bug 1680087 and bug 1707815.
651 // On Adreno 3xx GPUs due to bug 1695771.
652 const bool isMaliT =
653 mGLStrings->Renderer().LowerCaseFindASCII("mali-t") >= 0;
654 const bool isAdreno3xx =
655 mGLStrings->Renderer().LowerCaseFindASCII("adreno (tm) 3") >= 0;
656 if (isMaliT || isAdreno3xx) {
657 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
658 aFailureId = "FEATURE_FAILURE_BUG_1680087_1695771_1707815";
659 } else {
660 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
662 return NS_OK;
666 if (aFeature == FEATURE_GL_SWIZZLE) {
667 // Swizzling appears to be buggy on PowerVR Rogue devices with webrender.
668 // See bug 1704783.
669 const bool isPowerVRRogue =
670 mGLStrings->Renderer().LowerCaseFindASCII("powervr rogue") >= 0;
671 if (isPowerVRRogue) {
672 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
673 aFailureId = "FEATURE_FAILURE_POWERVR_ROGUE";
674 } else {
675 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
677 return NS_OK;
680 return GfxInfoBase::GetFeatureStatusImpl(
681 aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
684 static nsCString FeatureCacheOsVerPrefName(int32_t aFeature) {
685 nsCString osPrefName;
686 osPrefName.AppendASCII("gfxinfo.cache.");
687 osPrefName.AppendInt(aFeature);
688 osPrefName.AppendASCII(".osver");
689 return osPrefName;
692 static nsCString FeatureCacheAppVerPrefName(int32_t aFeature) {
693 nsCString osPrefName;
694 osPrefName.AppendASCII("gfxinfo.cache.");
695 osPrefName.AppendInt(aFeature);
696 osPrefName.AppendASCII(".appver");
697 return osPrefName;
700 static nsCString FeatureCacheValuePrefName(int32_t aFeature) {
701 nsCString osPrefName;
702 osPrefName.AppendASCII("gfxinfo.cache.");
703 osPrefName.AppendInt(aFeature);
704 osPrefName.AppendASCII(".value");
705 return osPrefName;
708 static bool GetCachedFeatureVal(int32_t aFeature, uint32_t aExpectedOsVer,
709 const nsCString& aCurrentAppVer,
710 int32_t& aOutStatus) {
711 uint32_t osVer = 0;
712 nsresult rv =
713 Preferences::GetUint(FeatureCacheOsVerPrefName(aFeature).get(), &osVer);
714 if (NS_FAILED(rv) || osVer != aExpectedOsVer) {
715 return false;
717 // Bug 1804287 requires we invalidate cached values for new builds to allow
718 // for code changes to modify the features support.
719 nsAutoCString cachedAppVersion;
720 rv = Preferences::GetCString(FeatureCacheAppVerPrefName(aFeature).get(),
721 cachedAppVersion);
722 if (NS_FAILED(rv) || !aCurrentAppVer.Equals(cachedAppVersion)) {
723 return false;
725 int32_t status = 0;
726 rv = Preferences::GetInt(FeatureCacheValuePrefName(aFeature).get(), &status);
727 if (NS_FAILED(rv)) {
728 return false;
730 aOutStatus = status;
731 return true;
734 static void SetCachedFeatureVal(int32_t aFeature, uint32_t aOsVer,
735 const nsCString& aCurrentAppVer,
736 int32_t aStatus) {
737 // Ignore failures; not much we can do anyway.
738 Preferences::SetUint(FeatureCacheOsVerPrefName(aFeature).get(), aOsVer);
739 Preferences::SetCString(FeatureCacheAppVerPrefName(aFeature).get(),
740 aCurrentAppVer);
741 Preferences::SetInt(FeatureCacheValuePrefName(aFeature).get(), aStatus);
744 int32_t GfxInfo::WebRtcHwVp8EncodeSupported() {
745 MOZ_ASSERT(jni::IsAvailable());
747 // The Android side of this calculation is very slow, so we cache the result
748 // in preferences, invalidating if the OS version changes.
750 int32_t status = 0;
751 const auto& currentAppVersion = GfxInfoBase::GetApplicationVersion();
752 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
753 mOSVersionInteger, currentAppVersion, status)) {
754 return status;
757 status = java::GeckoAppShell::HasHWVP8Encoder()
758 ? nsIGfxInfo::FEATURE_STATUS_OK
759 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
761 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, mOSVersionInteger,
762 currentAppVersion, status);
764 return status;
767 int32_t GfxInfo::WebRtcHwVp8DecodeSupported() {
768 MOZ_ASSERT(jni::IsAvailable());
770 // The Android side of this caclulation is very slow, so we cache the result
771 // in preferences, invalidating if the OS version changes.
773 int32_t status = 0;
774 const auto& appVersion = GfxInfoBase::GetApplicationVersion();
775 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
776 mOSVersionInteger, appVersion, status)) {
777 return status;
780 status = java::GeckoAppShell::HasHWVP8Decoder()
781 ? nsIGfxInfo::FEATURE_STATUS_OK
782 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
784 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, mOSVersionInteger,
785 appVersion, status);
787 return status;
790 int32_t GfxInfo::WebRtcHwH264Supported() {
791 MOZ_ASSERT(jni::IsAvailable());
793 // The Android side of this calculation is very slow, so we cache the result
794 // in preferences, invalidating if the OS version changes.
796 int32_t status = 0;
797 const auto& currentAppVersion = GfxInfoBase::GetApplicationVersion();
798 if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264,
799 mOSVersionInteger, currentAppVersion, status)) {
800 return status;
803 status = java::HardwareCodecCapabilityUtils::HasHWH264()
804 ? nsIGfxInfo::FEATURE_STATUS_OK
805 : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
807 SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264, mOSVersionInteger,
808 currentAppVersion, status);
810 return status;
813 #ifdef DEBUG
815 // Implement nsIGfxInfoDebug
817 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
818 mGLStrings->SpoofVendor(NS_LossyConvertUTF16toASCII(aVendorID));
819 return NS_OK;
822 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
823 mGLStrings->SpoofRenderer(NS_LossyConvertUTF16toASCII(aDeviceID));
824 return NS_OK;
827 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
828 mGLStrings->SpoofVersion(NS_LossyConvertUTF16toASCII(aDriverVersion));
829 return NS_OK;
832 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
833 EnsureInitialized();
834 mOSVersion = aVersion;
835 return NS_OK;
838 NS_IMETHODIMP GfxInfo::FireTestProcess() { return NS_OK; }
840 #endif
842 nsString GfxInfo::Model() {
843 EnsureInitialized();
844 return mModel;
847 nsString GfxInfo::Hardware() {
848 EnsureInitialized();
849 return mHardware;
852 nsString GfxInfo::Product() {
853 EnsureInitialized();
854 return mProduct;
857 nsString GfxInfo::Manufacturer() {
858 EnsureInitialized();
859 return mManufacturer;
862 uint32_t GfxInfo::OperatingSystemVersion() {
863 EnsureInitialized();
864 return mOSVersionInteger;
867 } // namespace widget
868 } // namespace mozilla