Bug 585248: Use a single device for all LayerManagerD3D9's. r=vlad
authorBas Schouten <bschouten@mozilla.com>
Wed, 11 Aug 2010 01:32:45 +0200
changeset 49316 abe6ec06867660da031c84eb57390c20c4c7a27d
parent 49315 c46399062caf8facacd3a56be97c91dc91cf5e87
child 49317 20ab6d450abcd8b74e6d5ccea26a9230c3483c17
push idunknown
push userunknown
push dateunknown
reviewersvlad
bugs585248
milestone2.0b4pre
Bug 585248: Use a single device for all LayerManagerD3D9's. r=vlad
gfx/layers/Makefile.in
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/ColorLayerD3D9.cpp
gfx/layers/d3d9/ContainerLayerD3D9.cpp
gfx/layers/d3d9/DeviceManagerD3D9.cpp
gfx/layers/d3d9/DeviceManagerD3D9.h
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.h
gfx/layers/d3d9/ThebesLayerD3D9.cpp
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -79,25 +79,29 @@ CPPSRCS = \
         ContainerLayerOGL.cpp \
         ImageLayerOGL.cpp \
         LayerManagerOGL.cpp \
         ThebesLayerOGL.cpp \
         $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifdef MOZ_ENABLE_D3D9_LAYER
-EXPORTS += LayerManagerD3D9.h
+EXPORTS += \
+        LayerManagerD3D9.h \
+        DeviceManagerD3D9.h \
+        $(NULL)
 
 CPPSRCS += \
         LayerManagerD3D9.cpp \
         ThebesLayerD3D9.cpp \
         ContainerLayerD3D9.cpp \
         ImageLayerD3D9.cpp \
         ColorLayerD3D9.cpp \
         CanvasLayerD3D9.cpp \
+        DeviceManagerD3D9.cpp \
         $(NULL)
 endif
 endif
 
 ifdef MOZ_IPC #{
 EXPORTS_NAMESPACES = mozilla/layers
 EXPORTS_mozilla/layers =\
         ShadowLayers.h \
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -225,17 +225,17 @@ CanvasLayerD3D9::RenderLayer()
   float opacity[4];
   /*
    * We always upload a 4 component float, but the shader will use only the
    * first component since it's declared as a 'float'.
    */
   opacity[0] = GetOpacity();
   device()->SetPixelShaderConstantF(0, opacity, 1);
 
-  mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER);
+  mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
 
   if (!mGLBufferIsPremultiplied) {
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
   }
   device()->SetTexture(0, mTexture);
   device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   if (!mGLBufferIsPremultiplied) {
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -71,15 +71,15 @@ ColorLayerD3D9::RenderLayer()
   // color is premultiplied, so we need to adjust all channels
   color[0] = (float)(mColor.r * GetOpacity());
   color[1] = (float)(mColor.g * GetOpacity());
   color[2] = (float)(mColor.b * GetOpacity());
   color[3] = (float)(mColor.a * GetOpacity());
 
   device()->SetPixelShaderConstantF(0, color, 1);
 
-  mD3DManager->SetShaderMode(LayerManagerD3D9::SOLIDCOLORLAYER);
+  mD3DManager->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER);
 
   device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -249,17 +249,17 @@ ContainerLayerD3D9::RenderLayer()
     float opacityVector[4];
     /*
      * We always upload a 4 component float, but the shader will use only the
      * first component since it's declared as a 'float'.
      */
     opacityVector[0] = opacity;
     device()->SetPixelShaderConstantF(0, opacityVector, 1);
 
