LCOV - code coverage report
Current view: top level - gfx/src - DriverCrashGuard.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 240 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : #include "DriverCrashGuard.h"
       6             : #include "gfxEnv.h"
       7             : #include "gfxPrefs.h"
       8             : #include "gfxConfig.h"
       9             : #include "nsAppDirectoryServiceDefs.h"
      10             : #include "nsDirectoryServiceUtils.h"
      11             : #ifdef MOZ_CRASHREPORTER
      12             : #include "nsExceptionHandler.h"
      13             : #endif
      14             : #include "nsServiceManagerUtils.h"
      15             : #include "nsString.h"
      16             : #include "nsXULAppAPI.h"
      17             : #include "mozilla/Preferences.h"
      18             : #include "mozilla/Telemetry.h"
      19             : #include "mozilla/Services.h"
      20             : #include "mozilla/gfx/Logging.h"
      21             : #include "mozilla/dom/ContentChild.h"
      22             : 
      23             : namespace mozilla {
      24             : namespace gfx {
      25             : 
      26             : static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES);
      27             : static const char* sCrashGuardNames[] = {
      28             :   "d3d11layers",
      29             :   "d3d9video",
      30             :   "glcontext",
      31             :   "d3d11video",
      32             : };
      33             : static_assert(MOZ_ARRAY_LENGTH(sCrashGuardNames) == NUM_CRASH_GUARD_TYPES,
      34             :               "CrashGuardType updated without a name string");
      35             : 
      36             : static inline void
      37           0 : BuildCrashGuardPrefName(CrashGuardType aType, nsCString& aOutPrefName)
      38             : {
      39           0 :   MOZ_ASSERT(aType < CrashGuardType::NUM_TYPES);
      40           0 :   MOZ_ASSERT(sCrashGuardNames[size_t(aType)]);
      41             : 
      42           0 :   aOutPrefName.Assign("gfx.crash-guard.status.");
      43           0 :   aOutPrefName.Append(sCrashGuardNames[size_t(aType)]);
      44           0 : }
      45             : 
      46           0 : DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent)
      47             :  : mType(aType)
      48           0 :  , mMode(aContentParent ? Mode::Proxy : Mode::Normal)
      49             :  , mInitialized(false)
      50             :  , mGuardActivated(false)
      51           0 :  , mCrashDetected(false)
      52             : {
      53           0 :   BuildCrashGuardPrefName(aType, mStatusPref);
      54           0 : }
      55             : 
      56             : void
      57           0 : DriverCrashGuard::InitializeIfNeeded()
      58             : {
      59           0 :   if (mInitialized) {
      60           0 :     return;
      61             :   }
      62             : 
      63           0 :   mInitialized = true;
      64           0 :   Initialize();
      65             : }
      66             : 
      67             : static inline bool
      68           0 : AreCrashGuardsEnabled()
      69             : {
      70             :   // Crash guard isn't supported in the GPU process since the entire
      71             :   // process is basically a crash guard.
      72           0 :   if (XRE_IsGPUProcess()) {
      73           0 :     return false;
      74             :   }
      75             : #ifdef NIGHTLY_BUILD
      76             :   // We only use the crash guard on non-nightly channels, since the nightly
      77             :   // channel is for development and having graphics features perma-disabled
      78             :   // is rather annoying.  Unless the user forces is with an environment
      79             :   // variable, which comes in handy for testing.
      80           0 :   return gfxEnv::ForceCrashGuardNightly();
      81             : #else
      82             :   // Check to see if all guards have been disabled through the environment.
      83             :   if (gfxEnv::DisableCrashGuard()) {
      84             :     return false;
      85             :   }
      86             :   return true;
      87             : #endif
      88             : }
      89             : 
      90             : void
      91           0 : DriverCrashGuard::Initialize()
      92             : {
      93           0 :   if (!AreCrashGuardsEnabled()) {
      94           0 :     return;
      95             :   }
      96             : 
      97             :   // Using DriverCrashGuard off the main thread currently does not work. Under
      98             :   // e10s it could conceivably work by dispatching the IPC calls via the main
      99             :   // thread. In the parent process this would be harder. For now, we simply
     100             :   // exit early instead.
     101           0 :   if (!NS_IsMainThread()) {
     102           0 :     return;
     103             :   }
     104             : 
     105           0 :   mGfxInfo = services::GetGfxInfo();
     106             : 
     107           0 :   if (XRE_IsContentProcess()) {
     108             :     // Ask the parent whether or not activating the guard is okay. The parent
     109             :     // won't bother if it detected a crash.
     110           0 :     dom::ContentChild* cc = dom::ContentChild::GetSingleton();
     111           0 :     cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected);
     112           0 :     if (mCrashDetected) {
     113           0 :       LogFeatureDisabled();
     114           0 :       return;
     115             :     }
     116             : 
     117           0 :     ActivateGuard();
     118           0 :     return;
     119             :   }
     120             : 
     121             :   // Always check whether or not the lock file exists. For example, we could
     122             :   // have crashed creating a D3D9 device in the parent process, and on restart
     123             :   // are now requesting one in the child process. We catch everything here.
     124           0 :   if (RecoverFromCrash()) {
     125           0 :     mCrashDetected = true;
     126           0 :     return;
     127             :   }
     128             : 
     129             :   // If the environment has changed, we always activate the guard. In the
     130             :   // parent process this performs main-thread disk I/O. Child process guards
     131             :   // only incur an IPC cost, so if we're proxying for a child process, we
     132             :   // play it safe and activate the guard as long as we don't expect it to
     133             :   // crash.
     134           0 :   if (CheckOrRefreshEnvironment() ||
     135           0 :       (mMode == Mode::Proxy && GetStatus() != DriverInitStatus::Crashed))
     136             :   {
     137           0 :     ActivateGuard();
     138           0 :     return;
     139             :   }
     140             : 
     141             :   // If we got here and our status is "crashed", then the environment has not
     142             :   // updated and we do not want to attempt to use the driver again.
     143           0 :   if (GetStatus() == DriverInitStatus::Crashed) {
     144           0 :     mCrashDetected = true;
     145           0 :     LogFeatureDisabled();
     146             :   }
     147             : }
     148             : 
     149           0 : DriverCrashGuard::~DriverCrashGuard()
     150             : {
     151           0 :   if (!mGuardActivated) {
     152           0 :     return;
     153             :   }
     154             : 
     155           0 :   if (XRE_IsParentProcess()) {
     156           0 :     if (mGuardFile) {
     157           0 :       mGuardFile->Remove(false);
     158             :     }
     159             : 
     160             :     // If during our initialization, no other process encountered a crash, we
     161             :     // proceed to mark the status as okay.
     162           0 :     if (GetStatus() != DriverInitStatus::Crashed) {
     163           0 :       SetStatus(DriverInitStatus::Okay);
     164             :     }
     165             :   } else {
     166           0 :     dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType));
     167             :   }
     168             : 
     169             : #ifdef MOZ_CRASHREPORTER
     170             :   // Remove the crash report annotation.
     171           0 :   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
     172           0 :                                      NS_LITERAL_CSTRING(""));
     173             : #endif
     174           0 : }
     175             : 
     176             : bool
     177           0 : DriverCrashGuard::Crashed()
     178             : {
     179           0 :   InitializeIfNeeded();
     180             : 
     181             :   // Note, we read mCrashDetected instead of GetStatus(), since in child
     182             :   // processes we're not guaranteed that the prefs have been synced in
     183             :   // time.
     184           0 :   return mCrashDetected;
     185             : }
     186             : 
     187             : nsCOMPtr<nsIFile>
     188           0 : DriverCrashGuard::GetGuardFile()
     189             : {
     190           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     191             : 
     192           0 :   nsCString filename;
     193           0 :   filename.Assign(sCrashGuardNames[size_t(mType)]);
     194           0 :   filename.Append(".guard");
     195             : 
     196           0 :   nsCOMPtr<nsIFile> file;
     197           0 :   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(file));
     198           0 :   if (!file) {
     199           0 :     return nullptr;
     200             :   }
     201           0 :   if (!NS_SUCCEEDED(file->AppendNative(filename))) {
     202           0 :     return nullptr;
     203             :   }
     204           0 :   return file;
     205             : }
     206             : 
     207             : void
     208           0 : DriverCrashGuard::ActivateGuard()
     209             : {
     210           0 :   mGuardActivated = true;
     211             : 
     212             : #ifdef MOZ_CRASHREPORTER
     213             :   // Anotate crash reports only if we're a real guard. Otherwise, we could
     214             :   // attribute a random parent process crash to a graphics problem in a child
     215             :   // process.
     216           0 :   if (mMode != Mode::Proxy) {
     217           0 :     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
     218           0 :                                        NS_LITERAL_CSTRING("1"));
     219             :   }
     220             : #endif
     221             : 
     222             :   // If we're in the content process, the rest of the guarding is handled
     223             :   // in the parent.
     224           0 :   if (XRE_IsContentProcess()) {
     225           0 :     return;
     226             :   }
     227             : 
     228           0 :   SetStatus(DriverInitStatus::Attempting);
     229             : 
     230           0 :   if (mMode != Mode::Proxy) {
     231             :     // In parent process guards, we use two tombstones to detect crashes: a
     232             :     // preferences and a zero-byte file on the filesystem.
     233           0 :     FlushPreferences();
     234             : 
     235             :     // Create a temporary tombstone/lockfile.
     236           0 :     FILE* fp = nullptr;
     237           0 :     mGuardFile = GetGuardFile();
     238           0 :     if (!mGuardFile || !NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) {
     239           0 :       return;
     240             :     }
     241           0 :     fclose(fp);
     242             :   }
     243             : }
     244             : 
     245             : void
     246           0 : DriverCrashGuard::NotifyCrashed()
     247             : {
     248           0 :   CheckOrRefreshEnvironment();
     249           0 :   SetStatus(DriverInitStatus::Crashed);
     250           0 :   FlushPreferences();
     251           0 :   LogCrashRecovery();
     252           0 : }
     253             : 
     254             : bool
     255           0 : DriverCrashGuard::RecoverFromCrash()
     256             : {
     257           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     258             : 
     259           0 :   nsCOMPtr<nsIFile> file = GetGuardFile();
     260             :   bool exists;
     261           0 :   if ((file &&
     262           0 :        NS_SUCCEEDED(file->Exists(&exists)) &&
     263           0 :        exists) ||
     264           0 :       (GetStatus() == DriverInitStatus::Attempting))
     265             :   {
     266             :     // If we get here, we've just recovered from a crash. Disable acceleration
     267             :     // until the environment changes.
     268           0 :     if (file) {
     269           0 :       file->Remove(false);
     270             :     }
     271           0 :     NotifyCrashed();
     272           0 :     return true;
     273             :   }
     274           0 :   return false;
     275             : }
     276             : 
     277             : // Return true if the caller should proceed to guard for crashes. False if
     278             : // the environment has not changed. We persist the "changed" status across
     279             : // calls, so that after an environment changes, all guards for the new
     280             : // session are activated rather than just the first.
     281             : bool
     282           0 : DriverCrashGuard::CheckOrRefreshEnvironment()
     283             : {
     284             :   // Our result can be cached statically since we don't check live prefs.
     285             :   static bool sBaseInfoChanged = false;
     286             :   static bool sBaseInfoChecked = false;
     287             : 
     288           0 :   if (!sBaseInfoChecked) {
     289             :     // None of the prefs we care about, so we cache the result statically.
     290           0 :     sBaseInfoChecked = true;
     291           0 :     sBaseInfoChanged = UpdateBaseEnvironment();
     292             :   }
     293             : 
     294             :   // Always update the full environment, even if the base info didn't change.
     295           0 :   return UpdateEnvironment() ||
     296           0 :          sBaseInfoChanged ||
     297           0 :          GetStatus() == DriverInitStatus::Unknown;
     298             : }
     299             : 
     300             : bool
     301           0 : DriverCrashGuard::UpdateBaseEnvironment()
     302             : {
     303           0 :   bool changed = false;
     304           0 :   if (mGfxInfo) {
     305           0 :     nsString value;
     306             : 
     307             :     // Driver properties.
     308           0 :     mGfxInfo->GetAdapterDriverVersion(value);
     309           0 :     changed |= CheckAndUpdatePref("driverVersion", value);
     310           0 :     mGfxInfo->GetAdapterDeviceID(value);
     311           0 :     changed |= CheckAndUpdatePref("deviceID", value);
     312             :   }
     313             : 
     314             :   // Firefox properties.
     315           0 :   changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
     316             : 
     317           0 :   return changed;
     318             : }
     319             : 
     320             : bool
     321           0 : DriverCrashGuard::FeatureEnabled(int aFeature, bool aDefault)
     322             : {
     323           0 :   if (!mGfxInfo) {
     324           0 :     return aDefault;
     325             :   }
     326             :   int32_t status;
     327           0 :   nsCString discardFailureId;
     328           0 :   if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, discardFailureId, &status))) {
     329           0 :     return false;
     330             :   }
     331           0 :   return status == nsIGfxInfo::FEATURE_STATUS_OK;
     332             : }
     333             : 
     334             : bool
     335           0 : DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
     336             : {
     337           0 :   std::string pref = GetFullPrefName(aPrefName);
     338             : 
     339             :   bool oldValue;
     340           0 :   if (NS_SUCCEEDED(Preferences::GetBool(pref.c_str(), &oldValue)) &&
     341           0 :       oldValue == aCurrentValue)
     342             :   {
     343           0 :     return false;
     344             :   }
     345           0 :   Preferences::SetBool(pref.c_str(), aCurrentValue);
     346           0 :   return true;
     347             : }
     348             : 
     349             : bool
     350           0 : DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
     351             : {
     352           0 :   std::string pref = GetFullPrefName(aPrefName);
     353             : 
     354           0 :   nsAdoptingString oldValue = Preferences::GetString(pref.c_str());
     355           0 :   if (oldValue == aCurrentValue) {
     356           0 :     return false;
     357             :   }
     358           0 :   Preferences::SetString(pref.c_str(), aCurrentValue);
     359           0 :   return true;
     360             : }
     361             : 
     362             : std::string
     363           0 : DriverCrashGuard::GetFullPrefName(const char* aPref)
     364             : {
     365           0 :   return std::string("gfx.crash-guard.") +
     366           0 :          std::string(sCrashGuardNames[uint32_t(mType)]) +
     367           0 :          std::string(".") +
     368           0 :          std::string(aPref);
     369             : }
     370             : 
     371             : DriverInitStatus
     372           0 : DriverCrashGuard::GetStatus() const
     373             : {
     374           0 :   return (DriverInitStatus)Preferences::GetInt(mStatusPref.get(), 0);
     375             : }
     376             : 
     377             : void
     378           0 : DriverCrashGuard::SetStatus(DriverInitStatus aStatus)
     379             : {
     380           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     381             : 
     382           0 :   Preferences::SetInt(mStatusPref.get(), int32_t(aStatus));
     383           0 : }
     384             : 
     385             : void
     386           0 : DriverCrashGuard::FlushPreferences()
     387             : {
     388           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     389             : 
     390           0 :   if (nsIPrefService* prefService = Preferences::GetService()) {
     391           0 :     static_cast<Preferences *>(prefService)->SavePrefFileBlocking();
     392             :   }
     393           0 : }
     394             : 
     395             : void
     396           0 : DriverCrashGuard::ForEachActiveCrashGuard(const CrashGuardCallback& aCallback)
     397             : {
     398           0 :   if (!AreCrashGuardsEnabled()) {
     399             :     // Even if guards look active (via prefs), they can be ignored if globally
     400             :     // disabled.
     401           0 :     return;
     402             :   }
     403             : 
     404           0 :   for (size_t i = 0; i < NUM_CRASH_GUARD_TYPES; i++) {
     405           0 :     CrashGuardType type = static_cast<CrashGuardType>(i);
     406             : 
     407           0 :     nsCString prefName;
     408           0 :     BuildCrashGuardPrefName(type, prefName);
     409             : 
     410             :     auto status =
     411           0 :       static_cast<DriverInitStatus>(Preferences::GetInt(prefName.get(), 0));
     412           0 :     if (status != DriverInitStatus::Crashed) {
     413           0 :       continue;
     414             :     }
     415             : 
     416           0 :     aCallback(sCrashGuardNames[i], prefName.get());
     417             :   }
     418             : }
     419             : 
     420           0 : D3D11LayersCrashGuard::D3D11LayersCrashGuard(dom::ContentParent* aContentParent)
     421           0 :  : DriverCrashGuard(CrashGuardType::D3D11Layers, aContentParent)
     422             : {
     423           0 : }
     424             : 
     425             : void
     426           0 : D3D11LayersCrashGuard::Initialize()
     427             : {
     428           0 :   if (!XRE_IsParentProcess()) {
     429             :     // We assume the parent process already performed crash detection for
     430             :     // graphics devices.
     431           0 :     return;
     432             :   }
     433             : 
     434           0 :   DriverCrashGuard::Initialize();
     435             : 
     436             :   // If no telemetry states have been recorded, this will set the state to okay.
     437             :   // Otherwise, it will have no effect.
     438           0 :   RecordTelemetry(TelemetryState::Okay);
     439             : }
     440             : 
     441             : bool
     442           0 : D3D11LayersCrashGuard::UpdateEnvironment()
     443             : {
     444             :   // Our result can be cached statically since we don't check live prefs.
     445             :   static bool checked = false;
     446             :   static bool changed = false;
     447             : 
     448           0 :   if (checked) {
     449           0 :     return changed;
     450             :   }
     451             : 
     452           0 :   checked = true;
     453             : 
     454             :   // Feature status.
     455             : #if defined(XP_WIN)
     456             :   bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
     457             :                     (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
     458             :   changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
     459             : 
     460             :   bool d3d11Enabled = gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING);
     461             :   changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
     462             : #endif
     463             : 
     464           0 :   if (!changed) {
     465           0 :     return false;
     466             :   }
     467             : 
     468           0 :   RecordTelemetry(TelemetryState::EnvironmentChanged);
     469           0 :   return true;
     470             : }
     471             : 
     472             : void
     473           0 : D3D11LayersCrashGuard::LogCrashRecovery()
     474             : {
     475           0 :   RecordTelemetry(TelemetryState::RecoveredFromCrash);
     476           0 :   gfxCriticalNote << "D3D11 layers just crashed; D3D11 will be disabled.";
     477           0 : }
     478             : 
     479             : void
     480           0 : D3D11LayersCrashGuard::LogFeatureDisabled()
     481             : {
     482           0 :   RecordTelemetry(TelemetryState::FeatureDisabled);
     483           0 :   gfxCriticalNote << "D3D11 layers disabled due to a prior crash.";
     484           0 : }
     485             : 
     486             : void
     487           0 : D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState)
     488             : {
     489             :   // D3D11LayersCrashGuard is a no-op in the child process.
     490           0 :   if (!XRE_IsParentProcess()) {
     491           0 :     return;
     492             :   }
     493             : 
     494             :   // Since we instantiate this class more than once, make sure we only record
     495             :   // the first state (since that is really all we care about).
     496             :   static bool sTelemetryStateRecorded = false;
     497           0 :   if (sTelemetryStateRecorded) {
     498           0 :     return;
     499             :   }
     500             : 
     501           0 :   Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
     502           0 :   sTelemetryStateRecorded = true;
     503             : }
     504             : 
     505           0 : D3D9VideoCrashGuard::D3D9VideoCrashGuard(dom::ContentParent* aContentParent)
     506           0 :  : DriverCrashGuard(CrashGuardType::D3D9Video, aContentParent)
     507             : {
     508           0 : }
     509             : 
     510             : bool
     511           0 : D3D9VideoCrashGuard::UpdateEnvironment()
     512             : {
     513             :   // We don't care about any extra preferences here.
     514           0 :   return false;
     515             : }
     516             : 
     517             : void
     518           0 : D3D9VideoCrashGuard::LogCrashRecovery()
     519             : {
     520           0 :   gfxCriticalNote << "DXVA2D3D9 just crashed; hardware video will be disabled.";
     521           0 : }
     522             : 
     523             : void
     524           0 : D3D9VideoCrashGuard::LogFeatureDisabled()
     525             : {
     526           0 :   gfxCriticalNote << "DXVA2D3D9 video decoding is disabled due to a previous crash.";
     527           0 : }
     528             : 
     529           0 : D3D11VideoCrashGuard::D3D11VideoCrashGuard(dom::ContentParent* aContentParent)
     530           0 :  : DriverCrashGuard(CrashGuardType::D3D11Video, aContentParent)
     531             : {
     532           0 : }
     533             : 
     534             : bool
     535           0 : D3D11VideoCrashGuard::UpdateEnvironment()
     536             : {
     537             :   // We don't care about any extra preferences here.
     538           0 :   return false;
     539             : }
     540             : 
     541             : void
     542           0 : D3D11VideoCrashGuard::LogCrashRecovery()
     543             : {
     544           0 :   gfxCriticalNote << "DXVA2D3D11 just crashed; hardware video will be disabled.";
     545           0 : }
     546             : 
     547             : void
     548           0 : D3D11VideoCrashGuard::LogFeatureDisabled()
     549             : {
     550           0 :   gfxCriticalNote << "DXVA2D3D11 video decoding is disabled due to a previous crash.";
     551           0 : }
     552             : 
     553           0 : GLContextCrashGuard::GLContextCrashGuard(dom::ContentParent* aContentParent)
     554           0 :  : DriverCrashGuard(CrashGuardType::GLContext, aContentParent)
     555             : {
     556           0 : }
     557             : 
     558             : void
     559           0 : GLContextCrashGuard::Initialize()
     560             : {
     561           0 :   if (XRE_IsContentProcess()) {
     562             :     // Disable the GL crash guard in content processes, since we're not going
     563             :     // to lose the entire browser and we don't want to hinder WebGL availability.
     564           0 :     return;
     565             :   }
     566             : 
     567             : #if defined(MOZ_WIDGET_ANDROID)
     568             :   // Disable the WebGL crash guard on Android - it doesn't use E10S, and
     569             :   // its drivers will essentially never change, so the crash guard could
     570             :   // permanently disable WebGL.
     571             :   return;
     572             : #endif
     573             : 
     574           0 :   DriverCrashGuard::Initialize();
     575             : }
     576             : 
     577             : bool
     578           0 : GLContextCrashGuard::UpdateEnvironment()
     579             : {
     580             :   static bool checked = false;
     581             :   static bool changed = false;
     582             : 
     583           0 :   if (checked) {
     584           0 :     return changed;
     585             :   }
     586             : 
     587           0 :   checked = true;
     588             : 
     589             : #if defined(XP_WIN)
     590             :   changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-d3d11",
     591             :                                     gfxPrefs::WebGLANGLEForceD3D11());
     592             :   changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-try-d3d11",
     593             :                                     gfxPrefs::WebGLANGLETryD3D11());
     594             :   changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-warp",
     595             :                                     gfxPrefs::WebGLANGLEForceWARP());
     596             :   changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle",
     597             :                                     FeatureEnabled(nsIGfxInfo::FEATURE_WEBGL_ANGLE, false));
     598             :   changed |= CheckAndUpdateBoolPref("gfx.driver-init.direct3d11-angle",
     599             :                                     FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, false));
     600             : #endif
     601             : 
     602           0 :   return changed;
     603             : }
     604             : 
     605             : void
     606           0 : GLContextCrashGuard::LogCrashRecovery()
     607             : {
     608           0 :   gfxCriticalNote << "GLContext just crashed.";
     609           0 : }
     610             : 
     611             : void
     612           0 : GLContextCrashGuard::LogFeatureDisabled()
     613             : {
     614           0 :   gfxCriticalNote << "GLContext remains enabled despite a previous crash.";
     615           0 : }
     616             : 
     617             : } // namespace gfx
     618             : } // namespace mozilla

Generated by: LCOV version 1.13