Bug 1145513 - Upload YCbCr image data on the client side when using d3d9 layers. r=nical
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 23 Mar 2015 15:13:56 +1300
changeset 235010 587c4a3c4c6b34e17823d762b6427a049f2c3353
parent 235009 5ae6881f492e129eeb3315a2ea950ab8131fcba6
child 235011 b7e5ddf82a1abe1d1b2840b86992f5653ac92676
push id57295
push usermwoodrow@mozilla.com
push dateMon, 23 Mar 2015 02:15:50 +0000
treeherdermozilla-inbound@587c4a3c4c6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1145513
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1145513 - Upload YCbCr image data on the client side when using d3d9 layers. r=nical
gfx/layers/IMFYCbCrImage.cpp
gfx/layers/IMFYCbCrImage.h
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/d3d9/TextureD3D9.cpp
gfx/layers/d3d9/TextureD3D9.h
gfx/layers/ipc/LayersSurfaces.ipdlh
--- a/gfx/layers/IMFYCbCrImage.cpp
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IMFYCbCrImage.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/layers/TextureClient.h"
+#include "d3d9.h"
 
 namespace mozilla {
 namespace layers {
 
 IMFYCbCrImage::IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer)
   : PlanarYCbCrImage(nullptr)
   , mBuffer(aBuffer)
   , m2DBuffer(a2DBuffer)
@@ -50,22 +51,171 @@ struct AutoLockTexture
     if (FAILED(hr)) {
       NS_WARNING("Failed to unlock the texture");
     }
   }
 
   RefPtr<IDXGIKeyedMutex> mMutex;
 };
 
