Bug 1107718: Properly deal with a D3D11 device reset. r=nical
authorBas Schouten <bschouten@mozilla.com>
Thu, 08 Jan 2015 00:10:49 +0000
changeset 222548 6c673d6a2fb8
parent 222547 d5ead6673b95
child 222549 3ca05c4232ab
push id28068
push usercbook@mozilla.com
push date2015-01-08 13:16 +0000
treeherdermozilla-central@2880e05d5e32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1107718
milestone37.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
Bug 1107718: Properly deal with a D3D11 device reset. r=nical
gfx/2d/Factory.cpp
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/CompositorD3D11.h
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxWindowsPlatform.cpp
widget/windows/nsWindow.cpp
widget/windows/nsWindowGfx.cpp
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -642,16 +642,20 @@ Factory::SetDirect3D11Device(ID3D11Devic
 {
   mD3D11Device = aDevice;
 
   if (mD2D1Device) {
     mD2D1Device->Release();
     mD2D1Device = nullptr;
   }
 
+  if (!aDevice) {
+    return;
+  }
+
   RefPtr<ID2D1Factory1> factory = D2DFactory1();
 
   RefPtr<IDXGIDevice> device;
   aDevice->QueryInterface((IDXGIDevice**)byRef(device));
   factory->CreateDevice(device, &mD2D1Device);
 }
 
 ID3D11Device*
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1040,17 +1040,17 @@ CompositorD3D11::BeginFrame(const nsIntR
                             const Rect& aRenderBounds,
                             Rect* aClipRectOut,
                             Rect* aRenderBoundsOut)
 {
   // Don't composite if we are minimised. Other than for the sake of efficency,
   // this is important because resizing our buffers when mimised will fail and
   // cause a crash when we're restored.
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
-  if (::IsIconic(mHwnd)) {
+  if (::IsIconic(mHwnd) || gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
   UpdateRenderTarget();
 
   // Failed to create a render target or the view.
   if (!mDefaultRT || !mDefaultRT->mRTView ||
@@ -1175,31 +1175,31 @@ void
 CompositorD3D11::EnsureSize()
 {
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
   mSize = rect.Size();
 }
 
-void
+bool
 CompositorD3D11::VerifyBufferSize()
 {
   DXGI_SWAP_CHAIN_DESC swapDesc;
   HRESULT hr;
 
   hr = mSwapChain->GetDesc(&swapDesc);
   if (Failed(hr)) {
-    return;
+    return false;
   }
 
   if ((swapDesc.BufferDesc.Width == mSize.width &&
        swapDesc.BufferDesc.Height == mSize.height) ||
       mSize.width <= 0 || mSize.height <= 0) {
-    return;
+    return true;
   }
 
   if (mDefaultRT) {
     // Make sure the texture, which belongs to the swapchain, is destroyed
     // before resizing the swapchain.
     if (mCurrentRT == mDefaultRT) {
       mCurrentRT = nullptr;
     }
@@ -1214,16 +1214,22 @@ CompositorD3D11::VerifyBufferSize()
     HandleError(hr);
     mDisableSequenceForNextFrame = true;
   } else {
     hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
                                    DXGI_FORMAT_B8G8R8A8_UNORM,
                                    0);
     HandleError(hr);
   }
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  return true;
 }
 
 void
 CompositorD3D11::UpdateRenderTarget()
 {
   EnsureSize();
   VerifyBufferSize();
 
@@ -1417,17 +1423,17 @@ CompositorD3D11::PaintToTarget()
 void
 CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
 {
   if (SUCCEEDED(hr)) {
     return;
   }
   // XXX - It would be nice to use gfxCriticalError, but it needs to
   // be made to work off the main thread first.
-  MOZ_ASSERT(aSeverity != DebugAssert);
+  //MOZ_ASSERT(aSeverity != DebugAssert);
 
   if (aSeverity == Critical) {
     MOZ_CRASH("Unrecoverable D3D11 error");
   }
 
   if (mDevice && hr == DXGI_ERROR_DEVICE_REMOVED) {
     hr = mDevice->GetDeviceRemovedReason();
   }
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -154,17 +154,17 @@ private:
   };
 
   void HandleError(HRESULT hr, Severity aSeverity = DebugAssert);
   bool Failed(HRESULT hr, Severity aSeverity = DebugAssert);
   bool Succeeded(HRESULT hr, Severity aSeverity = DebugAssert);
 
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
-  void VerifyBufferSize();
+  bool VerifyBufferSize();
   void UpdateRenderTarget();
   bool CreateShaders();
   bool UpdateConstantBuffers();
   void SetSamplerForFilter(gfx::Filter aFilter);
   void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
   void PaintToTarget();
 
   virtual gfx::IntSize GetWidgetSize() const MOZ_OVERRIDE { return gfx::ToIntSize(mSize); }
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -22,17 +22,17 @@
 #include "gfxPlatform.h"
 #include "gfxTeeSurface.h"
 #include "GeckoProfiler.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/DrawTargetTiled.h"
 #include <algorithm>
 
-#if CAIRO_HAS_DWRITE_FONT
+#if XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 UserDataKey gfxContext::sDontUseAsSourceKey;
 
@@ -1304,17 +1304,21 @@ gfxContext::PushNewDT(gfxContentType con
     mDT->CreateSimilarDrawTarget(IntSize(int32_t(clipBounds.width), int32_t(clipBounds.height)),
                                  format);
 
   if (!newDT) {
     NS_WARNING("Failed to create DrawTarget of sufficient size.");
     newDT = mDT->CreateSimilarDrawTarget(IntSize(64, 64), format);
 
     if (!newDT) {
-      if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+      if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()
+#ifdef XP_WIN
+          && !(mDT->GetBackendType() == BackendType::DIRECT2D1_1 && !gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice())
+#endif
+          ) {
         // If even this fails.. we're most likely just out of memory!
         NS_ABORT_OOM(BytesPerPixel(format) * 64 * 64);
       }
       newDT = CurrentState().drawTarget;
     }
   }
 
   Save();
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/WindowsVersion.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 
 #include "nsIWindowsRegKey.h"
 #include "nsIFile.h"
 #include "plbase64.h"
 #include "nsIXULRuntime.h"
+#include "imgLoader.h"
 
 #include "nsIGfxInfo.h"
 #include "GfxDriverInfo.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "gfxGDIFontList.h"
 #include "gfxGDIFont.h"
@@ -379,16 +380,26 @@ gfxWindowsPlatform::GetDPIScale()
 }
 
 void
 gfxWindowsPlatform::UpdateRenderMode()
 {
 /* Pick the default render mode for
  * desktop.
  */
+    if (DidRenderingDeviceReset()) {
+      mD3D11DeviceInitialized = false;
+      mD3D11Device = nullptr;
+      mD3D11ContentDevice = nullptr;
+
+      imgLoader::Singleton()->ClearCache(true);
+      imgLoader::Singleton()->ClearCache(false);
+      Factory::SetDirect3D11Device(nullptr);
+    }
+
     mRenderMode = RENDER_GDI;
 
     bool isVistaOrHigher = IsVistaOrLater();
 
     bool safeMode = false;
     nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
     if (xr)
       xr->GetInSafeMode(&safeMode);
@@ -1030,17 +1041,32 @@ gfxWindowsPlatform::IsFontFormatSupporte
 
     // no format hint set, need to look at data
     return true;
 }
 
 bool
 gfxWindowsPlatform::DidRenderingDeviceReset()
 {
-  return GetD3D10Device() && GetD3D10Device()->GetDeviceRemovedReason() != S_OK;
+  if (mD3D11Device) {
+    if (mD3D11Device->GetDeviceRemovedReason() != S_OK) {
+      return true;
+    }
+  }
+  if (mD3D11ContentDevice) {
+    if (mD3D11ContentDevice->GetDeviceRemovedReason() != S_OK) {
+      return true;
+    }
+  }
+  if (GetD3D10Device()) {
+    if (GetD3D10Device()->GetDeviceRemovedReason() != S_OK) {
+      return true;
+    }
+  }
+  return false;
 }
 
 gfxFontFamily *
 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
 {
     return gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
 }
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3336,16 +3336,18 @@ nsWindow::GetLayerManager(PLayerTransact
   }
 #endif
 
   RECT windowRect;
   ::GetClientRect(mWnd, &windowRect);
 
   // Try OMTC first.
   if (!mLayerManager && ShouldUseOffMainThreadCompositing()) {
+    gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
+
     // e10s uses the parameter to pass in the shadow manager from the TabChild
     // so we don't expect to see it there since this doesn't support e10s.
     NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
     CreateCompositor();
   }
 
   if (!mLayerManager ||
       (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -182,16 +182,23 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
 {
   // We never have reentrant paint events, except when we're running our RPC
   // windows event spin loop. If we don't trap for this, we'll try to paint,
   // but view manager will refuse to paint the surface, resulting is black
   // flashes on the plugin rendering surface.
   if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && mPainting)
     return false;
 
+  if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
+    mLayerManager = nullptr;
+    DestroyCompositor();
+    return false;
+  }
+
   // After we CallUpdateWindow to the child, occasionally a WM_PAINT message
   // is posted to the parent event loop with an empty update rect. Do a
   // dummy paint so that Windows stops dispatching WM_PAINT in an inifinite
   // loop. See bug 543788.
   if (IsPlugin()) {
     // XXX Ignore for now when we're running with full blown e10s
     if (mozilla::BrowserTabsRemoteAutostart()) {
       printf_stderr("nsWindow::OnPaint() bailing on paint!\n");
@@ -541,17 +548,16 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
             Invalidate();
           } else {
             result = listener->PaintWindow(this, region);
           }
         }
         break;
 #endif
       case LayersBackend::LAYERS_CLIENT:
-        gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
         result = listener->PaintWindow(this, region);
         break;
       default:
         NS_ERROR("Unknown layers backend used!");
         break;
     }
   }