-    mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER);
+    mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
 
     device()->SetTexture(0, renderTexture);
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
 } /* layers */
 } /* mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "DeviceManagerD3D9.h"
+#include "LayerManagerD3D9Shaders.h"
+#include "ThebesLayerD3D9.h"
+#include "nsIServiceManager.h"
+#include "nsIConsoleService.h"
+#include "nsPrintfCString.h"
+
+namespace mozilla {
+namespace layers {
+
+const LPCWSTR kClassName       = L"D3D9WindowClass";
+
+typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)(
+  UINT SDKVersion
+);
+
+struct vertex {
+  float x, y;
+};
+
+SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager)
+  : mDeviceManager(aDeviceManager)
+  , mWnd(0)
+{
+  mDeviceManager->mSwapChains.AppendElement(this);
+}
+
+SwapChainD3D9::~SwapChainD3D9()
+{
+  mDeviceManager->mSwapChains.RemoveElement(this);
+}
+
+bool
+SwapChainD3D9::Init(HWND hWnd)
+{
+  RECT r;
+  ::GetClientRect(hWnd, &r);
+
+  mWnd = hWnd;
+
+  D3DPRESENT_PARAMETERS pp;
+  memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
+
+  pp.BackBufferFormat = D3DFMT_UNKNOWN;
+  pp.SwapEffect = D3DSWAPEFFECT_COPY;
+  pp.Windowed = TRUE;
+  pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+  pp.hDeviceWindow = mWnd;
+  if (r.left == r.right || r.top == r.bottom) {
+    pp.BackBufferHeight = 1;
+    pp.BackBufferWidth = 1;
+  }
+
+  HRESULT hr = mDeviceManager->device()->
+    CreateAdditionalSwapChain(&pp,
+                              getter_AddRefs(mSwapChain));
+
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to create swap chain for window.");
+    return false;
+  }
+
+  return true;
+}
+
+bool
+SwapChainD3D9::PrepareForRendering()
+{
+  RECT r;
+  if (!::GetClientRect(mWnd, &r)) {
+    return false;
+  }
+
+  if (!mDeviceManager->VerifyReadyForRendering()) {
+    return false;
+  }
+
+  if (!mSwapChain) {
+    Init(mWnd);
+  }
+
+  if (mSwapChain) {
+    nsRefPtr<IDirect3DSurface9> backBuffer;
+    mSwapChain->GetBackBuffer(0,
+                              D3DBACKBUFFER_TYPE_MONO,
+                              getter_AddRefs(backBuffer));
+
+    D3DSURFACE_DESC desc;
+    backBuffer->GetDesc(&desc);
+
+    if (desc.Width == r.right - r.left && desc.Height == r.bottom - r.top) {
+      mDeviceManager->device()->SetRenderTarget(0, backBuffer);
+      return true;
+    }
+
+    mSwapChain = nsnull;
+    
+    Init(mWnd);
+    
+    if (!mSwapChain) {
+      return false;
+    }
+    
+    mSwapChain->GetBackBuffer(0,
+                              D3DBACKBUFFER_TYPE_MONO,
+                              getter_AddRefs(backBuffer));
+
+    mDeviceManager->device()->SetRenderTarget(0, backBuffer);
+    
+    return true;
+  }
+  return false;
+}
+
+void
+SwapChainD3D9::Present(const nsIntRect &aRect)
+{
+  RECT r;
+  r.left = aRect.x;
+  r.top = aRect.y;
+  r.right = aRect.XMost();
+  r.bottom = aRect.YMost();
+
+  mSwapChain->Present(&r, &r, 0, 0, 0);
+}
+
+void
+SwapChainD3D9::Reset()
+{
+  mSwapChain = nsnull;
+}
+
+#define HAS_CAP(a, b) (((a) & (b)) == (b))
+#define LACKS_CAP(a, b) !(((a) & (b)) == (b))
+
+DeviceManagerD3D9::DeviceManagerD3D9()
+{
+}
+
+bool
+DeviceManagerD3D9::Init()
+{
+  WNDCLASSW wc;
+  if (!GetClassInfoW(GetModuleHandle(NULL), kClassName, &wc)) {
+      ZeroMemory(&wc, sizeof(WNDCLASSW));
+      wc.hInstance = GetModuleHandle(NULL);
+      wc.lpfnWndProc = ::DefWindowProc;
+      wc.lpszClassName = kClassName;
+      if (!RegisterClassW(&wc)) {
+          NS_WARNING("Failed to register window class for DeviceManager.");
+          return false;
+      }
+  }
+
+  mFocusWnd = CreateWindow(kClassName, L"D3D9Window", WS_OVERLAPPEDWINDOW,
+                           CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL,
+                           NULL, GetModuleHandle(NULL), NULL);
+
+  if (!mFocusWnd) {
+    NS_WARNING("Failed to create DeviceManagerD3D9 Window.");
+    return false;
+  }
+
+  Direct3DCreate9Func d3d9create = (Direct3DCreate9Func)
+    GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9");
+  
+  if (!d3d9create) {
+    return false;
+  }
+
+  mD3D9 = dont_AddRef(d3d9create(D3D_SDK_VERSION));
+
+  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;
+
+  HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT,
+                                   D3DDEVTYPE_HAL,
+                                   mFocusWnd,
+                                   D3DCREATE_FPU_PRESERVE |
+                                   D3DCREATE_MULTITHREADED |
+                                   D3DCREATE_MIXED_VERTEXPROCESSING,
+                                   &pp,
+                                   getter_AddRefs(mDevice));
+
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to create Device for DeviceManagerD3D9.");
+    return false;
+  }
+
+  if (!VerifyCaps()) {
+    return false;
+  }
+
+  hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS,
+                                   getter_AddRefs(mLayerVS));
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS,
+                                  getter_AddRefs(mRGBPS));
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS,
+                                  getter_AddRefs(mYCbCrPS));
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS,
+                                  getter_AddRefs(mSolidColorPS));
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4,
+                                   0,
+                                   0,
+                                   D3DPOOL_MANAGED,
+                                   getter_AddRefs(mVB),
+                                   NULL);
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  vertex *vertices;
+  hr = mVB->Lock(0, 0, (void**)&vertices, 0);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  vertices[0].x = vertices[0].y = 0;
+  vertices[1].x = 1; vertices[1].y = 0;
+  vertices[2].x = 0; vertices[2].y = 1;
+  vertices[3].x = 1; vertices[3].y = 1;
+
+  mVB->Unlock();
+
+  hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  D3DVERTEXELEMENT9 elements[] = {
+    { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
+      D3DDECLUSAGE_POSITION, 0 },
+    D3DDECL_END()
+  };
+
+  mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD));
+
+  nsCOMPtr<nsIConsoleService>
+    console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+
+  D3DADAPTER_IDENTIFIER9 identifier;
+  mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier);
+
+  if (console) {
+    nsString msg;
+    msg +=
+      NS_LITERAL_STRING("Direct3D 9 DeviceManager Initialized Succesfully.\nDriver: ");
+    msg += NS_ConvertUTF8toUTF16(
+      nsDependentCString((const char*)identifier.Driver));
+    msg += NS_LITERAL_STRING("\nDescription: ");
+    msg += NS_ConvertUTF8toUTF16(
+      nsDependentCString((const char*)identifier.Description));
+    msg += NS_LITERAL_STRING("\nVersion: ");
+    msg += NS_ConvertUTF8toUTF16(
+      nsPrintfCString("%d.%d.%d.%d",
+                      HIWORD(identifier.DriverVersion.HighPart),
+                      LOWORD(identifier.DriverVersion.HighPart),
+                      HIWORD(identifier.DriverVersion.LowPart),
+                      LOWORD(identifier.DriverVersion.LowPart)));
+    console->LogStringMessage(msg.get());
+  }
+
+  return true;
+}
+
+void
+DeviceManagerD3D9::SetupRenderState()
+{
+  mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
+  mDevice->SetVertexDeclaration(mVD);
+  mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+  mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+  mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+  mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+  mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
+  mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+}
+
+already_AddRefed<SwapChainD3D9>
+DeviceManagerD3D9::CreateSwapChain(HWND hWnd)
+{
+  nsRefPtr<SwapChainD3D9> swapChain = new SwapChainD3D9(this);
+  
+  if (!swapChain->Init(hWnd)) {
+    return nsnull;
+  }
+
+  return swapChain.forget();
+}
+
+void
+DeviceManagerD3D9::SetShaderMode(ShaderMode aMode)
+{
+  switch (aMode) {
+    case RGBLAYER:
+      mDevice->SetVertexShader(mLayerVS);
+      mDevice->SetPixelShader(mRGBPS);
+      break;
+    case YCBCRLAYER:
+      mDevice->SetVertexShader(mLayerVS);
+      mDevice->SetPixelShader(mYCbCrPS);
+      break;
+    case SOLIDCOLORLAYER:
+      mDevice->SetVertexShader(mLayerVS);
+      mDevice->SetPixelShader(mSolidColorPS);
+      break;
+  }
+}
+
+bool
+DeviceManagerD3D9::VerifyReadyForRendering()
+{
+  HRESULT hr = mDevice->TestCooperativeLevel();
+
+  if (SUCCEEDED(hr)) {
+    return true;
+  }
+
+  if (hr != D3DERR_DEVICENOTRESET) {
+    return false;
+  }
+
+  for(unsigned int i = 0; i < mThebesLayers.Length(); i++) {
+    mThebesLayers[i]->CleanResources();
+  }
+  for(unsigned int i = 0; i < mSwapChains.Length(); i++) {
+    mSwapChains[i]->Reset();
+  }
+  
+  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);
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
+DeviceManagerD3D9::VerifyCaps()
+{
+  D3DCAPS9 caps;
+  HRESULT hr = mDevice->GetDeviceCaps(&caps);
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) ||
+      LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) ||
+      LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) ||
+      HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) ||
+      (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) &&
+       LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) ||
+      LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) {
+    return false;
+  }
+
+  if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) {
+    return false;
+  }
+
+  if (caps.MaxTextureHeight < 4096 ||
+      caps.MaxTextureWidth < 4096) {
+    return false;
+  }
+
+  if ((caps.PixelShaderVersion & 0xffff) < 0x200 ||
+      (caps.VertexShaderVersion & 0xffff) < 0x200) {
+    return false;
+  }
+
+  return true;
+}
+
+} /* namespace layers */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_DEVICEMANAGERD3D9_H
+#define GFX_DEVICEMANAGERD3D9_H
+
+#include "gfxTypes.h"
+#include "nsRect.h"
+#include "nsAutoPtr.h"
+#include "d3d9.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+class DeviceManagerD3D9;
+class ThebesLayerD3D9;
+
+/**
+ * SwapChain class, this class manages the swap chain belonging to a
+ * LayerManagerD3D9.
+ */
+class THEBES_API SwapChainD3D9
+{
+  NS_INLINE_DECL_REFCOUNTING(SwapChainD3D9)
+public:
+  ~SwapChainD3D9();
+
+  /**
+   * This function will prepare the device this swap chain belongs to for
+   * rendering to this swap chain. Only after calling this function can the
+   * swap chain be drawn to, and only until this function is called on another
+   * swap chain belonging to this device will the device draw to it. Passed in
+   * is the size of the swap chain. If the window size differs from the size
+   * during the last call to this function the swap chain will resize. Note that
+   * in no case does this function guarantee the backbuffer to still have its
+   * old content.
+   */
+  bool PrepareForRendering();
+
+  /**
+   * This function will present the selected rectangle of the swap chain to
+   * its associated window.
+   */
+  void Present(const nsIntRect &aRect);
+
+private:
+  friend class DeviceManagerD3D9;
+
+  SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager);
+  
+  bool Init(HWND hWnd);
+
+  /**
+   * This causes us to release our swap chain, clearing out our resource usage
+   * so the master device may reset.
+   */
+  void Reset();
+
+  nsRefPtr<IDirect3DSwapChain9> mSwapChain;
+  nsRefPtr<DeviceManagerD3D9> mDeviceManager;
+  HWND mWnd;
+};
+
+/**
+ * Device manager, this class is used by the layer managers to share the D3D9
+ * device and create swap chains for the individual windows the layer managers
+ * belong to.
+ */
+class THEBES_API DeviceManagerD3D9
+{
+public:
+  DeviceManagerD3D9();
+
+  // We want the nsrefcnt return value. So we cannot use the inline refcnt macro
+  NS_IMPL_ADDREF(DeviceManagerD3D9)
+  NS_IMPL_RELEASE(DeviceManagerD3D9)
+
+  bool Init();
+
+  /**
+   * Sets up the render state for the device for layer rendering.
+   */
+  void SetupRenderState();
+
+  /**
+   * Create a swap chain setup to work with the specified window.
+   */
+  already_AddRefed<SwapChainD3D9> CreateSwapChain(HWND hWnd);
+
+  IDirect3DDevice9 *device() { return mDevice; }
+
+  enum ShaderMode {
+    RGBLAYER,
+    YCBCRLAYER,
+    SOLIDCOLORLAYER
+  };
+
+  void SetShaderMode(ShaderMode aMode);
+
+  /**
+   * We keep a list of all thebes layers since we need their D3DPOOL_DEFAULT
+   * surfaces to be released when we want to reset the device.
+   */
+  nsTArray<ThebesLayerD3D9*> mThebesLayers;
+private:
+  friend class SwapChainD3D9;
+
+  /**
+   * 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();
+
+  /* Array used to store all swap chains for device resets */
+  nsTArray<SwapChainD3D9*> mSwapChains;
+
+  /* The D3D device we use */
+  nsRefPtr<IDirect3DDevice9> mDevice;
+
+  /* An instance of the D3D9 object */
+  nsRefPtr<IDirect3D9> mD3D9;
+
+  /* Vertex shader used for layer quads */
+  nsRefPtr<IDirect3DVertexShader9> mLayerVS;
+
+  /* Pixel shader used for RGB textures */
+  nsRefPtr<IDirect3DPixelShader9> mRGBPS;
+
+  /* Pixel shader used for RGB textures */
+  nsRefPtr<IDirect3DPixelShader9> mYCbCrPS;
+
+  /* Pixel shader used for solid colors */
+  nsRefPtr<IDirect3DPixelShader9> mSolidColorPS;
+
+  /* Vertex buffer containing our basic vertex structure */
+  nsRefPtr<IDirect3DVertexBuffer9> mVB;
+
+  /* Our vertex declaration */
+  nsRefPtr<IDirect3DVertexDeclaration9> mVD;
+
+  /* Our focus window - this is really a dummy window we can associate our
+   * device with.
+   */
+  HWND mFocusWnd;
+
+  nsAutoRefCnt mRefCnt;
+  NS_DECL_OWNINGTHREAD
+
+  /**
+   * Verifies all required device capabilities are present.
+   */
+  bool VerifyCaps();
+};
+
+} /* namespace layers */
+} /* namespace mozilla */
+
+#endif /* GFX_DEVICEMANAGERD3D9_H */
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -180,17 +180,17 @@ ImageLayerD3D9::RenderLayer()
     float opacity[4];
     /*
      * We always upload a 4 component float, but the shader will
      * only use the the first component since it's declared as a 'float'.
      */
     opacity[0] = GetOpacity();
     device()->SetPixelShaderConstantF(0, opacity, 1);
 
