Bug 584754: Use the D3D9Ex device where available. r=vlad
authorBas Schouten <bschouten@mozilla.com>
Wed, 11 Aug 2010 01:39:45 +0200
changeset 49317 20ab6d450abcd8b74e6d5ccea26a9230c3483c17
parent 49316 abe6ec06867660da031c84eb57390c20c4c7a27d
child 49318 022b9e8492a133722db66730fceef2f4ba8c9cda
push idunknown
push userunknown
push dateunknown
reviewersvlad
bugs584754
milestone2.0b4pre
Bug 584754: Use the D3D9Ex device where available. r=vlad
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/DeviceManagerD3D9.cpp
gfx/layers/d3d9/DeviceManagerD3D9.h
gfx/layers/d3d9/ImageLayerD3D9.cpp
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -65,19 +65,27 @@ CanvasLayerD3D9::Initialize(const Data& 
     mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
     mNeedsYFlip = PR_TRUE;
   } else {
     NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 
-  device()->CreateTexture(mBounds.width, mBounds.height, 1, 0,
-                          D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
-                          getter_AddRefs(mTexture), NULL);
+  if (mD3DManager->deviceManager()->HasDynamicTextures()) {
+    device()->CreateTexture(mBounds.width, mBounds.height, 1, D3DUSAGE_DYNAMIC,
+                            D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
+                            getter_AddRefs(mTexture), NULL);    
+  } else {
+    // D3DPOOL_MANAGED is fine here since we require Dynamic Textures for D3D9Ex
+    // devices.
+    device()->CreateTexture(mBounds.width, mBounds.height, 1, 0,
+                            D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
+                            getter_AddRefs(mTexture), NULL);
+  }
 }
 
 void
 CanvasLayerD3D9::Updated(const nsIntRect& aRect)
 {
   if (!mTexture) {
     NS_WARNING("CanvasLayerD3D9::Updated called but no texture present!");
     return;
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -42,20 +42,27 @@
 #include "nsIConsoleService.h"
 #include "nsPrintfCString.h"
 
 namespace mozilla {
 namespace layers {
 
 const LPCWSTR kClassName       = L"D3D9WindowClass";
 
+#define USE_D3D9EX
+
 typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)(
   UINT SDKVersion
 );
 
+typedef HRESULT (WINAPI*Direct3DCreate9ExFunc)(
+  UINT SDKVersion,
+  IDirect3D9Ex **ppD3D
+);
+
 struct vertex {
   float x, y;
 };
 
 SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager)
   : mDeviceManager(aDeviceManager)
   , mWnd(0)
 {
@@ -166,23 +173,26 @@ SwapChainD3D9::Reset()
 {
   mSwapChain = nsnull;
 }
 
 #define HAS_CAP(a, b) (((a) & (b)) == (b))
 #define LACKS_CAP(a, b) !(((a) & (b)) == (b))
 
 DeviceManagerD3D9::DeviceManagerD3D9()
+  : mHasDynamicTextures(false)
 {
 }
 
 bool
 DeviceManagerD3D9::Init()
 {
   WNDCLASSW wc;
+  HRESULT hr;
+
   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;
@@ -193,48 +203,95 @@ DeviceManagerD3D9::Init()
                            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");
+  HMODULE d3d9 = LoadLibraryW(L"d3d9.dll");
+  Direct3DCreate9Func d3d9Create = (Direct3DCreate9Func)
+    GetProcAddress(d3d9, "Direct3DCreate9");
+  Direct3DCreate9ExFunc d3d9CreateEx = (Direct3DCreate9ExFunc)
+    GetProcAddress(d3d9, "Direct3DCreate9Ex");
   
-  if (!d3d9create) {
-    return false;
+#ifdef USE_D3D9EX
+  if (d3d9CreateEx) {
+    hr = d3d9CreateEx(D3D_SDK_VERSION, getter_AddRefs(mD3D9Ex));
+    if (SUCCEEDED(hr)) {
+      mD3D9 = mD3D9Ex;
+    }
   }
+#endif
 
-  mD3D9 = dont_AddRef(d3d9create(D3D_SDK_VERSION));
+  if (!mD3D9) {
+    if (!d3d9Create) {
+      return false;
+    }
+
+    mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION));
+
+    if (!mD3D9) {
+      return false;
+    }
+  }
 
   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 (mD3D9Ex) {
+    hr = mD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
+                                 D3DDEVTYPE_HAL,
+                                 mFocusWnd,
+                                 D3DCREATE_FPU_PRESERVE |
+                                 D3DCREATE_MULTITHREADED |
+                                 D3DCREATE_MIXED_VERTEXPROCESSING,
+                                 &pp,
+                                 NULL,
+                                 getter_AddRefs(mDeviceEx));
+    if (SUCCEEDED(hr)) {
+      mDevice = mDeviceEx;
+    }
 
-  if (FAILED(hr)) {
-    NS_WARNING("Failed to create Device for DeviceManagerD3D9.");
-    return false;
+    D3DCAPS9 caps;
+    if (mDeviceEx->GetDeviceCaps(&caps)) {
+      if (LACKS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) {
+        // XXX - Should we actually hit this we'll need a CanvasLayer that
+        // supports static D3DPOOL_DEFAULT textures.
+        NS_WARNING("D3D9Ex device not used because of lack of support for \
+                   dynamic textures. This is unexpected.");
+        mDevice = nsnull;
+        mDeviceEx = nsnull;
+      }
+    }
+  }
+
+  if (!mDevice) {
+    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));
@@ -260,19 +317,19 @@ DeviceManagerD3D9::Init()
   hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS,
                                   getter_AddRefs(mSolidColorPS));
 
   if (FAILED(hr)) {
     return false;
   }
 
   hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4,
-                                   0,
+                                   D3DUSAGE_WRITEONLY,
                                    0,
-                                   D3DPOOL_MANAGED,
+                                   D3DPOOL_DEFAULT,
                                    getter_AddRefs(mVB),
                                    NULL);
 
   if (FAILED(hr)) {
     return false;
   }
 
   vertex *vertices;
