Bug 611595 - Prevent a crash when D3D9 texture creation fails because the screen is locked. In CairoImageD3D9::SetData, save the surface as a member. Try to create the texture immediately, but also try to create the texture again when painting if it failed the first time. r=bas a=blocker-topcrash
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 18 Nov 2010 13:47:59 -0500
changeset 57896 08d030e87bb7ad6bda6838a8c85aeb4033c29f2c
parent 57895 8ec78ba9e09cce24c4f1af3c7d9c03ecf0b73126
child 57897 2e2e864a29593436480c97199a4e762c69d87f55
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbas, blocker-topcrash
bugs611595
milestone2.0b8pre
Bug 611595 - Prevent a crash when D3D9 texture creation fails because the screen is locked. In CairoImageD3D9::SetData, save the surface as a member. Try to create the texture immediately, but also try to create the texture again when painting if it failed the first time. r=bas a=blocker-topcrash
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/ImageLayerD3D9.h
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -99,17 +99,17 @@ ImageContainerD3D9::GetCurrentAsSurface(
     PlanarYCbCrImageD3D9 *yuvImage =
       static_cast<PlanarYCbCrImageD3D9*>(mActiveImage.get());
     if (yuvImage->HasData()) {
       *aSize = yuvImage->mSize;
     }
   } else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImageD3D9 *cairoImage =
       static_cast<CairoImageD3D9*>(mActiveImage.get());
-    *aSize = cairoImage->mSize;
+    *aSize = cairoImage->GetSize();
   }
 
   return static_cast<ImageD3D9*>(mActiveImage->GetImplData())->GetAsSurface();
 }
 
 gfxIntSize
 ImageContainerD3D9::GetCurrentSize()
 {
@@ -123,17 +123,17 @@ ImageContainerD3D9::GetCurrentSize()
     if (!yuvImage->HasData()) {
       return gfxIntSize(0,0);
     }
     return yuvImage->mSize;
 
   } else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImageD3D9 *cairoImage =
       static_cast<CairoImageD3D9*>(mActiveImage.get());
-    return cairoImage->mSize;
+    return cairoImage->GetSize();
   }
 
   return gfxIntSize(0,0);
 }
 
 PRBool
 ImageContainerD3D9::SetLayerManager(LayerManager *aManager)
 {
@@ -203,25 +203,25 @@ ImageLayerD3D9::RenderLayer()
   } else if (image->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImageD3D9 *cairoImage =
       static_cast<CairoImageD3D9*>(image.get());
 
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(0,
                                                           0,
-                                                          cairoImage->mSize.width,
-                                                          cairoImage->mSize.height),
+                                                          cairoImage->GetSize().width,
+                                                          cairoImage->GetSize().height),
                                        1);
 
     SetShaderTransformAndOpacity();
 
     mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
-    device()->SetTexture(0, cairoImage->mTexture);
+    device()->SetTexture(0, cairoImage->GetOrCreateTexture());
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
 PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9(mozilla::layers::LayerManagerD3D9* aManager)
   : PlanarYCbCrImage(static_cast<ImageD3D9*>(this))
   , mManager(aManager)
   , mHasData(PR_FALSE)
@@ -449,68 +449,97 @@ PlanarYCbCrImageD3D9::GetAsSurface()
 CairoImageD3D9::~CairoImageD3D9()
 {
 }
 
 void
 CairoImageD3D9::SetData(const CairoImage::Data &aData)
 {
   mSize = aData.mSize;
+  mCachedSurface = aData.mSurface;
+  mTexture = NULL;
+
+  // Try to upload the surface immediately, so that we don't block the
+  // rendering pipeline at paint time.
+  (void) GetOrCreateTexture();
+}
+
+IDirect3DTexture9*
+CairoImageD3D9::GetOrCreateTexture()
+{
+  if (mTexture)
+    return mTexture;
 
   nsRefPtr<gfxImageSurface> imageSurface =
-    new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32);
+    new gfxImageSurface(mSize, gfxASurface::ImageFormatARGB32);
 
   nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
 
-  context->SetSource(aData.mSurface);
+  context->SetSource(mCachedSurface);
   context->Paint();
 
   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);
+    if (FAILED(mManager->device()->
+               CreateTexture(mSize.width, mSize.height,
+                             1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
+                             getter_AddRefs(mTexture), NULL)))
+      return NULL;
+
     nsRefPtr<IDirect3DSurface9> surface;
-    mManager->device()->CreateOffscreenPlainSurface(aData.mSize.width,
-                                                    aData.mSize.height,
-                                                    D3DFMT_A8R8G8B8,
-                                                    D3DPOOL_SYSTEMMEM,
-                                                    getter_AddRefs(surface),
-                                                    NULL);
+    if (FAILED(mManager->device()->
+               CreateOffscreenPlainSurface(mSize.width,
+                                           mSize.height,
+                                           D3DFMT_A8R8G8B8,
+                                           D3DPOOL_SYSTEMMEM,
+                                           getter_AddRefs(surface),
+                                           NULL))) {
+      mTexture = NULL;
+      return NULL;
+    }
+
     D3DLOCKED_RECT lockedRect;
     surface->LockRect(&lockedRect, NULL, 0);
-    for (int y = 0; y < aData.mSize.height; y++) {
+    for (int y = 0; y < mSize.height; y++) {
       memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
              imageSurface->Data() + imageSurface->Stride() * y,
-             aData.mSize.width * 4);
+             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);
+    if (FAILED(mManager->device()->
+               CreateTexture(mSize.width, mSize.height,
+                             1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
+                             getter_AddRefs(mTexture), NULL)))
+      return 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 y = 0; y < aData.mSize.height; y++) {
+    for (int y = 0; y < mSize.height; y++) {
       memcpy((char*)lockrect.pBits + lockrect.Pitch * y,
              imageSurface->Data() + imageSurface->Stride() * y,
-             aData.mSize.width * 4);
+             mSize.width * 4);
     }
 
     mTexture->UnlockRect(0);
   }
+
+  NS_ASSERTION(mTexture, "Should have succeeded by now.");
+  // Release our no-longer-needed mCachedSurface
+  mCachedSurface = NULL;
+  return mTexture;
 }
 
 already_AddRefed<gfxASurface>
 CairoImageD3D9::GetAsSurface()
 {
   return nsnull;
 }
 
--- a/gfx/layers/d3d9/ImageLayerD3D9.h
+++ b/gfx/layers/d3d9/ImageLayerD3D9.h
@@ -143,16 +143,25 @@ public:
     , mManager(aManager)
   { }
   ~CairoImageD3D9();
 
   virtual void SetData(const Data &aData);
 
   virtual already_AddRefed<gfxASurface> GetAsSurface();
 
+  /**
+   * Uploading a texture may fail if the screen is locked. If this happens,
+   * we need to save the backing surface and retry when we are asked to paint.
+   */
+  virtual IDirect3DTexture9* GetOrCreateTexture();
+  const gfxIntSize& GetSize() { return mSize; }
+
+private:
+  gfxIntSize mSize;
+  nsRefPtr<gfxASurface> mCachedSurface;
   nsRefPtr<IDirect3DTexture9> mTexture;
-  gfxIntSize mSize;
   LayerManagerD3D9 *mManager;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_IMAGELAYERD3D9_H */