-    mD3DManager->SetShaderMode(LayerManagerD3D9::YCBCRLAYER);
+    mD3DManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER);
 
     device()->SetTexture(0, yuvImage->mYTexture);
     device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
     device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
     device()->SetTexture(1, yuvImage->mCbTexture);
     device()->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
     device()->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
     device()->SetTexture(2, yuvImage->mCrTexture);
@@ -222,17 +222,17 @@ ImageLayerD3D9::RenderLayer()
     float opacity[4];
     /*
      * We always upload a 4 component float, but the shader will
      * only use the the first component since it's declared as a 'float'.
      */
     opacity[0] = GetOpacity();
     device()->SetPixelShaderConstantF(0, opacity, 1);
 
-    mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER);
+    mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
 
     device()->SetTexture(0, cairoImage->mTexture);
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
 PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9(mozilla::layers::LayerManagerD3D9* aManager)
   : PlanarYCbCrImage(static_cast<ImageD3D9*>(this))
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -38,182 +38,61 @@
 #include "LayerManagerD3D9.h"
 
 #include "ThebesLayerD3D9.h"
 #include "ContainerLayerD3D9.h"
 #include "ImageLayerD3D9.h"
 #include "ColorLayerD3D9.h"
 #include "CanvasLayerD3D9.h"
 