@@ -380,16 +437,37 @@ DeviceManagerD3D9::SetShaderMode(ShaderM
 }
 
 bool
 DeviceManagerD3D9::VerifyReadyForRendering()
 {
   HRESULT hr = mDevice->TestCooperativeLevel();
 
   if (SUCCEEDED(hr)) {
+    if (IsD3D9Ex()) {
+      hr = mDeviceEx->CheckDeviceState(mFocusWnd);
+      if (FAILED(hr)) {
+        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 = mDeviceEx->ResetEx(&pp, NULL);
+        // Handle D3DERR_DEVICEREMOVED!
+        if (FAILED(hr)) {
+          return false;
+        }
+      }
+    }
     return true;
   }
 
   if (hr != D3DERR_DEVICENOTRESET) {
     return false;
   }
 
   for(unsigned int i = 0; i < mThebesLayers.Length(); i++) {
@@ -468,13 +546,17 @@ DeviceManagerD3D9::VerifyCaps()
     return false;
   }
 
   if ((caps.PixelShaderVersion & 0xffff) < 0x200 ||
       (caps.VertexShaderVersion & 0xffff) < 0x200) {
     return false;
   }
 
+  if (HAS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) {
+    mHasDynamicTextures = true;
+  }
+
   return true;
 }
 
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -119,16 +119,20 @@ public:
 
   /**
    * Create a swap chain setup to work with the specified window.
    */
   already_AddRefed<SwapChainD3D9> CreateSwapChain(HWND hWnd);
 
   IDirect3DDevice9 *device() { return mDevice; }
 
+  bool IsD3D9Ex() { return mDeviceEx; }
+
+  bool HasDynamicTextures() { return mHasDynamicTextures; }
+
   enum ShaderMode {
     RGBLAYER,
     YCBCRLAYER,
     SOLIDCOLORLAYER
   };
 
   void SetShaderMode(ShaderMode aMode);
 
@@ -148,19 +152,25 @@ private:
   bool VerifyReadyForRendering();
 
   /* Array used to store all swap chains for device resets */
   nsTArray<SwapChainD3D9*> mSwapChains;
 
   /* The D3D device we use */
   nsRefPtr<IDirect3DDevice9> mDevice;
 
+  /* The D3D9Ex device - only valid on Vista+ with WDDM */
+  nsRefPtr<IDirect3DDevice9Ex> mDeviceEx;
+
   /* An instance of the D3D9 object */
   nsRefPtr<IDirect3D9> mD3D9;
 
+  /* An instance of the D3D9Ex object - only valid on Vista+ with WDDM */
+  nsRefPtr<IDirect3D9Ex> mD3D9Ex;
+
   /* 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;
@@ -174,16 +184,19 @@ private:
   /* Our vertex declaration */
   nsRefPtr<IDirect3DVertexDeclaration9> mVD;
 
   /* Our focus window - this is really a dummy window we can associate our
    * device with.
    */
   HWND mFocusWnd;
 
