Add driver crash guards to WebGL (bug 1190281 part 9, r=jgilbert,mattwoodrow)
authorDavid Anderson <dvander@alliedmods.net>
Fri, 14 Aug 2015 22:14:00 -0700
changeset 257947 06300b68be6c0d92df32eb2f9be299f74f49cbfe
parent 257946 3a12957a6bd3166c3c0f6b5667264ddd040e6318
child 257948 ddc3a4689c889a7f98d271e5103b6b9ca9e674c2
push id29238
push userryanvm@gmail.com
push dateMon, 17 Aug 2015 13:06:57 +0000
treeherdermozilla-central@a6eeb28458fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, mattwoodrow
bugs1190281
milestone43.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
Add driver crash guards to WebGL (bug 1190281 part 9, r=jgilbert,mattwoodrow)
dom/ipc/ContentParent.cpp
gfx/gl/GLContext.cpp
gfx/src/DriverCrashGuard.cpp
gfx/src/DriverCrashGuard.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5191,16 +5191,19 @@ ContentParent::RecvBeginDriverCrashGuard
   UniquePtr<gfx::DriverCrashGuard> guard;
   switch (gfx::CrashGuardType(aGuardType)) {
     case gfx::CrashGuardType::D3D11Layers:
       guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
       break;
     case gfx::CrashGuardType::D3D9Video:
       guard = MakeUnique<gfx::D3D9VideoCrashGuard>(this);
       break;
+    case gfx::CrashGuardType::GLContext:
+      guard = MakeUnique<gfx::GLContextCrashGuard>(this);
+      break;
     default:
       MOZ_ASSERT_UNREACHABLE("unknown crash guard type");
       return false;
   }
 
   if (guard->Crashed()) {
     *aOutCrashed = true;
     return true;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -25,16 +25,17 @@
 #include "prenv.h"
 #include "prlink.h"
 #include "ScopedGLHelpers.h"
 #include "SharedSurfaceGL.h"
 #include "GfxTexturesReporter.h"
 #include "TextureGarbageBin.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
+#include "DriverCrashGuard.h"
 #include "mozilla/IntegerPrintfMacros.h"
 
 #include "OGLShaderProgram.h" // for ShaderProgramType
 
 #include "mozilla/DebugOnly.h"
 
 #ifdef XP_MACOSX
 #include <CoreServices/CoreServices.h>
@@ -363,16 +364,21 @@ GLContext::InitWithPrefix(const char *pr
 {
     ScopedGfxFeatureReporter reporter("GL Context");
 
     if (mInitialized) {
         reporter.SetSuccessful();
         return true;
     }
 
+    GLContextCrashGuard crashGuard;
+    if (crashGuard.Crashed()) {
+        return false;
+    }
+
     mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
 
     SymLoadStruct symbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
--- a/gfx/src/DriverCrashGuard.cpp
+++ b/gfx/src/DriverCrashGuard.cpp
@@ -20,16 +20,17 @@
 
 namespace mozilla {
 namespace gfx {
 
 static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES);
 static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = {
   "d3d11layers",
   "d3d9video",
+  "glcontext",
 };
 
 DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent)
  : mType(aType)
  , mMode(aContentParent ? Mode::Proxy : Mode::Normal)
  , mInitialized(false)
  , mGuardActivated(false)
  , mCrashDetected(false)
@@ -49,16 +50,26 @@ DriverCrashGuard::InitializeIfNeeded()
 
   mInitialized = true;
   Initialize();
 }
 
 void
 DriverCrashGuard::Initialize()
 {
+  // Using DriverCrashGuard off the main thread currently does not work. Under
+  // e10s it could conceivably work by dispatching the IPC calls via the main
+  // thread. In the parent process this would be harder. For now, we simply
+  // exit early instead.
+  if (!NS_IsMainThread()) {
+    return;
+  }
+
+  mGfxInfo = services::GetGfxInfo();
+
   if (XRE_IsContentProcess()) {
     // Ask the parent whether or not activating the guard is okay. The parent
     // won't bother if it detected a crash.
     dom::ContentChild* cc = dom::ContentChild::GetSingleton();
     cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected);
     if (mCrashDetected) {
       LogFeatureDisabled();
       return;
@@ -246,17 +257,16 @@ DriverCrashGuard::CheckOrRefreshEnvironm
          sBaseInfoChanged ||
          GetStatus() == DriverInitStatus::Unknown;
 }
 
 bool
 DriverCrashGuard::UpdateBaseEnvironment()
 {
   bool changed = false;
-  mGfxInfo = services::GetGfxInfo();
   if (mGfxInfo) {
     nsString value;
 
     // Driver properties.
     mGfxInfo->GetAdapterDriverVersion(value);
     changed |= CheckAndUpdatePref("driverVersion", value);
     mGfxInfo->GetAdapterDeviceID(value);
     changed |= CheckAndUpdatePref("deviceID", value);
@@ -264,18 +274,21 @@ DriverCrashGuard::UpdateBaseEnvironment(
 
   // Firefox properties.
   changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
 
   return changed;
 }
 
 bool
-DriverCrashGuard::FeatureEnabled(int aFeature)
+DriverCrashGuard::FeatureEnabled(int aFeature, bool aDefault)
 {
+  if (!mGfxInfo) {
+    return aDefault;
+  }
   int32_t status;
   if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) {
     return false;
   }
   return status == nsIGfxInfo::FEATURE_STATUS_OK;
 }
 
 bool
@@ -368,30 +381,28 @@ D3D11LayersCrashGuard::UpdateEnvironment
   static bool changed = false;
 
   if (checked) {
     return changed;
   }
 
   checked = true;
 
-  if (mGfxInfo) {
-    // Feature status.
+  // Feature status.
 #if defined(XP_WIN)
-    bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
-                      (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
-    changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
+  bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
+                    (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
+  changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
 
-    bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
-    if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
-      d3d11Enabled = false;
-    }
-    changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
+  bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
+  if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
+    d3d11Enabled = false;
+  }
+  changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
 #endif
-  }
 
   if (!changed) {
     return false;
   }
 
   RecordTelemetry(TelemetryState::EnvironmentChanged);
   return true;
 }
@@ -448,10 +459,55 @@ D3D9VideoCrashGuard::LogCrashRecovery()
 }
 
 void
 D3D9VideoCrashGuard::LogFeatureDisabled()
 {
   gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 video decoding is disabled due to a previous crash.";
 }
 
+GLContextCrashGuard::GLContextCrashGuard(dom::ContentParent* aContentParent)
+ : DriverCrashGuard(CrashGuardType::GLContext, aContentParent)
+{
+}
+
+bool
+GLContextCrashGuard::UpdateEnvironment()
+{
+  static bool checked = false;
+  static bool changed = false;
+
+  if (checked) {
+    return changed;
+  }
+
+  checked = true;
+
+#if defined(XP_WIN)
+  changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-d3d11",
+                                    gfxPrefs::WebGLANGLEForceD3D11());
+  changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-try-d3d11",
+                                    gfxPrefs::WebGLANGLETryD3D11());
+  changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle-force-warp",
+                                    gfxPrefs::WebGLANGLEForceWARP());
+  changed |= CheckAndUpdateBoolPref("gfx.driver-init.webgl-angle",
+                                    FeatureEnabled(nsIGfxInfo::FEATURE_WEBGL_ANGLE, false));
+  changed |= CheckAndUpdateBoolPref("gfx.driver-init.direct3d11-angle",
+                                    FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, false));
+#endif
+
+  return changed;
+}
+
+void
+GLContextCrashGuard::LogCrashRecovery()
+{
+  gfxCriticalError(CriticalLog::DefaultOptions(false)) << "GLContext just crashed and is now disabled.";
+}
+
+void
+GLContextCrashGuard::LogFeatureDisabled()
+{
+  gfxCriticalError(CriticalLog::DefaultOptions(false)) << "GLContext is disabled due to a previous crash.";
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/src/DriverCrashGuard.h
+++ b/gfx/src/DriverCrashGuard.h
@@ -34,16 +34,17 @@ enum class DriverInitStatus
   // We crashed during driver initialization, and have restarted.
   Crashed
 };
 
 enum class CrashGuardType : uint32_t
 {
   D3D11Layers,
   D3D9Video,
+  GLContext,
   NUM_TYPES
 };
 
 // DriverCrashGuard is used to detect crashes at graphics driver callsites.
 // 
 // If the graphics environment is unrecognized or has changed since the last
 // session, the crash guard will activate and will detect any crashes within
 // the scope of the guard object.