-#include "LayerManagerD3D9Shaders.h"
-
-#include "nsIServiceManager.h"
-#include "nsIConsoleService.h"
-#include "nsPrintfCString.h"
-
 namespace mozilla {
 namespace layers {
 
-struct vertex {
-  float x, y;
-};
-
-IDirect3D9 *LayerManagerD3D9::mD3D9 = NULL;
-
-typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)(
-  UINT SDKVersion
-);
-
+DeviceManagerD3D9 *LayerManagerD3D9::mDeviceManager = nsnull;
 
 LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget)
 {
     mWidget = aWidget;
     mCurrentCallbackInfo.Callback = NULL;
     mCurrentCallbackInfo.CallbackData = NULL;
 }
 
 LayerManagerD3D9::~LayerManagerD3D9()
 {
-}
+  /* Important to release this first since it also holds a reference to the
+   * device manager
+   */
+  mSwapChain = nsnull;
 
-#define HAS_CAP(a, b) (((a) & (b)) == (b))
-#define LACKS_CAP(a, b) !(((a) & (b)) == (b))
+  if (mDeviceManager) {
+    if (!mDeviceManager->Release()) {
+      mDeviceManager = nsnull;
+    }
+  }
+}
 
 PRBool
 LayerManagerD3D9::Initialize()
 {
-  if (!mD3D9) {
-    Direct3DCreate9Func d3d9create = (Direct3DCreate9Func)
-      GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9");
-    if (!d3d9create) {
-      return PR_FALSE;
-    }
+  if (!mDeviceManager) {
+    mDeviceManager = new DeviceManagerD3D9;
 
-    mD3D9 = d3d9create(D3D_SDK_VERSION);
-    if (!mD3D9) {
+    if (!mDeviceManager->Init()) {
+      mDeviceManager = nsnull;
       return PR_FALSE;
     }
   }
 
-  D3DPRESENT_PARAMETERS pp;
-  memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
-
-  pp.BackBufferFormat = D3DFMT_A8R8G8B8;
-  pp.SwapEffect = D3DSWAPEFFECT_COPY;
-  pp.Windowed = TRUE;
-  pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-  pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
-
-  HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT,
-                                   D3DDEVTYPE_HAL,
-                                   NULL,
-                                   D3DCREATE_FPU_PRESERVE |
-                                   D3DCREATE_MULTITHREADED |
-                                   D3DCREATE_MIXED_VERTEXPROCESSING,
-                                   &pp,
-                                   getter_AddRefs(mDevice));
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  if (!VerifyCaps()) {
-    return PR_FALSE;
-  }
-
-  hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS,
-                                   getter_AddRefs(mLayerVS));
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS,
-                                  getter_AddRefs(mRGBPS));
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS,
-                                  getter_AddRefs(mYCbCrPS));
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS,
-                                  getter_AddRefs(mSolidColorPS));
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
+  mDeviceManager->AddRef();
 