+static TemporaryRef<IDirect3DTexture9>
+InitTextures(IDirect3DDevice9* aDevice,
+             const IntSize &aSize,
+            _D3DFORMAT aFormat,
+            RefPtr<IDirect3DSurface9>& aSurface,
+            HANDLE& aHandle,
+            D3DLOCKED_RECT& aLockedRect)
+{
+  if (!aDevice) {
+    return nullptr;
+  }
+
+  RefPtr<IDirect3DTexture9> result;
+  if (FAILED(aDevice->CreateTexture(aSize.width, aSize.height,
+                                    1, 0, aFormat, D3DPOOL_DEFAULT,
+                                    byRef(result), &aHandle))) {
+    return nullptr;
+  }
+  if (!result) {
+    return nullptr;
+  }
+
+  RefPtr<IDirect3DTexture9> tmpTexture;
+  if (FAILED(aDevice->CreateTexture(aSize.width, aSize.height,
+                                    1, 0, aFormat, D3DPOOL_SYSTEMMEM,
+                                    byRef(tmpTexture), nullptr))) {
+    return nullptr;
+  }
+  if (!tmpTexture) {
+    return nullptr;
+  }
+
+  tmpTexture->GetSurfaceLevel(0, byRef(aSurface));
+  aSurface->LockRect(&aLockedRect, nullptr, 0);
+  if (!aLockedRect.pBits) {
+    NS_WARNING("Could not lock surface");
+    return nullptr;
+  }
+
+  return result;
+}
+
+static void
+FinishTextures(IDirect3DDevice9* aDevice,
+               IDirect3DTexture9* aTexture,
+               IDirect3DSurface9* aSurface)
+{
+  if (!aDevice) {
+    return;
+  }
+
+  aSurface->UnlockRect();
+  nsRefPtr<IDirect3DSurface9> dstSurface;
+  aTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+  aDevice->UpdateSurface(aSurface, nullptr, dstSurface, nullptr);
+}
+
+static bool UploadData(IDirect3DDevice9* aDevice,
+                       RefPtr<IDirect3DTexture9>& aTexture,
+                       HANDLE& aHandle,
+                       uint8_t* aSrc,
+                       const gfx::IntSize& aSrcSize,
+                       int32_t aSrcStride)
+{
+  RefPtr<IDirect3DSurface9> surf;
+  D3DLOCKED_RECT rect;
+  aTexture = InitTextures(aDevice, aSrcSize, D3DFMT_A8, surf, aHandle, rect);
+  if (!aTexture) {
+    return false;
+  }
+
+  if (aSrcStride == rect.Pitch) {
+    memcpy(rect.pBits, aSrc, rect.Pitch * aSrcSize.height);
+  } else {
+    for (int i = 0; i < aSrcSize.height; i++) {
+      memcpy((uint8_t*)rect.pBits + i * rect.Pitch,
+             aSrc + i * aSrcStride,
+             aSrcSize.width);
+    }
+  }
+
+  FinishTextures(aDevice, aTexture, surf);
+  return true;
+}
+
+TextureClient*
+IMFYCbCrImage::GetD3D9TextureClient(CompositableClient* aClient)
+{
+  IDirect3DDevice9* device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
+
+  RefPtr<IDirect3DTexture9> textureY;
+  HANDLE shareHandleY = 0;
+  if (!UploadData(device, textureY, shareHandleY,
+                  mData.mYChannel, mData.mYSize, mData.mYStride)) {
+    return nullptr;
+  }
+
+  RefPtr<IDirect3DTexture9> textureCb;
+  HANDLE shareHandleCb = 0;
+  if (!UploadData(device, textureCb, shareHandleCb,
+                  mData.mCbChannel, mData.mCbCrSize, mData.mCbCrStride)) {
+    return nullptr;
+  }
+
+  RefPtr<IDirect3DTexture9> textureCr;
+  HANDLE shareHandleCr = 0;
+  if (!UploadData(device, textureCr, shareHandleCr,
+                  mData.mCrChannel, mData.mCbCrSize, mData.mCbCrStride)) {
+    return nullptr;
+  }
+
+  RefPtr<IDirect3DQuery9> query;
+  HRESULT hr = device->CreateQuery(D3DQUERYTYPE_EVENT, byRef(query));
+  hr = query->Issue(D3DISSUE_END);
+
+  int iterations = 0;
+  bool valid = false;
+  while (iterations < 10) {
+    HRESULT hr = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
+    if (hr == S_FALSE) {
+      Sleep(1);
+      iterations++;
+      continue;
+    }
+    if (hr == S_OK) {
+      valid = true;
+    }
+    break;
+  }
+
+  if (!valid) {
+    return nullptr;
+  }
+
+  RefPtr<DXGIYCbCrTextureClient> texClient =
+    new DXGIYCbCrTextureClient(aClient->GetForwarder(), TextureFlags::DEFAULT);
+  texClient->InitWith(textureY, textureCb, textureCr,
+                      shareHandleY, shareHandleCb, shareHandleCr,
+                      GetSize(), mData.mYSize, mData.mCbCrSize);
+  mTextureClient = texClient;
+
+  return mTextureClient;
+}
+
 TextureClient*
 IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
 {
   ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11MediaDevice();
   if (!device ||
     aClient->GetForwarder()->GetCompositorBackendType() != LayersBackend::LAYERS_D3D11) {
+
+    IDirect3DDevice9* d3d9device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
+    if (d3d9device && aClient->GetForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9) {
+      return GetD3D9TextureClient(aClient);
+    }
     return nullptr;
   }
 
   if (mTextureClient) {
     return mTextureClient;
   }
 
   RefPtr<ID3D11DeviceContext> ctx;
@@ -99,19 +249,35 @@ IMFYCbCrImage::GetTextureClient(Composit
     ctx->UpdateSubresource(textureY, 0, nullptr, mData.mYChannel,
                            mData.mYStride, mData.mYStride * mData.mYSize.height);
     ctx->UpdateSubresource(textureCb, 0, nullptr, mData.mCbChannel,
                            mData.mCbCrStride, mData.mCbCrStride * mData.mCbCrSize.height);
     ctx->UpdateSubresource(textureCr, 0, nullptr, mData.mCrChannel,
                            mData.mCbCrStride, mData.mCbCrStride * mData.mCbCrSize.height);
   }
 
-  RefPtr<DXGIYCbCrTextureClientD3D11> texClient =
-    new DXGIYCbCrTextureClientD3D11(aClient->GetForwarder(), TextureFlags::DEFAULT);
-  texClient->InitWith(textureY, textureCb, textureCr, GetSize());
+  RefPtr<IDXGIResource> resource;
+
+  HANDLE shareHandleY;
+  textureY->QueryInterface((IDXGIResource**)byRef(resource));
+  hr = resource->GetSharedHandle(&shareHandleY);
+
+  HANDLE shareHandleCb;
+  textureCb->QueryInterface((IDXGIResource**)byRef(resource));
+  hr = resource->GetSharedHandle(&shareHandleCb);
+
+  HANDLE shareHandleCr;
+  textureCr->QueryInterface((IDXGIResource**)byRef(resource));
+  hr = resource->GetSharedHandle(&shareHandleCr);
+
+  RefPtr<DXGIYCbCrTextureClient> texClient =
+    new DXGIYCbCrTextureClient(aClient->GetForwarder(), TextureFlags::DEFAULT);
+  texClient->InitWith(textureY, textureCb, textureCr,
+                      shareHandleY, shareHandleCb, shareHandleCr,
+                      GetSize(), mData.mYSize, mData.mCbCrSize);
   mTextureClient = texClient;
 
   return mTextureClient;
 }
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/IMFYCbCrImage.h
+++ b/gfx/layers/IMFYCbCrImage.h
@@ -23,16 +23,18 @@ public:
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
 
 protected:
   virtual uint8_t* AllocateBuffer(uint32_t aSize) override {
     MOZ_CRASH("Can't do manual allocations with IMFYCbCrImage");
     return nullptr;
   }
 
