☠☠ backed out by 7a68ee30a574 ☠ ☠ | |
author | David Anderson <danderson@mozilla.com> |
Wed, 10 Jun 2015 21:59:03 -0700 | |
changeset 248243 | 606cb8f0882590c86e09a2186eeb41c9a1c6da43 |
parent 248242 | 2f26ece1e25f6ca5f9eecc5dda194e6188434321 |
child 248244 | 45cdca10d5cd53afc01d4ce33cca6639417219d2 |
push id | 28893 |
push user | kwierso@gmail.com |
push date | Fri, 12 Jun 2015 00:02:58 +0000 |
treeherder | autoland@8cf9d3e497f9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mattwoodrow |
bugs | 1168935 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/gfx/src/DriverInitCrashDetection.cpp @@ -0,0 +1,208 @@ +/* -*- 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 "DriverInitCrashDetection.h" +#include "gfxPrefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsString.h" +#include "nsXULAppAPI.h" +#include "mozilla/Preferences.h" +#include "mozilla/gfx/Logging.h" + +namespace mozilla { +namespace gfx { + +bool DriverInitCrashDetection::sDisableAcceleration = false; +bool DriverInitCrashDetection::sEnvironmentHasBeenUpdated = false; + +DriverInitCrashDetection::DriverInitCrashDetection() + : mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) +{ + // Only use the lockfile in the privileged process, which is responsible for + // the first driver initialization run. Child processes can't access the + // filesystme anyway. + if (mIsChromeProcess && !InitLockFilePath()) { + return; + } + + if (RecoverFromDriverInitCrash()) { + if (!sDisableAcceleration) { + // This is the first time we're checking for a crash recovery, so print + // a message and disable acceleration for anyone who asks for it. + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Recovered from graphics driver startup crash; acceleration disabled."; + sDisableAcceleration = true; + } + return; + } + + // If we previously disabled acceleration, we should have gone through + // RecoverFromDriverInitCrash(). + MOZ_ASSERT(!sDisableAcceleration); + + if (mIsChromeProcess && + (UpdateEnvironment() || sEnvironmentHasBeenUpdated)) + { + // Something in the environment changed, *or* a previous instance of this + // class already updated the environment. Allow a fresh attempt at driver + // acceleration. This doesn't mean the previous attempt failed, it just + // means we want to detect whether the new environment crashes. + AllowDriverInitAttempt(); + sEnvironmentHasBeenUpdated = true; + return; + } +} + +DriverInitCrashDetection::~DriverInitCrashDetection() +{ + if (mLockFile) { + mLockFile->Remove(false); + } + + if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Attempting)) { + // If we attempted to initialize the driver, and got this far without + // crashing, assume everything is okay. + gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Okay)); + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Successfully verified new graphics environment."; + } +} + +bool +DriverInitCrashDetection::InitLockFilePath() +{ + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mLockFile)); + if (!mLockFile) { + return false; + } + if (!NS_SUCCEEDED(mLockFile->AppendNative(NS_LITERAL_CSTRING("gfxinit.lock")))) { + return false; + } + return true; +} + +void +DriverInitCrashDetection::AllowDriverInitAttempt() +{ + // Create a temporary tombstone/lockfile. + FILE* fp; + if (!NS_SUCCEEDED(mLockFile->OpenANSIFileDesc("w", &fp))) { + return; + } + fclose(fp); + + gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Attempting)); + + // Flush preferences, so if we crash, we don't think the environment has changed again. + FlushPreferences(); +} + +bool +DriverInitCrashDetection::RecoverFromDriverInitCrash() +{ + bool exists; + if (mLockFile && + NS_SUCCEEDED(mLockFile->Exists(&exists)) && + exists) + { + // If we get here, we've just recovered from a crash. Disable acceleration + // until the environment changes. Since we may have crashed before + // preferences we're flushed, we cache the environment again, then flush + // preferences so child processes can start right away. + gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Recovered)); + UpdateEnvironment(); + FlushPreferences(); + return true; + } + if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)) { + // If we get here, we crashed in the current environment and have already + // disabled acceleration. + return true; + } + return false; +} + +bool +DriverInitCrashDetection::UpdateEnvironment() +{ + mGfxInfo = do_GetService("@mozilla.org/gfx/info;1"); + + bool changed = false; + if (mGfxInfo) { + nsString value; + + // Driver properties. + mGfxInfo->GetAdapterDriverVersion(value); + changed |= CheckAndUpdatePref("gfx.driver-init.driverVersion", value); + mGfxInfo->GetAdapterDeviceID(value); + changed |= CheckAndUpdatePref("gfx.driver-init.deviceID", value); + + // Feature status. +#if defined(XP_WIN) + bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() || + (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D)); + changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled); + + bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9(); + if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) { + d3d11Enabled = false; + } + changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled); +#endif + } + + // Firefox properties. + changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION)); + + // Finally, mark as changed if the status has been reset by the user. + changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None)); + + mGfxInfo = nullptr; + return changed; +} + +bool +DriverInitCrashDetection::FeatureEnabled(int aFeature) +{ + int32_t status; + if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) { + return false; + } + return status == nsIGfxInfo::FEATURE_STATUS_OK; +} + +bool +DriverInitCrashDetection::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue) +{ + bool oldValue; + if (NS_SUCCEEDED(Preferences::GetBool(aPrefName, &oldValue)) && + oldValue == aCurrentValue) + { + return false; + } + Preferences::SetBool(aPrefName, aCurrentValue); + return true; +} + +bool +DriverInitCrashDetection::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue) +{ + nsAdoptingString oldValue = Preferences::GetString(aPrefName); + if (oldValue == aCurrentValue) { + return false; + } + Preferences::SetString(aPrefName, aCurrentValue); + return true; +} + +void +DriverInitCrashDetection::FlushPreferences() +{ + if (nsIPrefService* prefService = Preferences::GetService()) { + prefService->SavePrefFile(nullptr); + } +} + +} // namespace gfx +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/gfx/src/DriverInitCrashDetection.h @@ -0,0 +1,65 @@ +/* -*- 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/. */ +#ifndef gfx_src_DriverInitCrashDetection_h__ +#define gfx_src_DriverInitCrashDetection_h__ + +#include "gfxCore.h" +#include "nsCOMPtr.h" +#include "nsIGfxInfo.h" +#include "nsIFile.h" + +namespace mozilla { +namespace gfx { + +enum class DriverInitStatus +{ + // Drivers have not been initialized yet. + None, + + // We're attempting to initialize drivers. + Attempting, + + // Drivers were successfully initialized last run. + Okay, + + // We crashed during driver initialization, and have restarted. + Recovered +}; + +class DriverInitCrashDetection +{ +public: + DriverInitCrashDetection(); + ~DriverInitCrashDetection(); + + bool DisableAcceleration() const { + return sDisableAcceleration; + } + +private: + bool InitLockFilePath(); + bool UpdateEnvironment(); + bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue); + bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue); + bool FeatureEnabled(int aFeature); + void AllowDriverInitAttempt(); + bool RecoverFromDriverInitCrash(); + void FlushPreferences(); + +private: + static bool sDisableAcceleration; + static bool sEnvironmentHasBeenUpdated; + +private: + bool mIsChromeProcess; + nsCOMPtr<nsIGfxInfo> mGfxInfo; + nsCOMPtr<nsIFile> mLockFile; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // gfx_src_DriverInitCrashDetection_h__ +
--- a/gfx/src/moz.build +++ b/gfx/src/moz.build @@ -6,17 +6,20 @@ XPIDL_SOURCES += [ 'nsIFontEnumerator.idl', 'nsIScriptableRegion.idl', ] XPIDL_MODULE = 'gfx' +DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION'] + EXPORTS += [ + 'DriverInitCrashDetection.h', 'FilterSupport.h', 'gfxCore.h', 'gfxCrashReporterUtils.h', 'nsBoundingMetrics.h', 'nsColor.h', 'nsColorNameList.h', 'nsColorNames.h', 'nsCoord.h', @@ -45,16 +48,17 @@ EXPORTS.mozilla.gfx += [ if CONFIG['MOZ_X11']: EXPORTS.mozilla += ['X11Util.h'] SOURCES += [ 'X11Util.cpp', ] UNIFIED_SOURCES += [ + 'DriverInitCrashDetection.cpp', 'FilterSupport.cpp', 'gfxCrashReporterUtils.cpp', 'nsColor.cpp', 'nsFont.cpp', 'nsFontMetrics.cpp', 'nsRect.cpp', 'nsRegion.cpp', 'nsRenderingContext.cpp',
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -221,16 +221,19 @@ private: DECL_GFX_PREF(Live, "gfx.color_management.mode", CMSMode, int32_t,-1); // The zero default here should match QCMS_INTENT_DEFAULT from qcms.h DECL_GFX_PREF(Live, "gfx.color_management.rendering_intent", CMSRenderingIntent, int32_t, 0); DECL_GFX_PREF(Once, "gfx.direct2d.disabled", Direct2DDisabled, bool, false); DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false); DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false); + // This should be set to values in the DriverInitStatus enumeration found in + // DriverInitCrashDetection.h. + DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0); DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false); DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456); // Note that "gfx.logging.level" is defined in Logging.h DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6); DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false); DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -73,16 +73,17 @@ #include "SurfaceCache.h" #include "gfxPrefs.h" #if defined(MOZ_CRASHREPORTER) #include "nsExceptionHandler.h" #endif #include "VsyncSource.h" +#include "DriverInitCrashDetection.h" using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; using namespace mozilla::widget; using namespace mozilla::image; DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget) @@ -647,16 +648,21 @@ gfxWindowsPlatform::CreateDevice(nsRefPt return device ? S_OK : hr; } #endif void gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) { #ifdef CAIRO_HAS_D2D_SURFACE + DriverInitCrashDetection detectCrashes; + if (detectCrashes.DisableAcceleration()) { + return; + } + if (mD2DDevice) { ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice); if (SUCCEEDED(device->GetDeviceRemovedReason())) { return; } mD2DDevice = nullptr; @@ -1859,17 +1865,18 @@ gfxWindowsPlatform::InitD3D11Devices() // blacklisted, then this function will abort if WARP is disabled, causing us // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use // a WARP device which should always be available on Windows 7 and higher. mD3D11DeviceInitialized = true; MOZ_ASSERT(!mD3D11Device); - if (InSafeMode()) { + DriverInitCrashDetection detectCrashes; + if (InSafeMode() || detectCrashes.DisableAcceleration()) { return; } bool useWARP = false; nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); if (gfxInfo) { int32_t status;