-  hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4,
-                                   0,
-                                   0,
-                                   D3DPOOL_MANAGED,
-                                   getter_AddRefs(mVB),
-                                   NULL);
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  vertex *vertices;
-  hr = mVB->Lock(0, 0, (void**)&vertices, 0);
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  vertices[0].x = vertices[0].y = 0;
-  vertices[1].x = 1; vertices[1].y = 0;
-  vertices[2].x = 0; vertices[2].y = 1;
-  vertices[3].x = 1; vertices[3].y = 1;
-
-  mVB->Unlock();
-
-  hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
+  mSwapChain = mDeviceManager->
+    CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
 
-  D3DVERTEXELEMENT9 elements[] = {
-    { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
-      D3DDECLUSAGE_POSITION, 0 },
-    D3DDECL_END()
-  };
-
-  mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD));
-
-  SetupRenderState();
-
-  nsCOMPtr<nsIConsoleService>
-    console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-
-  D3DADAPTER_IDENTIFIER9 identifier;
-  mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier);
-
-  if (console) {
-    nsString msg;
-    msg +=
-      NS_LITERAL_STRING("Direct3D 9 LayerManager Initialized Succesfully.\nDriver: ");
-    msg += NS_ConvertUTF8toUTF16(
-      nsDependentCString((const char*)identifier.Driver));
-    msg += NS_LITERAL_STRING("\nDescription: ");
-    msg += NS_ConvertUTF8toUTF16(
-      nsDependentCString((const char*)identifier.Description));
-    msg += NS_LITERAL_STRING("\nVersion: ");
-    msg += NS_ConvertUTF8toUTF16(
-      nsPrintfCString("%d.%d.%d.%d",
-                      HIWORD(identifier.DriverVersion.HighPart),
-                      LOWORD(identifier.DriverVersion.HighPart),
-                      HIWORD(identifier.DriverVersion.LowPart),
-                      LOWORD(identifier.DriverVersion.LowPart)));
-    console->LogStringMessage(msg.get());
+  if (!mSwapChain) {
+    return PR_FALSE;
   }
 
   return PR_TRUE;
 }
 
 void
 LayerManagerD3D9::SetClippingRegion(const nsIntRegion &aClippingRegion)
 {
@@ -294,79 +173,56 @@ LayerManagerD3D9::CreateCanvasLayer()
 already_AddRefed<ImageContainer>
 LayerManagerD3D9::CreateImageContainer()
 {
   nsRefPtr<ImageContainer> container = new ImageContainerD3D9(this);
   return container.forget();
 }
 
 void
-LayerManagerD3D9::SetShaderMode(ShaderMode aMode)
-{
-  switch (aMode) {
-    case RGBLAYER:
-      mDevice->SetVertexShader(mLayerVS);
-      mDevice->SetPixelShader(mRGBPS);
-      break;
-    case YCBCRLAYER:
-      mDevice->SetVertexShader(mLayerVS);
-      mDevice->SetPixelShader(mYCbCrPS);
-      break;
-    case SOLIDCOLORLAYER:
-      mDevice->SetVertexShader(mLayerVS);
-      mDevice->SetPixelShader(mSolidColorPS);
-      break;
-  }
-}
-
-void
 LayerManagerD3D9::Render()
 {
-  if (!SetupBackBuffer()) {
+  if (!mSwapChain->PrepareForRendering()) {
     return;
   }
+  deviceManager()->SetupRenderState();
+
   SetupPipeline();
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
-  mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
+  device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
 
-  mDevice->BeginScene();
+  device()->BeginScene();
 
   if (mRootLayer) {
     const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect();
     RECT r;
     if (clipRect) {
       r.left = (LONG)clipRect->x;
       r.top = (LONG)clipRect->y;
       r.right = (LONG)(clipRect->x + clipRect->width);
       r.bottom = (LONG)(clipRect->y + clipRect->height);
     } else {
       r.left = r.top = 0;
       r.right = rect.width;
       r.bottom = rect.height;
     }
-    mDevice->SetScissorRect(&r);
+    device()->SetScissorRect(&r);
 
     mRootLayer->RenderLayer();
   }
 
-  mDevice->EndScene();
+  device()->EndScene();
 
   if (!mTarget) {
     const nsIntRect *r;
     for (nsIntRegionRectIterator iter(mClippingRegion);
          (r = iter.Next()) != nsnull;) {
-      RECT rect;
-      rect.left = r->x;
-      rect.top = r->y;
-      rect.right = r->XMost();
-      rect.bottom = r->YMost();
-
-      mDevice->Present(&rect, &rect, NULL, NULL);
+      mSwapChain->Present(*r);
     }
   } else {
     PaintToTarget();
   }
 }
 
 void
 LayerManagerD3D9::SetupPipeline()
@@ -382,186 +238,54 @@ LayerManagerD3D9::SetupPipeline()
   memset(&viewMatrix, 0, sizeof(viewMatrix));
   viewMatrix[0][0] = 2.0f / rect.width;
   viewMatrix[1][1] = -2.0f / rect.height;
   viewMatrix[2][2] = 1.0f;
   viewMatrix[3][0] = -1.0f;
   viewMatrix[3][1] = 1.0f;
   viewMatrix[3][3] = 1.0f;
 
-  HRESULT hr = mDevice->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4);
+  HRESULT hr = device()->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4);
 
   if (FAILED(hr)) {
     NS_WARNING("Failed to set projection shader constant!");
   }
 }
 
