Bug 900248. Rebuild the d3d9 device. r=Bas
authorNicholas Cameron <ncameron@mozilla.com>
Fri, 22 Nov 2013 11:07:56 +1300
changeset 171562 bbd6b4411f7c6a047e15c6ed0cedba62fd193bb1
parent 171561 1c832bd80232e46554d55f5738d902ac45382bdf
child 171563 71d5c31369c59ec0f17ac5df4455208c56889503
push idunknown
push userunknown
push dateunknown
reviewersBas
bugs900248
milestone28.0a1
Bug 900248. Rebuild the d3d9 device. r=Bas
gfx/layers/Compositor.h
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/d3d9/CompositorD3D9.cpp
gfx/layers/d3d9/CompositorD3D9.h
gfx/layers/d3d9/DeviceManagerD3D9.cpp
gfx/layers/d3d9/DeviceManagerD3D9.h
gfx/layers/ipc/CompositorChild.cpp
gfx/layers/ipc/CompositorChild.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/PCompositor.ipdl
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
widget/xpwidgets/nsBaseWidget.cpp
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -117,16 +117,18 @@ namespace layers {
 
 struct Effect;
 struct EffectChain;
 class Image;
 class ISurfaceAllocator;
 class NewTextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
+class PCompositorParent;
+class LayerManagerComposite;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
 /**
@@ -171,19 +173,20 @@ enum SurfaceInitMode
  * by CreateRenderTarget or CreateRenderTargetFromSource.
  *
  * The target and viewport methods can be called before any DrawQuad call and
  * affect any subsequent DrawQuad calls.
  */
 class Compositor : public RefCounted<Compositor>
 {
 public:
-  Compositor()
+  Compositor(PCompositorParent* aParent = nullptr)
     : mCompositorID(0)
     , mDiagnosticTypes(DIAGNOSTIC_NONE)
+    , mParent(aParent)
   {
     MOZ_COUNT_CTOR(Compositor);
   }
   virtual ~Compositor()
   {
     MOZ_COUNT_DTOR(Compositor);
   }
 
@@ -301,17 +304,18 @@ public:
    * aTransform is the transform from user space to window space.
    * aRenderBounds bounding rect for rendering, in user space.
    *
    * If aClipRectIn is null, this method sets *aClipRectOut to the clip rect
    * actually used for rendering (if aClipRectIn is non-null, we will use that
    * for the clip rect).
    *
    * If aRenderBoundsOut is non-null, it will be set to the render bounds
-   * actually used by the compositor in window space.
+   * actually used by the compositor in window space. If aRenderBoundsOut
+   * is returned empty, composition should be aborted.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect* aClipRectIn,
                           const gfxMatrix& aTransform,
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect* aClipRectOut = nullptr,
                           gfx::Rect* aRenderBoundsOut = nullptr) = 0;
 
@@ -441,16 +445,17 @@ protected:
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
   uint32_t mCompositorID;
   static LayersBackend sBackend;
   DiagnosticTypes mDiagnosticTypes;
+  PCompositorParent* mParent;
 
   /**
    * We keep track of the total number of pixels filled as we composite the
    * current frame. This value is an approximation and is not accurate,
    * especially in the presence of transforms.
    */
   size_t mPixelsPerFrame;
   size_t mPixelsFilled;
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -235,17 +235,16 @@ public:
   }
 
   Compositor* GetCompositor() const
   {
     return mCompositor;
   }
 
   bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
-  RefPtr<Compositor> mCompositor;
 
 private:
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
   nsIntRect mRenderBounds;
 
   /** Current root layer. */
   LayerComposite *RootLayer() const;
@@ -268,16 +267,18 @@ private:
 
   /**
    * Render debug overlays such as the FPS/FrameCounter above the frame.
    */
   void RenderDebugOverlay(const gfx::Rect& aBounds);
 
   void WorldTransformRect(nsIntRect& aRect);
 
