diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /widget/android/GfxInfo.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/android/GfxInfo.cpp')
-rw-r--r-- | widget/android/GfxInfo.cpp | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp new file mode 100644 index 0000000000..981c2c1741 --- /dev/null +++ b/widget/android/GfxInfo.cpp @@ -0,0 +1,800 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GfxInfo.h" +#include "GLContext.h" +#include "GLContextProvider.h" +#include "nsUnicharUtils.h" +#include "prenv.h" +#include "nsExceptionHandler.h" +#include "nsHashKeys.h" +#include "nsVersionComparator.h" +#include "AndroidBridge.h" +#include "nsServiceManagerUtils.h" + +#include "mozilla/Preferences.h" + +#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" + +namespace mozilla { +namespace widget { + +class GfxInfo::GLStrings { + nsCString mVendor; + nsCString mRenderer; + nsCString mVersion; + bool mReady; + + public: + GLStrings() : mReady(false) {} + + const nsCString& Vendor() { + EnsureInitialized(); + return mVendor; + } + + // This spoofed value wins, even if the environment variable + // MOZ_GFX_SPOOF_GL_VENDOR was set. + void SpoofVendor(const nsCString& s) { mVendor = s; } + + const nsCString& Renderer() { + EnsureInitialized(); + return mRenderer; + } + + // This spoofed value wins, even if the environment variable + // MOZ_GFX_SPOOF_GL_RENDERER was set. + void SpoofRenderer(const nsCString& s) { mRenderer = s; } + + const nsCString& Version() { + EnsureInitialized(); + return mVersion; + } + + // This spoofed value wins, even if the environment variable + // MOZ_GFX_SPOOF_GL_VERSION was set. + void SpoofVersion(const nsCString& s) { mVersion = s; } + + void EnsureInitialized() { + if (mReady) { + return; + } + + RefPtr<gl::GLContext> gl; + nsCString discardFailureId; + gl = gl::GLContextProvider::CreateHeadless( + {gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE}, &discardFailureId); + + if (!gl) { + // Setting mReady to true here means that we won't retry. Everything will + // remain blocklisted forever. Ideally, we would like to update that once + // any GLContext is successfully created, like the compositor's GLContext. + mReady = true; + return; + } + + gl->MakeCurrent(); + + if (mVendor.IsEmpty()) { + const char* spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR"); + if (spoofedVendor) { + mVendor.Assign(spoofedVendor); + } else { + mVendor.Assign((const char*)gl->fGetString(LOCAL_GL_VENDOR)); + } + } + + if (mRenderer.IsEmpty()) { + const char* spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER"); + if (spoofedRenderer) { + mRenderer.Assign(spoofedRenderer); + } else { + mRenderer.Assign((const char*)gl->fGetString(LOCAL_GL_RENDERER)); + } + } + + if (mVersion.IsEmpty()) { + const char* spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION"); + if (spoofedVersion) { + mVersion.Assign(spoofedVersion); + } else { + mVersion.Assign((const char*)gl->fGetString(LOCAL_GL_VERSION)); + } + } + + mReady = true; + } +}; + +#ifdef DEBUG +NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) +#endif + +GfxInfo::GfxInfo() + : mInitialized(false), + mGLStrings(new GLStrings), + mOSVersionInteger(0), + mSDKVersion(0) {} + +GfxInfo::~GfxInfo() {} + +/* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after + * gfxPlatform initialization has occurred because they depend on it for + * information. (See bug 591561) */ +nsresult GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; } + +nsresult GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; } + +nsresult GfxInfo::GetHasBattery(bool* aHasBattery) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) { + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) { + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) { + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +void GfxInfo::EnsureInitialized() { + if (mInitialized) return; + + if (!mozilla::AndroidBridge::Bridge()) { + gfxWarning() << "AndroidBridge missing during initialization"; + return; + } + + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", + "MODEL", mModel)) { + mAdapterDescription.AppendPrintf("Model: %s", + NS_LossyConvertUTF16toASCII(mModel).get()); + } + + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( + "android/os/Build", "PRODUCT", mProduct)) { + mAdapterDescription.AppendPrintf( + ", Product: %s", NS_LossyConvertUTF16toASCII(mProduct).get()); + } + + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( + "android/os/Build", "MANUFACTURER", mManufacturer)) { + mAdapterDescription.AppendPrintf( + ", Manufacturer: %s", NS_LossyConvertUTF16toASCII(mManufacturer).get()); + } + + if (mozilla::AndroidBridge::Bridge()->GetStaticIntField( + "android/os/Build$VERSION", "SDK_INT", &mSDKVersion)) { + // the HARDWARE field isn't available on Android SDK < 8, but we require 9+ + // anyway. + MOZ_ASSERT(mSDKVersion >= 8); + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( + "android/os/Build", "HARDWARE", mHardware)) { + mAdapterDescription.AppendPrintf( + ", Hardware: %s", NS_LossyConvertUTF16toASCII(mHardware).get()); + } + } else { + mSDKVersion = 0; + } + + nsString release; + mozilla::AndroidBridge::Bridge()->GetStaticStringField( + "android/os/Build$VERSION", "RELEASE", release); + mOSVersion = NS_LossyConvertUTF16toASCII(release); + + mOSVersionInteger = 0; + char a[5], b[5], c[5], d[5]; + SplitDriverVersion(mOSVersion.get(), a, b, c, d); + uint8_t na = atoi(a); + uint8_t nb = atoi(b); + uint8_t nc = atoi(c); + uint8_t nd = atoi(d); + + mOSVersionInteger = (uint32_t(na) << 24) | (uint32_t(nb) << 16) | + (uint32_t(nc) << 8) | uint32_t(nd); + + mAdapterDescription.AppendPrintf( + ", OpenGL: %s -- %s -- %s", mGLStrings->Vendor().get(), + mGLStrings->Renderer().get(), mGLStrings->Version().get()); + + AddCrashReportAnnotations(); + + mScreenInfo.mScreenDimensions = + mozilla::AndroidBridge::Bridge()->getScreenSize(); + + mInitialized = true; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) { + EnsureInitialized(); + aAdapterDescription = NS_ConvertASCIItoUTF16(mAdapterDescription); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) { + EnsureInitialized(); + *aAdapterRAM = 0; + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) { + EnsureInitialized(); + aAdapterDriver.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) { + EnsureInitialized(); + aAdapterDriverVendor.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) { + EnsureInitialized(); + aAdapterDriverVersion = NS_ConvertASCIItoUTF16(mGLStrings->Version()); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) { + EnsureInitialized(); + aAdapterDriverDate.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) { + EnsureInitialized(); + aAdapterVendorID = NS_ConvertASCIItoUTF16(mGLStrings->Vendor()); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) { + EnsureInitialized(); + aAdapterDeviceID = NS_ConvertASCIItoUTF16(mGLStrings->Renderer()); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { + EnsureInitialized(); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GfxInfo::GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) { + EnsureInitialized(); + nsString displayInfo; + displayInfo.AppendPrintf("%dx%d", + (int32_t)mScreenInfo.mScreenDimensions.width, + (int32_t)mScreenInfo.mScreenDimensions.height); + aDisplayInfo.AppendElement(displayInfo); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) { + aDisplayWidth.AppendElement((uint32_t)mScreenInfo.mScreenDimensions.width); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) { + aDisplayHeight.AppendElement((uint32_t)mScreenInfo.mScreenDimensions.height); + return NS_OK; +} + +NS_IMETHODIMP +GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +void GfxInfo::AddCrashReportAnnotations() { + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, + mGLStrings->Vendor()); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, + mGLStrings->Renderer()); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::AdapterDriverVersion, mGLStrings->Version()); +} + +const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() { + if (sDriverInfo->IsEmpty()) { + APPEND_TO_DRIVER_BLOCKLIST2( + OperatingSystem::Android, DeviceFamily::All, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK, + DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions, + "FEATURE_OK_FORCE_OPENGL"); + } + + return *sDriverInfo; +} + +nsresult GfxInfo::GetFeatureStatusImpl( + int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion, + const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId, + OperatingSystem* aOS /* = nullptr */) { + NS_ENSURE_ARG_POINTER(aStatus); + aSuggestedDriverVersion.SetIsVoid(true); + *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + OperatingSystem os = mOS; + if (aOS) *aOS = os; + + if (sShutdownOccurred) { + return NS_OK; + } + + // OpenGL layers are never blocklisted on Android. + // This early return is so we avoid potentially slow + // GLStrings initialization on startup when we initialize GL layers. + if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS) { + *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; + return NS_OK; + } + + EnsureInitialized(); + + if (mGLStrings->Vendor().IsEmpty() || mGLStrings->Renderer().IsEmpty()) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + return NS_OK; + } + + // Don't evaluate special cases when evaluating the downloaded blocklist. + if (aDriverInfo.IsEmpty()) { + if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) { + if (mSDKVersion < 11) { + // It's slower than software due to not having a compositing fast path + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION; + aFailureId = "FEATURE_FAILURE_CANVAS_2D_SDK"; + } else if (mGLStrings->Renderer().Find("Vivante GC1000") != -1) { + // Blocklist Vivante GC1000. See bug 1248183. + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILED_CANVAS_2D_HW"; + } else { + *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; + } + return NS_OK; + } + + if (aFeature == FEATURE_WEBGL_OPENGL) { + if (mGLStrings->Renderer().Find("Adreno 200") != -1 || + mGLStrings->Renderer().Find("Adreno 205") != -1) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_ADRENO_20x"; + return NS_OK; + } + + if (mSDKVersion <= 17) { + if (mGLStrings->Renderer().Find("Adreno (TM) 3") != -1) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_ADRENO_3xx"; + } + return NS_OK; + } + + if (mHardware.EqualsLiteral("ville")) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_VILLE"; + return NS_OK; + } + } + + if (aFeature == FEATURE_STAGEFRIGHT) { + NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer); + NS_LossyConvertUTF16toASCII cModel(mModel); + NS_LossyConvertUTF16toASCII cHardware(mHardware); + + if (cHardware.EqualsLiteral("antares") || + cHardware.EqualsLiteral("harmony") || + cHardware.EqualsLiteral("picasso") || + cHardware.EqualsLiteral("picasso_e") || + cHardware.EqualsLiteral("ventana") || + cHardware.EqualsLiteral("rk30board")) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_STAGE_HW"; + return NS_OK; + } + + if (CompareVersions(mOSVersion.get(), "4.1.0") < 0) { + // Whitelist: + // All Samsung ICS devices, except for: + // Samsung SGH-I717 (Bug 845729) + // Samsung SGH-I727 (Bug 845729) + // Samsung SGH-I757 (Bug 845729) + // All Galaxy nexus ICS devices + // Sony Xperia Ion (LT28) ICS devices + bool isWhitelisted = + cModel.Equals("LT28h", nsCaseInsensitiveCStringComparator) || + cManufacturer.Equals("samsung", + nsCaseInsensitiveCStringComparator) || + cModel.Equals( + "galaxy nexus", + nsCaseInsensitiveCStringComparator); // some Galaxy Nexus + // have + // manufacturer=amazon + + if (cModel.Find("SGH-I717", true) != -1 || + cModel.Find("SGH-I727", true) != -1 || + cModel.Find("SGH-I757", true) != -1) { + isWhitelisted = false; + } + + if (!isWhitelisted) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_4_1_HW"; + return NS_OK; + } + } else if (CompareVersions(mOSVersion.get(), "4.2.0") < 0) { + // Whitelist: + // All JB phones except for those in blocklist below + // Blocklist: + // Samsung devices from bug 812881 and 853522. + // Motorola XT890 from bug 882342. + bool isBlocklisted = cModel.Find("GT-P3100", true) != -1 || + cModel.Find("GT-P3110", true) != -1 || + cModel.Find("GT-P3113", true) != -1 || + cModel.Find("GT-P5100", true) != -1 || + cModel.Find("GT-P5110", true) != -1 || + cModel.Find("GT-P5113", true) != -1 || + cModel.Find("XT890", true) != -1; + + if (isBlocklisted) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_4_2_HW"; + return NS_OK; + } + } else if (CompareVersions(mOSVersion.get(), "4.3.0") < 0) { + // Blocklist all Sony devices + if (cManufacturer.Find("Sony", true) != -1) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_4_3_SONY"; + return NS_OK; + } + } + } + + if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) { + if (mozilla::AndroidBridge::Bridge()) { + *aStatus = WebRtcHwVp8EncodeSupported(); + aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE"; + return NS_OK; + } + } + if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) { + if (mozilla::AndroidBridge::Bridge()) { + *aStatus = WebRtcHwVp8DecodeSupported(); + aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE"; + return NS_OK; + } + } + if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_H264) { + if (mozilla::AndroidBridge::Bridge()) { + *aStatus = WebRtcHwH264Supported(); + aFailureId = "FEATURE_FAILURE_WEBRTC_H264"; + return NS_OK; + } + } + if (aFeature == FEATURE_VP8_HW_DECODE || + aFeature == FEATURE_VP9_HW_DECODE) { + NS_LossyConvertUTF16toASCII model(mModel); + bool isBlocked = + // GIFV crash, see bug 1232911. + model.Equals("GT-N8013", nsCaseInsensitiveCStringComparator); + + if (isBlocked) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_VPx"; + } else { + *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; + } + return NS_OK; + } + + if (aFeature == FEATURE_WEBRENDER) { + bool isUnblocked = false; + const nsCString& gpu = mGLStrings->Renderer(); + NS_LossyConvertUTF16toASCII model(mModel); + +#ifdef NIGHTLY_BUILD + // On Nightly enable Webrender on all Adreno 5xx GPUs + isUnblocked |= gpu.Find("Adreno (TM) 5", /*ignoreCase*/ true) >= 0; + + // On Nightly enable Webrender on all Mali-Txxx GPUs + isUnblocked |= gpu.Find("Mali-T", /*ignoreCase*/ true) >= 0; +#endif + // Enable Webrender on all Adreno 5xx GPUs, excluding 505 and 506. + isUnblocked |= + gpu.Find("Adreno (TM) 5", /*ignoreCase*/ true) >= 0 && + gpu.Find("Adreno (TM) 505", /*ignoreCase*/ true) == kNotFound && + gpu.Find("Adreno (TM) 506", /*ignoreCase*/ true) == kNotFound; + + // Enable Webrender on all Adreno 6xx devices + isUnblocked |= gpu.Find("Adreno (TM) 6", /*ignoreCase*/ true) >= 0; + + // Enable Webrender on all Mali-Gxx GPUs... + isUnblocked |= gpu.Find("Mali-G", /*ignoreCase*/ true) >= 0 && + // Excluding G72 and G76 on Android 11, due to + // bugs 1688705 and 1688017. + !(mSDKVersion == 30 && + (gpu.Find("Mali-G72", /*ignoreCase*/ true) >= 0 || + gpu.Find("Mali-G76", /*ignoreCase*/ true) >= 0)) && + // And excluding G31 due to bug 1689947. + gpu.Find("Mali-G31", /*ignoreCase*/ true) == kNotFound; + + if (!isUnblocked) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_WEBRENDER_BLOCKED_DEVICE"; + } else { + *aStatus = nsIGfxInfo::FEATURE_ALLOW_QUALIFIED; + } + return NS_OK; + } + + if (aFeature == FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS) { + // Emulator with SwiftShader is buggy when attempting to clear picture + // cache textures with a scissor rect set. + const bool isEmulatorSwiftShader = + mGLStrings->Renderer().Find( + "Android Emulator OpenGL ES Translator (Google SwiftShader)") >= + 0; + if (isEmulatorSwiftShader) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + aFailureId = "FEATURE_FAILURE_BUG_1603515"; + } else { + *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; + } + return NS_OK; + } + } + + return GfxInfoBase::GetFeatureStatusImpl( + aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os); +} + +static nsCString FeatureCacheOsVerPrefName(int32_t aFeature) { + nsCString osPrefName; + osPrefName.AppendASCII("gfxinfo.cache."); + osPrefName.AppendInt(aFeature); + osPrefName.AppendASCII(".osver"); + return osPrefName; +} + +static nsCString FeatureCacheValuePrefName(int32_t aFeature) { + nsCString osPrefName; + osPrefName.AppendASCII("gfxinfo.cache."); + osPrefName.AppendInt(aFeature); + osPrefName.AppendASCII(".value"); + return osPrefName; +} + +static bool GetCachedFeatureVal(int32_t aFeature, uint32_t aExpectedOsVer, + int32_t& aOutStatus) { + uint32_t osVer = 0; + nsresult rv = + Preferences::GetUint(FeatureCacheOsVerPrefName(aFeature).get(), &osVer); + if (NS_FAILED(rv) || osVer != aExpectedOsVer) { + return false; + } + int32_t status = 0; + rv = Preferences::GetInt(FeatureCacheValuePrefName(aFeature).get(), &status); + if (NS_FAILED(rv)) { + return false; + } + aOutStatus = status; + return true; +} + +static void SetCachedFeatureVal(int32_t aFeature, uint32_t aOsVer, + int32_t aStatus) { + // Ignore failures; not much we can do anyway. + Preferences::SetUint(FeatureCacheOsVerPrefName(aFeature).get(), aOsVer); + Preferences::SetInt(FeatureCacheValuePrefName(aFeature).get(), aStatus); +} + +int32_t GfxInfo::WebRtcHwVp8EncodeSupported() { + MOZ_ASSERT(mozilla::AndroidBridge::Bridge()); + + // The Android side of this calculation is very slow, so we cache the result + // in preferences, invalidating if the OS version changes. + + int32_t status = 0; + if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, + mOSVersionInteger, status)) { + return status; + } + + status = mozilla::AndroidBridge::Bridge()->HasHWVP8Encoder() + ? nsIGfxInfo::FEATURE_STATUS_OK + : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + + SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, mOSVersionInteger, + status); + + return status; +} + +int32_t GfxInfo::WebRtcHwVp8DecodeSupported() { + MOZ_ASSERT(mozilla::AndroidBridge::Bridge()); + + // The Android side of this caclulation is very slow, so we cache the result + // in preferences, invalidating if the OS version changes. + + int32_t status = 0; + if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, + mOSVersionInteger, status)) { + return status; + } + + status = mozilla::AndroidBridge::Bridge()->HasHWVP8Decoder() + ? nsIGfxInfo::FEATURE_STATUS_OK + : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + + SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, mOSVersionInteger, + status); + + return status; +} + +int32_t GfxInfo::WebRtcHwH264Supported() { + MOZ_ASSERT(mozilla::AndroidBridge::Bridge()); + + // The Android side of this calculation is very slow, so we cache the result + // in preferences, invalidating if the OS version changes. + + int32_t status = 0; + if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264, + mOSVersionInteger, status)) { + return status; + } + + status = mozilla::AndroidBridge::Bridge()->HasHWH264() + ? nsIGfxInfo::FEATURE_STATUS_OK + : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + + SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_H264, mOSVersionInteger, + status); + + return status; +} + +#ifdef DEBUG + +// Implement nsIGfxInfoDebug + +NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) { + mGLStrings->SpoofVendor(NS_LossyConvertUTF16toASCII(aVendorID)); + return NS_OK; +} + +NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) { + mGLStrings->SpoofRenderer(NS_LossyConvertUTF16toASCII(aDeviceID)); + return NS_OK; +} + +NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) { + mGLStrings->SpoofVersion(NS_LossyConvertUTF16toASCII(aDriverVersion)); + return NS_OK; +} + +NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) { + EnsureInitialized(); + mOSVersion = aVersion; + return NS_OK; +} + +NS_IMETHODIMP GfxInfo::FireTestProcess() { return NS_OK; } + +#endif + +nsString GfxInfo::Model() { + EnsureInitialized(); + return mModel; +} + +nsString GfxInfo::Hardware() { + EnsureInitialized(); + return mHardware; +} + +nsString GfxInfo::Product() { + EnsureInitialized(); + return mProduct; +} + +nsString GfxInfo::Manufacturer() { + EnsureInitialized(); + return mManufacturer; +} + +uint32_t GfxInfo::OperatingSystemVersion() { + EnsureInitialized(); + return mOSVersionInteger; +} + +} // namespace widget +} // namespace mozilla |