-PRBool
-LayerManagerD3D9::SetupBackBuffer()
-{
-  nsRefPtr<IDirect3DSurface9> backBuffer;
-  mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO,
-                         getter_AddRefs(backBuffer));
-
-  D3DSURFACE_DESC desc;
-  nsIntRect rect;
-  mWidget->GetClientBounds(rect);
-  backBuffer->GetDesc(&desc);
-
-  HRESULT hr = mDevice->TestCooperativeLevel();
-
-  /* The device is lost or something else is wrong, failure */
-  if (FAILED(hr) && hr != D3DERR_DEVICENOTRESET) {
-    return PR_FALSE;
-  }
-
-  /*
-   * If the backbuffer is the right size, and the device is not lost, we can
-   * safely render without doing anything.
-   */
-  if ((desc.Width == rect.width && desc.Height == rect.height) &&
-      SUCCEEDED(hr)) {
-    return PR_TRUE;
-  }
-
-  /*
-   * Our device is lost or our backbuffer needs resizing, start by clearing
-   * out all D3DPOOL_DEFAULT surfaces.
-   */
-  for(unsigned int i = 0; i < mThebesLayers.Length(); i++) {
-    mThebesLayers[i]->CleanResources();
-  }
-
-  backBuffer = NULL;
-
-  D3DPRESENT_PARAMETERS pp;
-  memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
-
-  pp.BackBufferFormat = D3DFMT_A8R8G8B8;
-  pp.SwapEffect = D3DSWAPEFFECT_COPY;
-  pp.Windowed = TRUE;
-  pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-  pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
-
-  hr = mDevice->Reset(&pp);
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  SetupRenderState();
-
-  return PR_TRUE;
-}
-
 void
 LayerManagerD3D9::PaintToTarget()
 {
   nsRefPtr<IDirect3DSurface9> backBuff;
   nsRefPtr<IDirect3DSurface9> destSurf;
-  mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO,
+  device()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO,
                          getter_AddRefs(backBuff));
 
   D3DSURFACE_DESC desc;
   backBuff->GetDesc(&desc);
 
