Bug 1138967 - Part 3: Add D3D11 YCbCr texture clients and upload on the client side. r=nical
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Mar 2015 10:17:13 +1300
changeset 234369 d6242b24bc47
parent 234368 215046aa1f38
child 234370 9c8be30657ca
push id28443
push usercbook@mozilla.com
push date2015-03-19 12:46 +0000
treeherdermozilla-central@0a11b73c77b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1138967
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 1138967 - Part 3: Add D3D11 YCbCr texture clients and upload on the client side. r=nical
gfx/layers/IMFYCbCrImage.cpp
gfx/layers/IMFYCbCrImage.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/moz.build
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * 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"
+
+namespace mozilla {
+namespace layers {
+
+IMFYCbCrImage::IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer)
+  : PlanarYCbCrImage(nullptr)
+  , mBuffer(aBuffer)
+  , m2DBuffer(a2DBuffer)
+{}
+
+IMFYCbCrImage::~IMFYCbCrImage()
+{
+  if (m2DBuffer) {
+    m2DBuffer->Unlock2D();
+  }
+  else {
+    mBuffer->Unlock();
+  }
+}
+
+struct AutoLockTexture
+{
+  AutoLockTexture(ID3D11Texture2D* aTexture)
+  {
+    aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mMutex));
+    HRESULT hr = mMutex->AcquireSync(0, 10000);
+    if (hr == WAIT_TIMEOUT) {
+      MOZ_CRASH();
+    }
+
+    if (FAILED(hr)) {
+      NS_WARNING("Failed to lock the texture");
+    }
+  }
+
+  ~AutoLockTexture()
+  {
+    HRESULT hr = mMutex->ReleaseSync(0);
+    if (FAILED(hr)) {
+      NS_WARNING("Failed to unlock the texture");
+    }
+  }
+
+  RefPtr<IDXGIKeyedMutex> mMutex;
+};
+
+TextureClient*
+IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
+{
+  ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11MediaDevice();
+  if (!device ||
+    aClient->GetForwarder()->GetCompositorBackendType() != LayersBackend::LAYERS_D3D11) {
+    return nullptr;
+  }
+
+  if (mTextureClient) {
+    return mTextureClient;
+  }
+
+  RefPtr<ID3D11DeviceContext> ctx;
+  device->GetImmediateContext(byRef(ctx));
+
+  CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_A8_UNORM,
+                                mData.mYSize.width, mData.mYSize.height, 1, 1);
+
+  newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+
+  RefPtr<ID3D11Texture2D> textureY;
+  HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(textureY));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  newDesc.Width = mData.mCbCrSize.width;
+  newDesc.Height = mData.mCbCrSize.height;
+
+  RefPtr<ID3D11Texture2D> textureCb;
+  hr = device->CreateTexture2D(&newDesc, nullptr, byRef(textureCb));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  RefPtr<ID3D11Texture2D> textureCr;
+  hr = device->CreateTexture2D(&newDesc, nullptr, byRef(textureCr));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+
+  {
+    AutoLockTexture lockY(textureY);
+    AutoLockTexture lockCb(textureCb);
+    AutoLockTexture lockCr(textureCr);
+
+    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());
+  mTextureClient = texClient;
+
+  return mTextureClient;
+}
+
+
+} /* layers */
+} /* mozilla */
--- a/gfx/layers/IMFYCbCrImage.h
+++ b/gfx/layers/IMFYCbCrImage.h
@@ -11,40 +11,31 @@
 #include "Mfidl.h"
 
 namespace mozilla {
 namespace layers {
 
 class IMFYCbCrImage : public PlanarYCbCrImage
 {
 public:
-  IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer)
-    : PlanarYCbCrImage(nullptr)
-    , mBuffer(aBuffer)
-    , m2DBuffer(a2DBuffer)
-  {}
+  IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer);
 
   virtual bool IsValid() { return true; }
 
+  virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
+
 protected:
   virtual uint8_t* AllocateBuffer(uint32_t aSize) MOZ_OVERRIDE {
     MOZ_CRASH("Can't do manual allocations with IMFYCbCrImage");
     return nullptr;
   }
 
-  ~IMFYCbCrImage()
-  {
-    if (m2DBuffer) {
-      m2DBuffer->Unlock2D();
-    }
-    else {
-      mBuffer->Unlock();
-    }
-  }
+  ~IMFYCbCrImage();
 
   RefPtr<IMFMediaBuffer> mBuffer;
   RefPtr<IMF2DBuffer> m2DBuffer;
+  RefPtr<TextureClient> mTextureClient;
 };
 
 } // namepace layers
 } // namespace mozilla
 
 #endif // GFX_D3DSURFACEIMAGE_H
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -227,16 +227,17 @@ TextureHost::Create(const SurfaceDescrip
     }
 #endif
 
 #ifdef XP_WIN
     case SurfaceDescriptor::TSurfaceDescriptorD3D9:
       return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
 
     case SurfaceDescriptor::TSurfaceDescriptorD3D10:
+    case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
       if (Compositor::GetBackend() == LayersBackend::LAYERS_D3D9) {
         return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
       } else {
         return CreateTextureHostD3D11(aDesc, aDeallocator, aFlags);
       }
 #endif
     default:
       MOZ_CRASH("Unsupported Surface type");
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -153,16 +153,21 @@ CreateTextureHostD3D11(const SurfaceDesc
       result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       result = new DXGITextureHostD3D11(aFlags,
                                         aDesc.get_SurfaceDescriptorD3D10());
       break;
     }
+    case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
+      result = new DXGIYCbCrTextureHostD3D11(aFlags,
+                                             aDesc.get_SurfaceDescriptorDXGIYCbCr());
+      break;
+    }
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type");
     }
   }
   return result;
 }
 
 TextureClientD3D11::TextureClientD3D11(ISurfaceAllocator* aAllocator,
@@ -494,16 +499,92 @@ 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)
+  : TextureClient(aAllocator, aFlags)
+  , mIsLocked(false)
+{
+  MOZ_COUNT_CTOR(DXGIYCbCrTextureClientD3D11);
+}
+
+class YCbCrKeepAliveD3D11 : public KeepAlive
+{
+public:
+  YCbCrKeepAliveD3D11(RefPtr<ID3D11Texture2D> aTextures[3])
+  {
+    mTextures[0] = aTextures[0];
+    mTextures[1] = aTextures[1];
+    mTextures[2] = aTextures[2];
+  }
+
+protected:
+  RefPtr<ID3D11Texture2D> mTextures[3];
+};
+
+DXGIYCbCrTextureClientD3D11::~DXGIYCbCrTextureClientD3D11()
+{
+  if (mTextures[0] && mActor) {
+    KeepUntilFullDeallocation(MakeUnique<YCbCrKeepAliveD3D11>(mTextures));
+  }
+  MOZ_COUNT_DTOR(DXGIYCbCrTextureClientD3D11);
+}
+
+bool
+DXGIYCbCrTextureClientD3D11::Lock(OpenMode)
+{
+  MOZ_ASSERT(!mIsLocked);
+  if (!IsValid()) {
+    return false;
+  }
+  mIsLocked = true;
+  return true;
+}
+
+void
+DXGIYCbCrTextureClientD3D11::Unlock()
+{
+  MOZ_ASSERT(mIsLocked, "Unlock called while the texture is not locked!");
+  mIsLocked = false;
+}
+
+bool
+DXGIYCbCrTextureClientD3D11::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());
+  return true;
+}
+
 DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags,
                                            const SurfaceDescriptorD3D10& aDescriptor)
   : TextureHost(aFlags)
   , mSize(aDescriptor.size())
   , mHandle(aDescriptor.handle())
   , mFormat(aDescriptor.format())
   , mIsLocked(false)
 {
@@ -574,16 +655,118 @@ TextureSource*
 DXGITextureHostD3D11::GetTextureSources()
 {
   MOZ_ASSERT(mIsLocked);
   // If Lock was successful we must have a valid TextureSource.
   MOZ_ASSERT(mTextureSource);
   return mTextureSource.get();
 }
 
+DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
+  const SurfaceDescriptorDXGIYCbCr& aDescriptor)
+  : TextureHost(aFlags)
+  , mSize(aDescriptor.size())
+  , mIsLocked(false)
+{
+  mHandles[0] = aDescriptor.handleY();
+  mHandles[1] = aDescriptor.handleCb();
+  mHandles[2] = aDescriptor.handleCr();
+}
+
+bool
+DXGIYCbCrTextureHostD3D11::OpenSharedHandle()
+{
+  if (!GetDevice()) {
+    return false;
+  }
+
+  HRESULT hr = GetDevice()->OpenSharedResource((HANDLE)mHandles[0],
+                                               __uuidof(ID3D11Texture2D),
+                                               (void**)(ID3D11Texture2D**)byRef(mTextures[0]));
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to open shared texture for Y Plane");
+    return false;
+  }
+
+  hr = GetDevice()->OpenSharedResource((HANDLE)mHandles[1],
+                                       __uuidof(ID3D11Texture2D),
+                                       (void**)(ID3D11Texture2D**)byRef(mTextures[1]));
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to open shared texture for Cb Plane");
+    return false;
+  }
+
+  hr = GetDevice()->OpenSharedResource((HANDLE)mHandles[2],
+                                       __uuidof(ID3D11Texture2D),
+                                       (void**)(ID3D11Texture2D**)byRef(mTextures[2]));
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to open shared texture for Cr Plane");
+    return false;
+  }
+
+  return true;
+}
+
+ID3D11Device*
+DXGIYCbCrTextureHostD3D11::GetDevice()
+{
+  return gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
+}
+
+void
+DXGIYCbCrTextureHostD3D11::SetCompositor(Compositor* aCompositor)
+{
+  mCompositor = static_cast<CompositorD3D11*>(aCompositor);
+}
+
+bool
+DXGIYCbCrTextureHostD3D11::Lock()
+{
+  if (!GetDevice()) {
+    NS_WARNING("trying to lock a TextureHost without a D3D device");
+    return false;
+  }
+  if (!mTextureSources[0]) {
+    if (!mTextures[0] && !OpenSharedHandle()) {
+      return false;
+    }
+
+    mTextureSources[0] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[0]);
+    mTextureSources[1] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[1]);
+    mTextureSources[2] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[2]);
+    mTextureSources[0]->SetNextSibling(mTextureSources[1]);
+    mTextureSources[1]->SetNextSibling(mTextureSources[2]);
+  }
+
+  mIsLocked = LockD3DTexture(mTextureSources[0]->GetD3D11Texture()) &&
+              LockD3DTexture(mTextureSources[1]->GetD3D11Texture()) &&
+              LockD3DTexture(mTextureSources[2]->GetD3D11Texture());
+
+  return mIsLocked;
+}
+
+void
+DXGIYCbCrTextureHostD3D11::Unlock()
+{
+  MOZ_ASSERT(mIsLocked);
+  UnlockD3DTexture(mTextureSources[0]->GetD3D11Texture());
+  UnlockD3DTexture(mTextureSources[1]->GetD3D11Texture());
+  UnlockD3DTexture(mTextureSources[2]->GetD3D11Texture());
+  mIsLocked = false;
+}
+
+TextureSource*
+DXGIYCbCrTextureHostD3D11::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();
+}
+
 bool
 DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
                                nsIntRegion* aDestRegion,
                                IntPoint* aSrcOffset)
 {
   // Incremental update with a source offset is only used on Mac so it is not
   // clear that we ever will need to support it for D3D.
   MOZ_ASSERT(!aSrcOffset);
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -73,16 +73,69 @@ protected:
   RefPtr<ID3D11Texture2D> mTexture;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
   bool mNeedsClear;
   bool mNeedsClearWhite;
 };
 