@@ -79,17 +80,17 @@ public:
 
 protected:
   virtual void Initialize();
   virtual bool UpdateEnvironment() = 0;
   virtual void LogCrashRecovery() = 0;
   virtual void LogFeatureDisabled() = 0;
 
   // Helper functions.
-  bool FeatureEnabled(int aFeature);
+  bool FeatureEnabled(int aFeature, bool aDefault=true);
   bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
   bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
   std::string GetFullPrefName(const char* aPref);
 
 private:
   // Either process.
   void InitializeIfNeeded();
   bool CheckOrRefreshEnvironment();
@@ -137,13 +138,24 @@ class D3D9VideoCrashGuard final : public
   explicit D3D9VideoCrashGuard(dom::ContentParent* aContentParent = nullptr);
 
  protected:
   bool UpdateEnvironment() override;
   void LogCrashRecovery() override;
   void LogFeatureDisabled() override;
 };
 
+class GLContextCrashGuard final : public DriverCrashGuard
+{
+ public:
+  explicit GLContextCrashGuard(dom::ContentParent* aContentParent = nullptr);
+
+ protected:
+  bool UpdateEnvironment() override;
+  void LogCrashRecovery() override;
+  void LogFeatureDisabled() override;
+};
+
 } // namespace gfx
 } // namespace mozilla
 
 #endif // gfx_src_DriverCrashGuard_h__