-  mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height,
+  device()->CreateOffscreenPlainSurface(desc.Width, desc.Height,
                                        D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
                                        getter_AddRefs(destSurf), NULL);
 
-  mDevice->GetRenderTargetData(backBuff, destSurf);
+  device()->GetRenderTargetData(backBuff, destSurf);
 
   D3DLOCKED_RECT rect;
   destSurf->LockRect(&rect, NULL, D3DLOCK_READONLY);
 
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface((unsigned char*)rect.pBits,
                         gfxIntSize(desc.Width, desc.Height),
                         rect.Pitch,
                         gfxASurface::ImageFormatARGB32);
 
   mTarget->SetSource(imageSurface);
   mTarget->SetOperator(gfxContext::OPERATOR_OVER);
   mTarget->Paint();
   destSurf->UnlockRect();
 }
 
-void
-LayerManagerD3D9::SetupRenderState()
-{
-  mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
-  mDevice->SetVertexDeclaration(mVD);
-  mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
-  mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-  mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
-  mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
-  mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
-  mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
-  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-}
-
-PRBool
-LayerManagerD3D9::VerifyCaps()
-{
-  D3DCAPS9 caps;
-  HRESULT hr = mDevice->GetDeviceCaps(&caps);
-
-  if (FAILED(hr)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) ||
-      LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) ||
-      LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) ||
-      HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) ||
-      (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) &&
-       LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) ||
-      LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) {
-    return PR_FALSE;
-  }
-
-  if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) {
-    return PR_FALSE;
-  }
-
-  if (caps.MaxTextureHeight < 4096 ||
-      caps.MaxTextureWidth < 4096) {
-    return PR_FALSE;
-  }
-
-  if ((caps.PixelShaderVersion & 0xffff) < 0x200 ||
-      (caps.VertexShaderVersion & 0xffff) < 0x200) {
-    return PR_FALSE;
-  }
-  return PR_TRUE;
-}
-
 LayerD3D9::LayerD3D9(LayerManagerD3D9 *aManager)
   : mD3DManager(aManager)
 {
 }
 
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -41,16 +41,18 @@
 #include "Layers.h"
 
 #include <windows.h>
 #include <d3d9.h>
 
 #include "gfxContext.h"
 #include "nsIWidget.h"
 