+class DXGIYCbCrTextureClientD3D11 : public TextureClient
+{
+public:
+  DXGIYCbCrTextureClientD3D11(ISurfaceAllocator* aAllocator,
+                              TextureFlags aFlags);
+
+  virtual ~DXGIYCbCrTextureClientD3D11();
+
+  // TextureClient
+
+  virtual bool IsAllocated() const MOZ_OVERRIDE{ return !!mTextures[0]; }
+
+  virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual bool IsLocked() const MOZ_OVERRIDE{ return mIsLocked; }
+
+  virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
+
+  void InitWith(ID3D11Texture2D* aTextureY,
+                ID3D11Texture2D* aTextureCb,
+                ID3D11Texture2D* aTextureCr,
+                const gfx::IntSize& aSize)
+  {
+    MOZ_ASSERT(aTextureY && aTextureCb && aTextureCr);
+    MOZ_ASSERT(!mTextures[0]);
+    mTextures[0] = aTextureY;
+    mTextures[1] = aTextureCb;
+    mTextures[2] = aTextureCr;
+    mSize = aSize;
+  }
+
+  virtual gfx::IntSize GetSize() const
+  {
+    return mSize;
+  }
+
+  virtual bool HasInternalBuffer() const MOZ_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 MOZ_OVERRIDE{ return nullptr; }
+
+private:
+  RefPtr<ID3D11Texture2D> mTextures[3];
+  gfx::IntSize mSize;
+  bool mIsLocked;
+};
+
+
 /**
  * TextureSource that provides with the necessary APIs to be composited by a
  * CompositorD3D11.
  */
 class TextureSourceD3D11
 {
 public:
   TextureSourceD3D11() {}
@@ -208,16 +261,55 @@ protected:
   RefPtr<DataTextureSourceD3D11> mTextureSource;
   RefPtr<CompositorD3D11> mCompositor;
   gfx::IntSize mSize;
   WindowsHandle mHandle;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
 };
 