+  /* If this device supports dynamic textures */
+  bool mHasDynamicTextures;
+
   nsAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
    * Verifies all required device capabilities are present.
    */
   bool VerifyCaps();
 };
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -239,16 +239,17 @@ PlanarYCbCrImageD3D9::PlanarYCbCrImageD3
   , mManager(aManager)
   , mHasData(PR_FALSE)
 {
 }
 
 void
 PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData)
 {
+  // XXX - For D3D9Ex we really should just copy to systemmem surfaces here.
   // For now, we copy the data
   int width_shift = 0;
   int height_shift = 0;
   if (aData.mYSize.width == aData.mCbCrSize.width &&
       aData.mYSize.height == aData.mCbCrSize.height) {
      // YV24 format
      width_shift = 0;
      height_shift = 0;
@@ -304,86 +305,126 @@ PlanarYCbCrImageD3D9::SetData(const Plan
   mHasData = PR_TRUE;
 }
 
 void
 PlanarYCbCrImageD3D9::AllocateTextures()
 {
 
 
-  D3DLOCKED_RECT lockrect;
+  D3DLOCKED_RECT lockrectY;
+  D3DLOCKED_RECT lockrectCb;
+  D3DLOCKED_RECT lockrectCr;
   PRUint8* src;
   PRUint8* dest;
-  //XXX: ensure correct usage flags
-  mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
-                          1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
-                          getter_AddRefs(mYTexture), NULL);
+
+  nsRefPtr<IDirect3DSurface9> tmpSurfaceY;
+  nsRefPtr<IDirect3DSurface9> tmpSurfaceCb;
+  nsRefPtr<IDirect3DSurface9> tmpSurfaceCr;
 
+  if (mManager->deviceManager()->IsD3D9Ex()) {
+    // D3D9Ex does not support the managed pool, could use dynamic textures
+    // here. But since an Image is immutable static textures are probably a
+    // better idea.
+    mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
+                            getter_AddRefs(mYTexture), NULL);
+    mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
+                            getter_AddRefs(mCbTexture), NULL);
+    mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
+                            getter_AddRefs(mCrTexture), NULL);
+    mManager->device()->CreateOffscreenPlainSurface(mData.mYSize.width,
+                                                    mData.mYSize.height,
+                                                    D3DFMT_L8,
+                                                    D3DPOOL_SYSTEMMEM,
+                                                    getter_AddRefs(tmpSurfaceY),
+                                                    NULL);
+    mManager->device()->CreateOffscreenPlainSurface(mData.mCbCrSize.width,
+                                                    mData.mCbCrSize.height,
+                                                    D3DFMT_L8,
+                                                    D3DPOOL_SYSTEMMEM,
+                                                    getter_AddRefs(tmpSurfaceCb),
+                                                    NULL);
+    mManager->device()->CreateOffscreenPlainSurface(mData.mCbCrSize.width,
+                                                    mData.mCbCrSize.height,
+                                                    D3DFMT_L8,
+                                                    D3DPOOL_SYSTEMMEM,
+                                                    getter_AddRefs(tmpSurfaceCr),
+                                                    NULL);
+    tmpSurfaceY->LockRect(&lockrectY, NULL, 0);
+    tmpSurfaceCb->LockRect(&lockrectCb, NULL, 0);
+    tmpSurfaceCr->LockRect(&lockrectCr, NULL, 0);
+  } else {
+    mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
+                            getter_AddRefs(mYTexture), NULL);
+    mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
+                            getter_AddRefs(mCbTexture), NULL);
+    mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
+                            1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
+                            getter_AddRefs(mCrTexture), NULL);
 
-  /* lock the entire texture */
-  mYTexture->LockRect(0, &lockrect, NULL, 0);
+    /* lock the entire texture */
+    mYTexture->LockRect(0, &lockrectY, NULL, 0);
+    mCbTexture->LockRect(0, &lockrectCb, NULL, 0);
+    mCrTexture->LockRect(0, &lockrectCr, NULL, 0);
+  }
 
   src  = mData.mYChannel;
   //FIX cast
-  dest = (PRUint8*)lockrect.pBits;
+  dest = (PRUint8*)lockrectY.pBits;
 
   // copy over data
   for (int h=0; h<mData.mYSize.height; h++) {
     memcpy(dest, src, mData.mYSize.width);
-    dest += lockrect.Pitch;
+    dest += lockrectY.Pitch;
     src += mData.mYStride;
   }
 
-  mYTexture->UnlockRect(0);
-
-  //XXX: ensure correct usage flags
-  mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
-                          1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
-                          getter_AddRefs(mCbTexture), NULL);
-
-
-  /* lock the entire texture */
-  mCbTexture->LockRect(0, &lockrect, NULL, 0);
-
   src  = mData.mCbChannel;
   //FIX cast
-  dest = (PRUint8*)lockrect.pBits;
+  dest = (PRUint8*)lockrectCb.pBits;
 
   // copy over data
   for (int h=0; h<mData.mCbCrSize.height; h++) {
     memcpy(dest, src, mData.mCbCrSize.width);
-    dest += lockrect.Pitch;
+    dest += lockrectCb.Pitch;
     src += mData.mCbCrStride;
   }
 