+  TextureClient* GetD3D9TextureClient(CompositableClient* aClient);
+
   ~IMFYCbCrImage();
 
   RefPtr<IMFMediaBuffer> mBuffer;
   RefPtr<IMF2DBuffer> m2DBuffer;
   RefPtr<TextureClient> mTextureClient;
 };
 
 } // namepace layers
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -499,89 +499,74 @@ TextureClientD3D11::ToSurfaceDescriptor(
     LOGD3D11("Error getting shared handle for texture.");
     return false;
   }
 
   aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize);
   return true;
 }
 
-DXGIYCbCrTextureClientD3D11::DXGIYCbCrTextureClientD3D11(ISurfaceAllocator* aAllocator,
-                                                         TextureFlags aFlags)
+DXGIYCbCrTextureClient::DXGIYCbCrTextureClient(ISurfaceAllocator* aAllocator,
+                                               TextureFlags aFlags)
   : TextureClient(aAllocator, aFlags)
   , mIsLocked(false)
 {
-  MOZ_COUNT_CTOR(DXGIYCbCrTextureClientD3D11);
+  MOZ_COUNT_CTOR(DXGIYCbCrTextureClient);
 }
 
 class YCbCrKeepAliveD3D11 : public KeepAlive
 {
 public:
-  YCbCrKeepAliveD3D11(RefPtr<ID3D11Texture2D> aTextures[3])
+  YCbCrKeepAliveD3D11(RefPtr<IUnknown> aTextures[3])
   {
     mTextures[0] = aTextures[0];
     mTextures[1] = aTextures[1];
     mTextures[2] = aTextures[2];
   }
 
 protected:
-  RefPtr<ID3D11Texture2D> mTextures[3];
+  RefPtr<IUnknown> mTextures[3];
 };
 