+  RefPtr<Compositor> mCompositor;
+
   /** Our more efficient but less powerful alter ego, if one is available. */
   nsRefPtr<Composer2D> mComposer2D;
 
   /* Thebes layer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawThebesLayerCallback mThebesLayerCallback;
   void *mThebesLayerCallbackData;
   gfxMatrix mWorldMatrix;
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -8,24 +8,27 @@
 #include "gfxWindowsPlatform.h"
 #include "nsIWidget.h"
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/ContentHost.h"
 #include "mozilla/layers/Effects.h"
 #include "nsWindowsHelpers.h"
 #include "Nv3DVUtils.h"
 #include "gfxFailure.h"
+#include "mozilla/layers/PCompositorParent.h"
+#include "mozilla/layers/LayerManagerComposite.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
-CompositorD3D9::CompositorD3D9(nsIWidget *aWidget)
-  : mWidget(aWidget)
+CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget)
+  : Compositor(aParent)
+  , mWidget(aWidget)
 {
   sBackend = LAYERS_D3D9;
 }
 
 CompositorD3D9::~CompositorD3D9()
 {
   mSwapChain = nullptr;
   mDeviceManager = nullptr;
@@ -81,16 +84,20 @@ CompositorD3D9::GetMaxTextureSize() cons
 {
   return mDeviceManager->GetMaxTextureSize();
 }
 
 TemporaryRef<CompositingRenderTarget>
 CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect,
                                    SurfaceInitMode aInit)
 {
+  if (!mDeviceManager) {
+    return nullptr;
+  }
+
   RefPtr<IDirect3DTexture9> texture;
   HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1,
                                        D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                                        D3DPOOL_DEFAULT, byRef(texture),
                                        NULL);
   if (FAILED(hr)) {
     ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTarget: Failed to create texture"),
                   hr);
@@ -103,16 +110,20 @@ CompositorD3D9::CreateRenderTarget(const
   return rt;
 }
 
 TemporaryRef<CompositingRenderTarget>
 CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                              const CompositingRenderTarget *aSource,
                                              const gfx::IntPoint &aSourcePoint)
 {
+  if (!mDeviceManager) {
+    return nullptr;
+  }
+
   RefPtr<IDirect3DTexture9> texture;
   HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1,
                                        D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                                        D3DPOOL_DEFAULT, byRef(texture),
                                        NULL);
   if (FAILED(hr)) {
     ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to create texture"),
                   hr);
@@ -160,17 +171,17 @@ CompositorD3D9::CreateRenderTargetFromSo
                                     aRect);
 
   return rt;
 }
 
 void
 CompositorD3D9::SetRenderTarget(CompositingRenderTarget *aRenderTarget)
 {
-  MOZ_ASSERT(aRenderTarget);
+  MOZ_ASSERT(aRenderTarget && mDeviceManager);
   RefPtr<CompositingRenderTargetD3D9> oldRT = mCurrentRT;
   mCurrentRT = static_cast<CompositingRenderTargetD3D9*>(aRenderTarget);
   mCurrentRT->BindRenderTarget(device());
   PrepareViewport(mCurrentRT->GetSize(), gfxMatrix());
 }
 
 static DeviceManagerD3D9::ShaderMode
 ShaderModeForEffectType(EffectTypes aEffectType)
@@ -192,16 +203,20 @@ ShaderModeForEffectType(EffectTypes aEff
 
 void
 CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
                          const gfx::Rect &aClipRect,
                          const EffectChain &aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4 &aTransform)
 {
+  if (!mDeviceManager) {
+    return;
+  }
+
   MOZ_ASSERT(mCurrentRT, "No render target");
   device()->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);
 
   IntPoint origin = mCurrentRT->GetOrigin();
   float renderTargetOffset[] = { origin.x, origin.y, 0, 0 };
   device()->SetVertexShaderConstantF(CBvRenderTargetOffset,
                                      renderTargetOffset,
                                      1);
@@ -433,27 +448,67 @@ CompositorD3D9::SetMask(const EffectChai
   device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, 
                                      ShaderConstantRect(bounds.x,
                                                         bounds.y,
                                                         bounds.width,
                                                         bounds.height),
                                      1);
 }
 
+static void
+CancelCompositing(Rect* aRenderBoundsOut)
+{
+  if (aRenderBoundsOut) {
+    *aRenderBoundsOut = Rect(0, 0, 0, 0);
+  }
+}
+
 void
 CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
                            const Rect *aClipRectIn,
                            const gfxMatrix& aTransform,
                            const Rect& aRenderBounds,
                            Rect *aClipRectOut,
                            Rect *aRenderBoundsOut)
 {
-  if (!mSwapChain->PrepareForRendering()) {
+  if (!mDeviceManager) {
+    mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+    if (!mDeviceManager) {
+      mSwapChain = nullptr;
+      CancelCompositing(aRenderBoundsOut);
+      return;
+    }
+
+    // We have destroyed all our texture memory so we need to tell the client
+    // to redraw everything so we can put that in our new textures and use
+    // them for compositing.
+    mParent->SendInvalidateAll();
+  }
+
+  if (!mDeviceManager->VerifyReadyForRendering()) {
+    NS_ASSERTION(!mCurrentRT && !mDefaultRT,
+                 "Shouldn't have any render targets around, they must be released before our device");
+    mSwapChain = nullptr;
+    mDeviceManager = nullptr;
+
+    CancelCompositing(aRenderBoundsOut);
     return;
   }
+  MOZ_ASSERT(mDeviceManager);
+
+  if (!mSwapChain) {
+    mSwapChain = mDeviceManager->
+      CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
+  }
+  if (!mSwapChain ||
+      !mSwapChain->PrepareForRendering()) {
+    CancelCompositing(aRenderBoundsOut);
+    return;
+  }
+
   mDeviceManager->SetupRenderState();
 
   EnsureSize();
 
   device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
   device()->BeginScene();
 
   if (aClipRectOut) {
@@ -481,29 +536,32 @@ CompositorD3D9::BeginFrame(const nsIntRe
                                                INIT_MODE_CLEAR,
                                                IntRect(0, 0, mSize.width, mSize.height));
   SetRenderTarget(mDefaultRT);
 }
 
 void
 CompositorD3D9::EndFrame()
 {
-  device()->EndScene();
+  if (mDeviceManager) {
+    device()->EndScene();
 
-  nsIntSize oldSize = mSize;
-  EnsureSize();
-  if (oldSize == mSize) {
-    if (mTarget) {
-      PaintToTarget();
-    } else {
-      mSwapChain->Present();
+    nsIntSize oldSize = mSize;
+    EnsureSize();
+    if (oldSize == mSize) {
+      if (mTarget) {
+        PaintToTarget();
+      } else {
+        mSwapChain->Present();
+      }
     }
   }
 
   mCurrentRT = nullptr;
+  mDefaultRT = nullptr;
 }
 
 void
 CompositorD3D9::PrepareViewport(const gfx::IntSize& aSize,
                                 const gfxMatrix &aWorldTransform)
 {
   gfx3DMatrix viewMatrix;
   /*
@@ -549,16 +607,20 @@ CompositorD3D9::SetSamplerForFilter(Filt
     device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
     device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   }
 }
 
 void
 CompositorD3D9::PaintToTarget()
 {
+  if (!mDeviceManager) {
+    return;
+  }
+
   nsRefPtr<IDirect3DSurface9> backBuff;
   nsRefPtr<IDirect3DSurface9> destSurf;
   device()->GetRenderTarget(0, getter_AddRefs(backBuff));
 
   D3DSURFACE_DESC desc;
   backBuff->GetDesc(&desc);
 
   device()->CreateOffscreenPlainSurface(desc.Width, desc.Height,
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -14,17 +14,17 @@
 class nsWidget;
 
 namespace mozilla {
 namespace layers {
 
 class CompositorD3D9 : public Compositor
 {
 public:
-  CompositorD3D9(nsIWidget *aWidget);
+  CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget);
   ~CompositorD3D9();
 
   virtual bool Initialize() MOZ_OVERRIDE;
   virtual void Destroy() MOZ_OVERRIDE {}
 
   virtual TextureFactoryIdentifier
     GetTextureFactoryIdentifier() MOZ_OVERRIDE;
 
@@ -90,17 +90,22 @@ public:
   {
     NS_ASSERTION(false, "Getting the widget size on windows causes some kind of resizing of buffers. "
                         "You should not do that outside of BeginFrame, so the best we can do is return "
                         "the last size we got, that might not be up to date. So you probably shouldn't "
                         "use this method.");
     return mSize;
   }
 
-  IDirect3DDevice9* device() const { return mDeviceManager->device(); }
+  IDirect3DDevice9* device() const
+  {
+    return mDeviceManager
+           ? mDeviceManager->device()
+           : nullptr;
+  }
 
   /**
    * Declare an offset to use when rendering layers. This will be ignored when
    * rendering to a target instead of the screen.
    */
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE
   {
     if (aOffset.x || aOffset.y) {
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -8,16 +8,17 @@
 #include "ThebesLayerD3D9.h"
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 #include "nsPrintfCString.h"
 #include "Nv3DVUtils.h"
 #include "plstr.h"
 #include <algorithm>
 #include "gfxPlatform.h"
+#include "gfxWindowsPlatform.h"
 #include "TextureD3D9.h"
 #include "mozilla/gfx/Point.h"
 
 using mozilla::gfx::IntSize;
 
 namespace mozilla {
 namespace layers {
 
@@ -172,17 +173,23 @@ DeviceManagerD3D9::DeviceManagerD3D9()
   , mTextureAddressingMode(D3DTADDRESS_CLAMP)
   , mHasDynamicTextures(false)
   , mDeviceWasRemoved(false)
 {
 }
 
 DeviceManagerD3D9::~DeviceManagerD3D9()
 {
+  // When we die, we release a ref on our device which will cause it to die.
+  // If not immediately, then soon. We MUST have released all our textures
+  // before we release the device, otherwise we crash.
+  ReleaseTextureResources();
+
   LayerManagerD3D9::OnDeviceManagerDestroy(this);
+  gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this);
 }
 
 bool
 DeviceManagerD3D9::Init()
 {
   WNDCLASSW wc;
   HRESULT hr;
 
@@ -670,72 +677,51 @@ DeviceManagerD3D9::VerifyReadyForRenderi
 
   if (SUCCEEDED(hr)) {
     if (IsD3D9Ex()) {
       hr = mDeviceEx->CheckDeviceState(mFocusWnd);
 
       if (FAILED(hr)) {
         mDeviceWasRemoved = true;
         LayerManagerD3D9::OnDeviceManagerDestroy(this);
+        gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this);
         ++mDeviceResetCount;
         return false;
       }
     }
     return true;
   }
 
   for(unsigned int i = 0; i < mLayersWithResources.Length(); i++) {
     mLayersWithResources[i]->CleanResources();
   }
   for(unsigned int i = 0; i < mSwapChains.Length(); i++) {
     mSwapChains[i]->Reset();
   }
 
   mVB = nullptr;
-  
+
   D3DPRESENT_PARAMETERS pp;
   memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
 
   pp.BackBufferWidth = 1;
   pp.BackBufferHeight = 1;
   pp.BackBufferFormat = D3DFMT_A8R8G8B8;
   pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   pp.Windowed = TRUE;
   pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
   pp.hDeviceWindow = mFocusWnd;
 
   hr = mDevice->Reset(&pp);
   ++mDeviceResetCount;
 
-  if (hr == D3DERR_DEVICELOST) {
-    /* It is not unusual for Reset to return DEVICELOST
-     * we're supposed to continue trying until we get
-     * DEVICENOTRESET and then Reset is supposed to succeed.
-     * Unfortunately, it seems like when we dock or undock
-     * DEVICELOST happens and we never get DEVICENOTRESET. */
-
-    HMONITOR hMonitorWindow;
-    hMonitorWindow = MonitorFromWindow(mFocusWnd, MONITOR_DEFAULTTOPRIMARY);
-    if (hMonitorWindow == mDeviceMonitor) {
-      /* The monitor has not changed. So, let's assume that the
-       * DEVICENOTRESET will be comming. */
-
-      /* jrmuizel: I'm not sure how to trigger this case. Usually, we get
-       * DEVICENOTRESET right away and Reset() succeeds without going through a
-       * set of DEVICELOSTs. This is presumeably because we don't call
-       * VerifyReadyForRendering when we don't have any reason to paint.
-       * Hopefully comparing HMONITORs is not overly aggressive. */
-      return false;
-    }
-    /* otherwise fall through and recreate the device */
-  }
-
   if (FAILED(hr) || !CreateVertexBuffer()) {
     mDeviceWasRemoved = true;
     LayerManagerD3D9::OnDeviceManagerDestroy(this);
+    gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this);
     return false;
   }
 
   return true;
 }
 
 bool
 DeviceManagerD3D9::VerifyCaps()
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -119,16 +119,23 @@ private:
  * belong to.
  */
 class DeviceManagerD3D9 MOZ_FINAL
 {
 public:
   DeviceManagerD3D9();
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceManagerD3D9)
 
+  /**
+   * Initialises the device manager, the underlying device, and everything else
+   * the manager needs.
+   * Returns true if initialisation succeeds, false otherwise.
+   * Note that if initisalisation fails, you cannot try again - you must throw
+   * away the DeviceManagerD3D9 and create a new one.
+   */
   bool Init();
 
   /**
    * Sets up the render state for the device for layer rendering.
    */
   void SetupRenderState();
 
   /**
@@ -188,31 +195,31 @@ public:
                                                 D3DPOOL aPool,
                                                 TextureSourceD3D9* aTextureHostIDirect3DTexture9);
 #ifdef DEBUG
   // Looks for aFind in the list of texture hosts.
   // O(n) so only use for assertions.
   bool DeviceManagerD3D9::IsInTextureHostList(TextureSourceD3D9* aFind);
 #endif
 
+  /**
+   * This function verifies the device is ready for rendering, internally this
+   * will test the cooperative level of the device and reset the device if
+   * needed. If this returns false subsequent rendering calls may return errors.
+   */
+  bool VerifyReadyForRendering();
+
   static uint32_t sMaskQuadRegister;
 
 private:
   friend class SwapChainD3D9;
 
   ~DeviceManagerD3D9();
 
   /**
-   * This function verifies the device is ready for rendering, internally this
-   * will test the cooperative level of the device and reset the device if
-   * needed. If this returns false subsequent rendering calls may return errors.
-   */
-  bool VerifyReadyForRendering();
-
-  /**
    * This will fill our vertex buffer with the data of our quad, it may be
    * called when the vertex buffer is recreated.
    */
   bool CreateVertexBuffer();
 
   /**
    * Release all textures created by this device manager.
    */
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -1,38 +1,39 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=2 et tw=80 : */
 /* 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 "CompositorChild.h"
 #include <stddef.h>                     // for size_t
-#include "Layers.h"                     // for LayerManager
+#include "ClientLayerManager.h"         // for ClientLayerManager
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/process_util.h"          // for OpenProcessHandle
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsIObserver.h"                // for nsIObserver
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop, etc
+#include "FrameLayerBuilder.h"
 
 using mozilla::layers::LayerTransactionChild;
 
 namespace mozilla {
 namespace layers {
 
 /*static*/ CompositorChild* CompositorChild::sCompositor;
 
-CompositorChild::CompositorChild(LayerManager *aLayerManager)
+CompositorChild::CompositorChild(ClientLayerManager *aLayerManager)
   : mLayerManager(aLayerManager)
 {
   MOZ_COUNT_CTOR(CompositorChild);
 }
 
 CompositorChild::~CompositorChild()
 {
   MOZ_COUNT_DTOR(CompositorChild);
@@ -91,16 +92,23 @@ CompositorChild::AllocPLayerTransactionC
 
 bool
 CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
 {
   delete actor;
   return true;
 }
 
+bool
+CompositorChild::RecvInvalidateAll()
+{
+  FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
+  return true;
+}
+
 void
 CompositorChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_ASSERT(sCompositor == this);
 
 #ifdef MOZ_B2G
   // Due to poor lifetime management of gralloc (and possibly shmems) we will
   // crash at some point in the future when we get destroyed due to abnormal
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -16,52 +16,55 @@
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_REFCOUNTING
 
 class nsIObserver;
 
 namespace mozilla {
 namespace layers {
 
-class LayerManager;
+class ClientLayerManager;
 class CompositorParent;
 
 class CompositorChild : public PCompositorChild
 {
   NS_INLINE_DECL_REFCOUNTING(CompositorChild)
 public:
-  CompositorChild(LayerManager *aLayerManager);
+  CompositorChild(ClientLayerManager *aLayerManager);
   virtual ~CompositorChild();
 
   void Destroy();
 
   /**
    * We're asked to create a new Compositor in response to an Opens()
    * or Bridge() request from our parent process.  The Transport is to
    * the compositor's context.
    */
   static PCompositorChild*
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   static PCompositorChild* Get();
 
   static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
+
+  virtual bool RecvInvalidateAll() MOZ_OVERRIDE;
+
 protected:
   virtual PLayerTransactionChild*
     AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
                                 const uint64_t& aId,
                                 TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                 bool* aSuccess) MOZ_OVERRIDE;
 
   virtual bool DeallocPLayerTransactionChild(PLayerTransactionChild *aChild) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
 private:
-  nsRefPtr<LayerManager> mLayerManager;
+  nsRefPtr<ClientLayerManager> mLayerManager;
   nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
   // When we're in a child process, this is the process-global
   // compositor that we use to forward transactions directly to the
   // compositor context in another process.
   static CompositorChild* sCompositor;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorChild);
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -667,17 +667,17 @@ CompositorParent::InitializeLayerManager
       layerManager =
         new LayerManagerComposite(new BasicCompositor(mWidget));
 #ifdef XP_WIN
     } else if (aBackendHints[i] == LAYERS_D3D11) {
       layerManager =
         new LayerManagerComposite(new CompositorD3D11(mWidget));
     } else if (aBackendHints[i] == LAYERS_D3D9) {
       layerManager =
-        new LayerManagerComposite(new CompositorD3D9(mWidget));
+        new LayerManagerComposite(new CompositorD3D9(this, mWidget));
 #endif
     }
 
     if (!layerManager) {
       continue;
     }
 
     layerManager->SetCompositorID(mCompositorID);
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -26,16 +26,20 @@ namespace layers {
  */
 // This should really be 'sync', but we're using 'rpc' as a workaround
 // for Bug 716631.
 intr protocol PCompositor
 {
   // A Compositor manages a single Layer Manager (PLayerTransaction)
   manages PLayerTransaction;
 
+child:
+  // The child should invalidate everything so that the whole window is redrawn.
+  async InvalidateAll();
+
 parent:
 
   // The child is about to be destroyed, so perform any necessary cleanup.
   sync WillStop();
 
   // Clean up in preparation for own destruction.
   sync Stop();
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -346,18 +346,17 @@ static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
 
 gfxWindowsPlatform::gfxWindowsPlatform()
-  : mD3D9DeviceInitialized(false)
-  , mD3D11DeviceInitialized(false)
+  : mD3D11DeviceInitialized(false)
   , mPrefFonts(50)
 {
     mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
     mUsingGDIFonts = false;
 
     /* 
@@ -1451,32 +1450,36 @@ gfxWindowsPlatform::SetupClearTypeParams
 
         GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
 	    dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
             getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
     }
 #endif
 }
 
+void
+gfxWindowsPlatform::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager)
+{
+  mDeviceManager = nullptr;
+}
+
 IDirect3DDevice9*
 gfxWindowsPlatform::GetD3D9Device()
 {
   DeviceManagerD3D9* manager = GetD3D9DeviceManager();
   return manager ? manager->device() : nullptr;
 }
 
 DeviceManagerD3D9*
 gfxWindowsPlatform::GetD3D9DeviceManager()
 {
-  if (!mD3D9DeviceInitialized) {
-    mD3D9DeviceInitialized = true;
-
+  if (!mDeviceManager) {
     mDeviceManager = new DeviceManagerD3D9();
     if (!mDeviceManager->Init()) {
-      NS_WARNING("Could not initialise devive manager");
+      NS_WARNING("Could not initialise device manager");
       mDeviceManager = nullptr;
     }
   }
 
   return mDeviceManager;
 }
 
 ID3D11Device*
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -267,16 +267,17 @@ public:
     inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
     IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; }
 
     IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
     { return mRenderingParams[aRenderMode]; }
 #else
     inline bool DWriteEnabled() { return false; }
 #endif
+    void OnDeviceManagerDestroy(mozilla::layers::DeviceManagerD3D9* aDeviceManager);
     mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
     IDirect3DDevice9* GetD3D9Device();
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
 #endif
     ID3D11Device *GetD3D11Device();
 
@@ -303,17 +304,16 @@ private:
     DWRITE_MEASURING_MODE mMeasuringMode;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
-    bool mD3D9DeviceInitialized;
     bool mD3D11DeviceInitialized;
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 
     nsIMemoryReporter* mGPUAdapterReporter;
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -947,17 +947,17 @@ void nsBaseWidget::CreateCompositor(int 
   // If we've already received a shutdown notification, don't try
   // create a new compositor.
   if (!mShutdownObserver) {
     return;
   }
 
   mCompositorParent = NewCompositorParent(aWidth, aHeight);
   MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
-  LayerManager* lm = new ClientLayerManager(this);
+  ClientLayerManager* lm = new ClientLayerManager(this);
   MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
   mCompositorChild = new CompositorChild(lm);
   mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
 
   TextureFactoryIdentifier textureFactoryIdentifier;
   PLayerTransactionChild* shadowManager;
   nsTArray<LayersBackend> backendHints;
   GetPreferredCompositorBackends(backendHints);