+#include "DeviceManagerD3D9.h"
+
 namespace mozilla {
 namespace layers {
 
 class LayerD3D9;
 class ThebesLayerD3D9;
 
 /*
  * This is the LayerManager used for Direct3D 9. For now this will render on
@@ -117,95 +119,62 @@ public:
 
   virtual LayersBackend GetBackendType() { return LAYERS_D3D9; }
 
   /*
    * Helper methods.
    */
   void SetClippingEnabled(PRBool aEnabled);
 
-  IDirect3DDevice9 *device() const { return mDevice; }
+  void SetShaderMode(DeviceManagerD3D9::ShaderMode aMode)
+    { mDeviceManager->SetShaderMode(aMode); }
 
-  enum ShaderMode {
-    RGBLAYER,
-    YCBCRLAYER,
-    SOLIDCOLORLAYER
-  };
-
-  void SetShaderMode(ShaderMode aMode);
-
-  nsTArray<ThebesLayerD3D9*> mThebesLayers;
+  IDirect3DDevice9 *device() const { return mDeviceManager->device(); }
+  DeviceManagerD3D9 *deviceManager() const { return mDeviceManager; }
 
 private:
-  /* Direct3D9 instance */
-  static IDirect3D9 *mD3D9;
+  /* Device manager instance */
+  static DeviceManagerD3D9 *mDeviceManager;
+
+  /* Swap chain associated with this layer manager */
+  nsRefPtr<SwapChainD3D9> mSwapChain;
 
   /* Widget associated with this layer manager */
   nsIWidget *mWidget;
+
   /*
    * Context target, NULL when drawing directly to our swap chain.
    */
   nsRefPtr<gfxContext> mTarget;
 
-  nsRefPtr<IDirect3DDevice9> mDevice;
-
-  /* Vertex shader used for layer quads */
-  nsRefPtr<IDirect3DVertexShader9> mLayerVS;
-
-  /* Pixel shader used for RGB textures */
-  nsRefPtr<IDirect3DPixelShader9> mRGBPS;
-
-  /* Pixel shader used for RGB textures */
-  nsRefPtr<IDirect3DPixelShader9> mYCbCrPS;
-
-  /* Pixel shader used for solid colors */
-  nsRefPtr<IDirect3DPixelShader9> mSolidColorPS;
-
-  /* Vertex buffer containing our basic vertex structure */
-  nsRefPtr<IDirect3DVertexBuffer9> mVB;
-
-  /* Our vertex declaration */
-  nsRefPtr<IDirect3DVertexDeclaration9> mVD;
-
   /* Current root layer. */
   LayerD3D9 *mRootLayer;
 
   /* Callback info for current transaction */
   CallbackInfo mCurrentCallbackInfo;
 
   /*
    * Region we're clipping our current drawing to.
    */
   nsIntRegion mClippingRegion;
+
   /*
    * Render the current layer tree to the active target.
    */
   void Render();
+
   /*
    * Setup the pipeline.
    */
   void SetupPipeline();
-  /*
-   * Setup the backbuffer.
-   *
-   * \return PR_TRUE if setup was succesful
-   */
-  PRBool SetupBackBuffer();
-  /*
-   * Setup the render state for the surface.
-   */
-  void SetupRenderState();
+
   /*
    * Copies the content of our backbuffer to the set transaction target.
    */
   void PaintToTarget();
-  /*
-   * Verifies all required device capabilities are present.
-   */
-  PRBool VerifyCaps();
 
 };
 
 /*
  * General information and tree management for OGL layers.
  */
 class LayerD3D9
 {
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -64,22 +64,22 @@ UseOpaqueSurface(Layer* aLayer)
          UseOpaqueSurface(parent);
 }
 
 ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager)
   : ThebesLayer(aManager, NULL)
   , LayerD3D9(aManager)
 {
   mImplData = static_cast<LayerD3D9*>(this);
-  aManager->mThebesLayers.AppendElement(this);
+  aManager->deviceManager()->mThebesLayers.AppendElement(this);
 }
 
 ThebesLayerD3D9::~ThebesLayerD3D9()
 {
-  mD3DManager->mThebesLayers.RemoveElement(this);
+  mD3DManager->deviceManager()->mThebesLayers.RemoveElement(this);
 }
 
 /**
  * Retention threshold - amount of pixels intersection required to enable
  * layer content retention. This is a guesstimate. Profiling could be done to
  * figure out the optimal threshold.
  */
 #define RETENTION_THRESHOLD 16384
@@ -333,17 +333,17 @@ ThebesLayerD3D9::RenderLayer()
   float opacity[4];
   /*
    * We always upload a 4 component float, but the shader will use only the
    * first component since it's declared as a 'float'.
    */
   opacity[0] = GetOpacity();
   device()->SetPixelShaderConstantF(0, opacity, 1);
 
-  mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER);
+  mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
 
   device()->SetTexture(0, mTexture);
   device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 }
 
 void
 ThebesLayerD3D9::CleanResources()
 {