-DXGIYCbCrTextureClientD3D11::~DXGIYCbCrTextureClientD3D11()
+DXGIYCbCrTextureClient::~DXGIYCbCrTextureClient()
 {
-  if (mTextures[0] && mActor) {
-    KeepUntilFullDeallocation(MakeUnique<YCbCrKeepAliveD3D11>(mTextures));
+  if (mHoldRefs[0] && mActor) {
+    KeepUntilFullDeallocation(MakeUnique<YCbCrKeepAliveD3D11>(mHoldRefs));
   }
-  MOZ_COUNT_DTOR(DXGIYCbCrTextureClientD3D11);
+  MOZ_COUNT_DTOR(DXGIYCbCrTextureClient);
 }
 
 bool
-DXGIYCbCrTextureClientD3D11::Lock(OpenMode)
+DXGIYCbCrTextureClient::Lock(OpenMode)
 {
   MOZ_ASSERT(!mIsLocked);
   if (!IsValid()) {
     return false;
   }
   mIsLocked = true;
   return true;
 }
 
 void
-DXGIYCbCrTextureClientD3D11::Unlock()
+DXGIYCbCrTextureClient::Unlock()
 {
   MOZ_ASSERT(mIsLocked, "Unlock called while the texture is not locked!");
   mIsLocked = false;
 }
 
 bool
-DXGIYCbCrTextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
+DXGIYCbCrTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated()) {
     return false;
   }
 
-  RefPtr<IDXGIResource> resource;
-  mTextures[0]->QueryInterface((IDXGIResource**)byRef(resource));
-
-  HANDLE sharedHandleY;
-  HRESULT hr = resource->GetSharedHandle(&sharedHandleY);
-
-  mTextures[1]->QueryInterface((IDXGIResource**)byRef(resource));
-
-  HANDLE sharedHandleCb;
-  hr = resource->GetSharedHandle(&sharedHandleCb);
-
-  mTextures[2]->QueryInterface((IDXGIResource**)byRef(resource));
-
-  HANDLE sharedHandleCr;
-  hr = resource->GetSharedHandle(&sharedHandleCr);
-
-  aOutDescriptor = SurfaceDescriptorDXGIYCbCr((WindowsHandle)sharedHandleY, (WindowsHandle)sharedHandleCb, (WindowsHandle)sharedHandleCr, GetSize());
+  aOutDescriptor = SurfaceDescriptorDXGIYCbCr((WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2],
+                                              GetSize(), mSizeY, mSizeCbCr);
   return true;
 }
 
 DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags,
                                            const SurfaceDescriptorD3D10& aDescriptor)
   : TextureHost(aFlags)
   , mSize(aDescriptor.size())
   , mHandle(aDescriptor.handle())
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -73,65 +73,76 @@ protected:
   RefPtr<ID3D11Texture2D> mTexture;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
   bool mNeedsClear;
   bool mNeedsClearWhite;
 };
 