+class DXGIYCbCrTextureHostD3D11 : public TextureHost
+{
+public:
+  DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
+                            const SurfaceDescriptorDXGIYCbCr& aDescriptor);
+
+  virtual TextureSource* GetTextureSources() MOZ_OVERRIDE;
+
+  virtual void DeallocateDeviceData() MOZ_OVERRIDE{}
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE{ return gfx::SurfaceFormat::YUV; }
+
+  virtual bool Lock() MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE{ return mSize; }
+
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
+  {
+    return nullptr;
+  }
+
+protected:
+  ID3D11Device* GetDevice();
+
+  bool OpenSharedHandle();
+
+  RefPtr<ID3D11Texture2D> mTextures[3];
+  RefPtr<DataTextureSourceD3D11> mTextureSources[3];
+
+  RefPtr<CompositorD3D11> mCompositor;
+  gfx::IntSize mSize;
+  WindowsHandle mHandles[3];
+  bool mIsLocked;
+};
+
 class CompositingRenderTargetD3D11 : public CompositingRenderTarget,
                                      public TextureSourceD3D11
 {
 public:
   CompositingRenderTargetD3D11(ID3D11Texture2D* aTexture,
                                const gfx::IntPoint& aOrigin);
 
   virtual TextureSourceD3D11* AsSourceD3D11() MOZ_OVERRIDE { return this; }
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -45,16 +45,23 @@ struct SurfaceDescriptorDIB {
 };
 
 struct SurfaceDescriptorD3D10 {
   WindowsHandle handle;
   SurfaceFormat format;
   IntSize size;
 };
 
+struct SurfaceDescriptorDXGIYCbCr {
+  WindowsHandle handleY;
+  WindowsHandle handleCb;
+  WindowsHandle handleCr;
+  IntSize size;
+};
+
 struct SurfaceDescriptorMacIOSurface {
   uint32_t surface;
   double scaleFactor;
   bool isOpaque;
 };
 
 struct SurfaceTextureDescriptor {
   uintptr_t surfTex;
@@ -99,16 +106,17 @@ struct SurfaceDescriptorShmem {
 };
 
 union SurfaceDescriptor {
   SurfaceDescriptorShmem;
   SurfaceDescriptorMemory;
   SurfaceDescriptorD3D9;
   SurfaceDescriptorDIB;
   SurfaceDescriptorD3D10;
+  SurfaceDescriptorDXGIYCbCr;
   SurfaceDescriptorX11;
   SurfaceTextureDescriptor;
   EGLImageDescriptor;
   SurfaceDescriptorMacIOSurface;
   NewSurfaceDescriptorGralloc;
   SharedSurfaceDescriptor;
   null_t;
 };
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -43,16 +43,17 @@ EXPORTS += [
     'protobuf/LayerScopePacket.pb.h',
     'ReadbackLayer.h',
     'TiledLayerBuffer.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     UNIFIED_SOURCES += [
         'D3D9SurfaceImage.cpp',
+        'IMFYCbCrImage.cpp',
         'TextureDIB.cpp',
     ]
     EXPORTS.mozilla.layers += [
         'TextureDIB.h',
     ]
     if CONFIG['MOZ_ENABLE_D3D9_LAYER']:
         EXPORTS += [
             'd3d9/DeviceManagerD3D9.h',
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1577,16 +1577,29 @@ gfxWindowsPlatform::GetD3D11ContentDevic
     return mD3D11ContentDevice;
   }
 
   InitD3D11Devices();
 
   return mD3D11ContentDevice;
 }
 
+ID3D11Device*
+gfxWindowsPlatform::GetD3D11MediaDevice()
+{
+  if (mD3D11DeviceInitialized) {
+    return mD3D11MediaDevice;
+  }
+
+  InitD3D11Devices();
+
+  return mD3D11MediaDevice;
+}
+
+
 ReadbackManagerD3D11*
 gfxWindowsPlatform::GetReadbackManager()
 {
   if (!mD3D11ReadbackManager) {
     mD3D11ReadbackManager = new ReadbackManagerD3D11();
   }
 
   return mD3D11ReadbackManager;
@@ -1937,16 +1950,35 @@ gfxWindowsPlatform::InitD3D11Devices()
       return;
     }
 
     mD3D11ContentDevice->SetExceptionMode(0);
 
     Factory::SetDirect3D11Device(mD3D11ContentDevice);
   }
 