-  mCbTexture->UnlockRect(0);
-
-
-  //XXX: ensure correct usage flags
-  mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
-                          1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
-                          getter_AddRefs(mCrTexture), NULL);
-
-
-  /* lock the entire texture */
-  mCrTexture->LockRect(0, &lockrect, NULL, 0);
-
   src  = mData.mCrChannel;
   //FIX cast
-  dest = (PRUint8*)lockrect.pBits;
+  dest = (PRUint8*)lockrectCr.pBits;
 
   // copy over data
   for (int h=0; h<mData.mCbCrSize.height; h++) {
     memcpy(dest, src, mData.mCbCrSize.width);
-    dest += lockrect.Pitch;
+    dest += lockrectCr.Pitch;
     src += mData.mCbCrStride;
   }
 
-  mCrTexture->UnlockRect(0);
-
+  if (mManager->deviceManager()->IsD3D9Ex()) {
+    tmpSurfaceY->UnlockRect();
+    tmpSurfaceCb->UnlockRect();
+    tmpSurfaceCr->UnlockRect();
+    nsRefPtr<IDirect3DSurface9> dstSurface;
+    mYTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+    mManager->device()->UpdateSurface(tmpSurfaceY, NULL, dstSurface, NULL);
+    mCbTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+    mManager->device()->UpdateSurface(tmpSurfaceCb, NULL, dstSurface, NULL);
+    mCrTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+    mManager->device()->UpdateSurface(tmpSurfaceCr, NULL, dstSurface, NULL);
+  } else {
+    mYTexture->UnlockRect(0);
+    mCbTexture->UnlockRect(0);
+    mCrTexture->UnlockRect(0);
+  }
 }
 
 void
 PlanarYCbCrImageD3D9::FreeTextures()
 {
 }
 
 already_AddRefed<gfxASurface>
@@ -421,41 +462,59 @@ CairoImageD3D9::SetData(const CairoImage
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32);
 
   nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
 
   context->SetSource(aData.mSurface);
   context->Paint();
 
-  //XXX: make sure we're using the correct usage flags
-  mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height,
-                  1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
-                  getter_AddRefs(mTexture), NULL);
-
-  D3DLOCKED_RECT lockrect;
-  /* lock the entire texture */
-  mTexture->LockRect(0, &lockrect, NULL, 0);
-
-  PRUint8* src  = imageSurface->Data();
-  //FIX cast
-  PRUint8* dest = (PRUint8*)lockrect.pBits;
+  if (mManager->deviceManager()->IsD3D9Ex()) {
+    // D3D9Ex doesn't support managed textures. We could use dynamic textures
+    // here but since Images are immutable that probably isn't such a great
+    // idea.
+    mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height,
+                    1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
+                    getter_AddRefs(mTexture), NULL);
+    nsRefPtr<IDirect3DSurface9> surface;
+    mManager->device()->CreateOffscreenPlainSurface(aData.mSize.width,
+                                                    aData.mSize.height,
+                                                    D3DFMT_A8R8G8B8,
+                                                    D3DPOOL_SYSTEMMEM,
+                                                    getter_AddRefs(surface),
+                                                    NULL);
+    D3DLOCKED_RECT lockedRect;
+    surface->LockRect(&lockedRect, NULL, 0);
+    for (int y = 0; y < aData.mSize.height; y++) {
+      memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
+             imageSurface->Data() + imageSurface->Stride() * y,
+             aData.mSize.width * 4);
+    }
+    surface->UnlockRect();
+    nsRefPtr<IDirect3DSurface9> dstSurface;
+    mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+    mManager->device()->UpdateSurface(surface, NULL, dstSurface, NULL);
+  } else {
+    mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height,
+                    1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
+                    getter_AddRefs(mTexture), NULL);
+    D3DLOCKED_RECT lockrect;
+    /* lock the entire texture */
+    mTexture->LockRect(0, &lockrect, NULL, 0);
 
-  // copy over data. If we don't need to do any swaping we can
-  // use memcpy
-  for (int i=0; i<aData.mSize.width*aData.mSize.height; i++) {
-    dest[0] = src[0];
-    dest[1] = src[1];
-    dest[2] = src[2];
-    dest[3] = src[3];
-    dest += 4;
-    src += 4;
+    // copy over data. If we don't need to do any swaping we can
+    // use memcpy
+    for (int y = 0; y < aData.mSize.height; y++) {
+      memcpy((char*)lockrect.pBits + lockrect.Pitch * y,
+             imageSurface->Data() + imageSurface->Stride() * y,
+             aData.mSize.width * 4);
+    }
+
+    mTexture->UnlockRect(0);
   }
-
-  mTexture->UnlockRect(0);
 }
 
 already_AddRefed<gfxASurface>
 CairoImageD3D9::GetAsSurface()
 {
   return nsnull;
 }