-class DXGIYCbCrTextureClientD3D11 : public TextureClient
+class DXGIYCbCrTextureClient : public TextureClient
 {
 public:
-  DXGIYCbCrTextureClientD3D11(ISurfaceAllocator* aAllocator,
-                              TextureFlags aFlags);
+  DXGIYCbCrTextureClient(ISurfaceAllocator* aAllocator,
+                         TextureFlags aFlags);
 
-  virtual ~DXGIYCbCrTextureClientD3D11();
+  virtual ~DXGIYCbCrTextureClient();
 
   // TextureClient
 
-  virtual bool IsAllocated() const override{ return !!mTextures[0]; }
+  virtual bool IsAllocated() const override{ return !!mHoldRefs[0]; }
 
   virtual bool Lock(OpenMode aOpenMode) override;
 
   virtual void Unlock() override;
 
   virtual bool IsLocked() const override{ return mIsLocked; }
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
 
-  void InitWith(ID3D11Texture2D* aTextureY,
-                ID3D11Texture2D* aTextureCb,
-                ID3D11Texture2D* aTextureCr,
-                const gfx::IntSize& aSize)
+  void InitWith(IUnknown* aTextureY,
+                IUnknown* aTextureCb,
+                IUnknown* aTextureCr,
+                HANDLE aHandleY,
+                HANDLE aHandleCb,
+                HANDLE aHandleCr,
+                const gfx::IntSize& aSize,
+                const gfx::IntSize& aSizeY,
+                const gfx::IntSize& aSizeCbCr)
   {
-    MOZ_ASSERT(aTextureY && aTextureCb && aTextureCr);
-    MOZ_ASSERT(!mTextures[0]);
-    mTextures[0] = aTextureY;
-    mTextures[1] = aTextureCb;
-    mTextures[2] = aTextureCr;
+    mHandles[0] = aHandleY;
+    mHandles[1] = aHandleCb;
+    mHandles[2] = aHandleCr;
+    mHoldRefs[0] = aTextureY;
+    mHoldRefs[1] = aTextureCb;
+    mHoldRefs[2] = aTextureCr;
     mSize = aSize;
+    mSizeY = aSizeY;
+    mSizeCbCr = aSizeCbCr;
   }
 
   virtual gfx::IntSize GetSize() const
   {
     return mSize;
   }
 
   virtual bool HasInternalBuffer() const override{ return true; }
 
     // This TextureClient should not be used in a context where we use CreateSimilar
     // (ex. component alpha) because the underlying texture data is always created by
     // an external producer.
     virtual TemporaryRef<TextureClient>
     CreateSimilar(TextureFlags, TextureAllocationFlags) const override{ return nullptr; }
 
 private:
-  RefPtr<ID3D11Texture2D> mTextures[3];
+  RefPtr<IUnknown> mHoldRefs[3];
+  HANDLE mHandles[3];
   gfx::IntSize mSize;
+  gfx::IntSize mSizeY;
+  gfx::IntSize mSizeCbCr;
   bool mIsLocked;
 };
 
 
 /**
  * TextureSource that provides with the necessary APIs to be composited by a
  * CompositorD3D11.
  */
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -61,16 +61,20 @@ CreateTextureHostD3D9(const SurfaceDescr
     case SurfaceDescriptor::TSurfaceDescriptorD3D9: {
       result = new TextureHostD3D9(aFlags, aDesc);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       result = new DXGITextureHostD3D9(aFlags, aDesc);
       break;
     }
+    case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
+      result = new DXGIYCbCrTextureHostD3D9(aFlags, aDesc.get_SurfaceDescriptorDXGIYCbCr());
+      break;
+    }
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type");
     }
   }
   return result.forget();
 }
 
 static SurfaceFormat
@@ -1027,10 +1031,92 @@ DXGITextureHostD3D9::SetCompositor(Compo
 }
 
 void
 DXGITextureHostD3D9::DeallocateDeviceData()
 {
   mTextureSource = nullptr;
 }
 