+  if (!useWARP || gfxPrefs::LayersD3D11ForceWARP()) {
+    hr = E_INVALIDARG;
+    MOZ_SEH_TRY{
+      hr = d3d11CreateDevice(adapter, useWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN, nullptr,
+                             D3D11_CREATE_DEVICE_BGRA_SUPPORT,
+                             featureLevels.Elements(), featureLevels.Length(),
+                             D3D11_SDK_VERSION, byRef(mD3D11MediaDevice), nullptr, nullptr);
+    } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+      mD3D11MediaDevice = nullptr;
+    }
+
+    if (FAILED(hr)) {
+      d3d11Module.disown();
+      return;
+    }
+
+    mD3D11MediaDevice->SetExceptionMode(0);
+  }
+
   // We leak these everywhere and we need them our entire runtime anyway, let's
   // leak it here as well.
   d3d11Module.disown();
 }
 
 static bool
 DwmCompositionEnabled()
 {
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -241,16 +241,17 @@ public:
     mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
     IDirect3DDevice9* GetD3D9Device();
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
 #endif
     ID3D11Device *GetD3D11Device();
     ID3D11Device *GetD3D11ContentDevice();
+    ID3D11Device *GetD3D11MediaDevice();
 
     mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
 
     static bool IsOptimus();
 
     bool IsWARP() { return mIsWARP; }
 
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() MOZ_OVERRIDE;
@@ -281,16 +282,17 @@ private:
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
+    mozilla::RefPtr<ID3D11Device> mD3D11MediaDevice;
     bool mD3D11DeviceInitialized;
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
     bool mIsWARP;
 
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 };
 
 bool DoesD3D11TextureSharingWork(ID3D11Device *device);