Bug 593268 - Part 3: Implement CreateOptimalSurface for D3D9 layers and use interop in CanvasLayerD3D9. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Wed, 08 Sep 2010 05:27:36 +0200
changeset 52175 9f8e55caeca1b6a84f123f02802f6dd1e830ec73
parent 52174 7ad078323b5259c54cb6009a8b85d328acd8ffd6
child 52176 c1bb86ae655a3a029dbccde40132393ea46a808a
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjrmuizel
bugs593268
milestone2.0b6pre
Bug 593268 - Part 3: Implement CreateOptimalSurface for D3D9 layers and use interop in CanvasLayerD3D9. r=jrmuizel
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/CanvasLayerD3D9.h
gfx/layers/d3d9/LayerManagerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.h
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "CanvasLayerD3D9.h"
 
 #include "gfxImageSurface.h"
 #include "gfxWindowsSurface.h"
+#include "gfxWindowsPlatform.h"
 
 namespace mozilla {
 namespace layers {
 
 CanvasLayerD3D9::~CanvasLayerD3D9()
 {
 }
 
@@ -66,16 +67,27 @@ CanvasLayerD3D9::Initialize(const Data& 
     mDataIsPremultiplied = aData.mGLBufferIsPremultiplied;
     mNeedsYFlip = PR_TRUE;
   } else {
     NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 
+  if (mSurface && mSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
+    void *data = mSurface->GetData(&gKeyD3D9Texture);
+    if (data) {
+      mTexture = static_cast<IDirect3DTexture9*>(data);
+      mIsInteropTexture = true;
+      return;
+    }
+  }
+
+  mIsInteropTexture = false;
+
   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,
@@ -87,16 +99,24 @@ CanvasLayerD3D9::Initialize(const Data& 
 void
 CanvasLayerD3D9::Updated(const nsIntRect& aRect)
 {
   if (!mTexture) {
     NS_WARNING("CanvasLayerD3D9::Updated called but no texture present!");
     return;
   }
 
+#ifdef CAIRO_HAS_D2D_SURFACE
+  if (mIsInteropTexture) {
+    mSurface->Flush();
+    cairo_d2d_finish_device(gfxWindowsPlatform::GetPlatform()->GetD2DDevice());
+    return;
+  }
+#endif
+
   if (mGLContext) {
     // WebGL reads entire surface.
     D3DLOCKED_RECT r;
     mTexture->LockRect(0, &r, NULL, 0);
 
     PRUint8 *destination;
     if (r.Pitch != mBounds.width * 4) {
       destination = new PRUint8[mBounds.width * mBounds.height * 4];
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -69,16 +69,19 @@ public:
 
   // LayerD3D9 implementation
   virtual Layer* GetLayer();
   virtual void RenderLayer();
 
 protected:
   typedef mozilla::gl::GLContext GLContext;
 
+  // Indicates whether our texture was obtained through D2D interop.
+  bool mIsInteropTexture;
+
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
 
   PRUint32 mCanvasFramebuffer;
 
   nsRefPtr<IDirect3DTexture9> mTexture;
 
   nsIntRect mBounds;
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -39,16 +39,20 @@
 
 #include "ThebesLayerD3D9.h"
 #include "ContainerLayerD3D9.h"
 #include "ImageLayerD3D9.h"
 #include "ColorLayerD3D9.h"
 #include "CanvasLayerD3D9.h"
 #include "nsIServiceManager.h"
 #include "nsIPrefService.h"
+#include "gfxWindowsPlatform.h"
+#ifdef CAIRO_HAS_D2D_SURFACE
+#include "gfxD2DSurface.h"
+#endif
 
 namespace mozilla {
 namespace layers {
 
 DeviceManagerD3D9 *LayerManagerD3D9::mDeviceManager = nsnull;
 
 LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget)
   : mIs3DEnabled(PR_FALSE)
@@ -179,16 +183,61 @@ LayerManagerD3D9::CreateCanvasLayer()
 
 already_AddRefed<ImageContainer>
 LayerManagerD3D9::CreateImageContainer()
 {
   nsRefPtr<ImageContainer> container = new ImageContainerD3D9(this);
   return container.forget();
 }
 
+cairo_user_data_key_t gKeyD3D9Texture;
+
+void ReleaseTexture(void *texture)
+{
+  static_cast<IDirect3DTexture9*>(texture)->Release();
+}
+
+already_AddRefed<gfxASurface>
+LayerManagerD3D9::CreateOptimalSurface(const gfxIntSize &aSize,
+                                   gfxASurface::gfxImageFormat aFormat)
+{
+#ifdef CAIRO_HAS_D2D_SURFACE
+  if ((aFormat != gfxASurface::ImageFormatRGB24 &&
+       aFormat != gfxASurface::ImageFormatARGB32) ||
+      gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
+        gfxWindowsPlatform::RENDER_DIRECT2D ||
+      !deviceManager()->IsD3D9Ex()) {
+    return LayerManager::CreateOptimalSurface(aSize, aFormat);
+  }
+
+  nsRefPtr<IDirect3DTexture9> texture;
+  
+  HANDLE sharedHandle = 0;
+  device()->CreateTexture(aSize.width, aSize.height, 1,
+                          D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                          D3DPOOL_DEFAULT, getter_AddRefs(texture), &sharedHandle);
+
+  nsRefPtr<gfxD2DSurface> surface =
+    new gfxD2DSurface(sharedHandle, aFormat == gfxASurface::ImageFormatRGB24 ?
+      gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
+
+  if (!surface || surface->CairoStatus()) {
+    return LayerManager::CreateOptimalSurface(aSize, aFormat);
+  }
+
+  surface->SetData(&gKeyD3D9Texture,
+                   texture.forget().get(),
+                   ReleaseTexture);
+
+  return surface.forget();
+#else
+  return LayerManager::CreateOptimalSurface(aSize, aFormat);
+#endif
+}
+
 void
 LayerManagerD3D9::Render()
 {
   if (!mSwapChain->PrepareForRendering()) {
     return;
   }
   deviceManager()->SetupRenderState();
 
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -46,16 +46,18 @@
 #include "gfxContext.h"
 #include "nsIWidget.h"
 
 #include "DeviceManagerD3D9.h"
 
 namespace mozilla {
 namespace layers {
 
+extern cairo_user_data_key_t gKeyD3D9Texture;
+
 class LayerD3D9;
 class ThebesLayerD3D9;
 
 /*
  * This is the LayerManager used for Direct3D 9. For now this will render on
  * the main thread.
  */
 class THEBES_API LayerManagerD3D9 : public LayerManager {
@@ -112,16 +114,20 @@ public:
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
 
   virtual already_AddRefed<ColorLayer> CreateColorLayer();
 
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
 
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
 
+  virtual already_AddRefed<gfxASurface>
+    CreateOptimalSurface(const gfxIntSize &aSize,
+                         gfxASurface::gfxImageFormat imageFormat);
+
   virtual LayersBackend GetBackendType() { return LAYERS_D3D9; }
   virtual void GetBackendName(nsAString& name) { name.AssignLiteral("Direct3D 9"); }
 
   /*
    * Helper methods.
    */
   void SetClippingEnabled(PRBool aEnabled);