+DXGIYCbCrTextureHostD3D9::DXGIYCbCrTextureHostD3D9(TextureFlags aFlags,
+                                                   const SurfaceDescriptorDXGIYCbCr& aDescriptor)
+ : TextureHost(aFlags)
+ , mSize(aDescriptor.size())
+ , mSizeY(aDescriptor.sizeY())
+ , mSizeCbCr(aDescriptor.sizeCbCr())
+ , mIsLocked(false)
+{
+  mHandles[0] = reinterpret_cast<HANDLE>(aDescriptor.handleY());
+  mHandles[1] = reinterpret_cast<HANDLE>(aDescriptor.handleCb());
+  mHandles[2] = reinterpret_cast<HANDLE>(aDescriptor.handleCr());
+}
+
+IDirect3DDevice9*
+DXGIYCbCrTextureHostD3D9::GetDevice()
+{
+  return mCompositor ? mCompositor->device() : nullptr;
+}
+
+void
+DXGIYCbCrTextureHostD3D9::SetCompositor(Compositor* aCompositor)
+{
+  mCompositor = static_cast<CompositorD3D9*>(aCompositor);
+}
+
+bool
+DXGIYCbCrTextureHostD3D9::Lock()
+{
+  if (!GetDevice()) {
+    NS_WARNING("trying to lock a TextureHost without a D3D device");
+    return false;
+  }
+  if (!mTextureSources[0]) {
+    if (!mHandles[0]) {
+      return false;
+    }
+
+    if (FAILED(GetDevice()->CreateTexture(mSizeY.width, mSizeY.height,
+                                          1, 0, D3DFMT_A8, D3DPOOL_DEFAULT,
+                                          byRef(mTextures[0]), &mHandles[0]))) {
+      return false;
+    }
+
+    if (FAILED(GetDevice()->CreateTexture(mSizeCbCr.width, mSizeCbCr.height,
+                                          1, 0, D3DFMT_A8, D3DPOOL_DEFAULT,
+                                          byRef(mTextures[1]), &mHandles[1]))) {
+      return false;
+    }
+
+    if (FAILED(GetDevice()->CreateTexture(mSizeCbCr.width, mSizeCbCr.height,
+                                          1, 0, D3DFMT_A8, D3DPOOL_DEFAULT,
+                                          byRef(mTextures[2]), &mHandles[2]))) {
+      return false;
+    }
+
+    mTextureSources[0] = new DataTextureSourceD3D9(SurfaceFormat::A8, mSize, mCompositor, mTextures[0]);
+    mTextureSources[1] = new DataTextureSourceD3D9(SurfaceFormat::A8, mSize, mCompositor, mTextures[1]);
+    mTextureSources[2] = new DataTextureSourceD3D9(SurfaceFormat::A8, mSize, mCompositor, mTextures[2]);
+    mTextureSources[0]->SetNextSibling(mTextureSources[1]);
+    mTextureSources[1]->SetNextSibling(mTextureSources[2]);
+  }
+
+  mIsLocked = true;
+  return mIsLocked;
+}
+
+void
+DXGIYCbCrTextureHostD3D9::Unlock()
+{
+  MOZ_ASSERT(mIsLocked);
+  mIsLocked = false;
+}
+
+TextureSource*
+DXGIYCbCrTextureHostD3D9::GetTextureSources()
+{
+  MOZ_ASSERT(mIsLocked);
+  // If Lock was successful we must have a valid TextureSource.
+  MOZ_ASSERT(mTextureSources[0] && mTextureSources[1] && mTextureSources[2]);
+  return mTextureSources[0].get();
+}
+
 }
 }
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -365,16 +365,53 @@ protected:
   RefPtr<DataTextureSourceD3D9> mTextureSource;
   RefPtr<CompositorD3D9> mCompositor;
   WindowsHandle mHandle;
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   bool mIsLocked;
 };
 
+class DXGIYCbCrTextureHostD3D9 : public TextureHost
+{
+public:
+  DXGIYCbCrTextureHostD3D9(TextureFlags aFlags,
+                           const SurfaceDescriptorDXGIYCbCr& aDescriptor);
+
+  virtual TextureSource* GetTextureSources() override;
+
+  virtual void DeallocateDeviceData() override {}
+
+  virtual void SetCompositor(Compositor* aCompositor) override;
+
+  virtual gfx::SurfaceFormat GetFormat() const override { return gfx::SurfaceFormat::YUV; }
+
+  virtual bool Lock() override;
+  virtual void Unlock() override;
+  virtual gfx::IntSize GetSize() const override { return mSize; }
+
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
+  {
+    return nullptr;
+  }
+
+ protected:
+  IDirect3DDevice9* GetDevice();
+
+  HANDLE mHandles[3];
+  RefPtr<IDirect3DTexture9> mTextures[3];
+  RefPtr<DataTextureSourceD3D9> mTextureSources[3];
+
+  RefPtr<CompositorD3D9> mCompositor;
+  gfx::IntSize mSize;
+  gfx::IntSize mSizeY;
+  gfx::IntSize mSizeCbCr;
+  bool mIsLocked;
+ };
+
 class CompositingRenderTargetD3D9 : public CompositingRenderTarget,
                                     public TextureSourceD3D9
 {
 public:
   CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture,
                               SurfaceInitMode aInit,
                               const gfx::IntRect& aRect);
   // use for rendering to the main window, cannot be rendered as a texture
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -50,16 +50,18 @@ struct SurfaceDescriptorD3D10 {
   IntSize size;
 };
 
 struct SurfaceDescriptorDXGIYCbCr {
   WindowsHandle handleY;
   WindowsHandle handleCb;
   WindowsHandle handleCr;
   IntSize size;
+  IntSize sizeY;
+  IntSize sizeCbCr;
 };
 
 struct SurfaceDescriptorMacIOSurface {
   uint32_t surface;
   double scaleFactor;
   bool isOpaque;
 };