From 54ffe8cacaca6a42ea2a27686b1248ff60ba4353 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 16 May 2019 22:42:00 +0000 Subject: [PATCH] Bug 1551890 - Cache GFXInfo WebRTC HW encode/decode result on Android. r=snorp Profiling shows that we're spending a lot of time on startup inside android.media.MediaCodecList.getCodecCount when GfxInfo::GetFeatureStatus calls over to Java to determine whether hardware accelerated video encoding is supported. Looking at the Java stacks in the profile, Android is spending most of our time creating a list of codecs. It doesn't look like there's a faster way to query for hardware accelerated video support. So to speed this up we can cache the value in the user's profile. We also store the OS version, which we can use to detect when the OS is updated so we can invalidate the cache then. Presumably an OS update is the only way a device can have its hardware acceleration support status change. With this change, the time we take figuring out the HW encode/decode status goes from ~100ms on a cold run to ~0.01ms on a cache hit on my HD8 tablet. Differential Revision: https://phabricator.services.mozilla.com/D31380 --HG-- extra : moz-landing-system : lando --- widget/android/GfxInfo.cpp | 93 +++++++++++++++++++++++++++++++++++--- widget/android/GfxInfo.h | 2 + 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index cb3731554cd1..68a75a55cc83 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -16,6 +16,8 @@ #include "nsIWindowWatcher.h" #include "nsServiceManagerUtils.h" +#include "mozilla/Preferences.h" + #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" namespace mozilla { @@ -484,18 +486,14 @@ nsresult GfxInfo::GetFeatureStatusImpl( if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) { if (mozilla::AndroidBridge::Bridge()) { - *aStatus = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability() - ? nsIGfxInfo::FEATURE_STATUS_OK - : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + *aStatus = WebRtcHwEncodeSupported(); aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE"; return NS_OK; } } if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) { if (mozilla::AndroidBridge::Bridge()) { - *aStatus = mozilla::AndroidBridge::Bridge()->GetHWDecoderCapability() - ? nsIGfxInfo::FEATURE_STATUS_OK - : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + *aStatus = WebRtcHwDecodeSupported(); aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE"; return NS_OK; } @@ -522,6 +520,89 @@ nsresult GfxInfo::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::WebRtcHwEncodeSupported() { + 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_ENCODE, + mOSVersionInteger, status)) { + return status; + } + + status = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability() + ? nsIGfxInfo::FEATURE_STATUS_OK + : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + + SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, mOSVersionInteger, + status); + + return status; +} + +int32_t GfxInfo::WebRtcHwDecodeSupported() { + 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()->GetHWDecoderCapability() + ? nsIGfxInfo::FEATURE_STATUS_OK + : nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + + SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, mOSVersionInteger, + status); + + return status; +} #ifdef DEBUG // Implement nsIGfxInfoDebug diff --git a/widget/android/GfxInfo.h b/widget/android/GfxInfo.h index 2d6f26a6e0ad..6566823308cd 100644 --- a/widget/android/GfxInfo.h +++ b/widget/android/GfxInfo.h @@ -77,6 +77,8 @@ class GfxInfo : public GfxInfoBase { private: void AddCrashReportAnnotations(); + int32_t WebRtcHwEncodeSupported(); + int32_t WebRtcHwDecodeSupported(); bool mInitialized;