Bug 1138967 - Part 3: Add D3D11 YCbCr texture clients and upload on the client side. r=nical, a=lmandel
💩💩 backed out by 2592523e1eb0 💩 💩
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Mar 2015 10:17:13 +1300
changeset 250451 0c23dcbc6bf7
parent 250450 07e266d45703
child 250452 02b9c74353ad
push id4591
push userryanvm@gmail.com
push date2015-03-19 18:13 +0000
treeherdermozilla-beta@9b7aa96d0e11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical, lmandel
bugs1138967
milestone37.0
Bug 1138967 - Part 3: Add D3D11 YCbCr texture clients and upload on the client side. r=nical, a=lmandel
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,
@@ -491,16 +496,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)
 {
@@ -571,16 +652,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
@@ -40,16 +40,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
@@ -1587,16 +1587,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;
@@ -1947,13 +1960,32 @@ 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();
 }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -245,16 +245,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; }
 
     static mozilla::Atomic<size_t> sD3D11MemoryUsed;
@@ -284,16 +285,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);