Bug 1288618 - Part 2: Allow allocating D3D9/11 Images when we don't have a recycling allocator available. r?nical draft
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 15 Sep 2016 11:50:58 +1200
changeset 413855 b5dc526eefc7632c71d202b310c4744e6b632869
parent 413854 19e2292f9cde7f6ec81aa23e9cb7b2699e4806d5
child 413856 b75ceb2470afa2675dafea59fd4b8b7df037b8cd
push id29543
push usermwoodrow@mozilla.com
push dateThu, 15 Sep 2016 02:36:28 +0000
reviewersnical
bugs1288618
milestone51.0a1
Bug 1288618 - Part 2: Allow allocating D3D9/11 Images when we don't have a recycling allocator available. r?nical MozReview-Commit-ID: 5pYZbHJSSIc
dom/media/platforms/wmf/DXVA2Manager.cpp
gfx/layers/D3D11ShareHandleImage.cpp
gfx/layers/D3D11ShareHandleImage.h
gfx/layers/D3D9SurfaceImage.cpp
gfx/layers/D3D9SurfaceImage.h
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -423,19 +423,21 @@ D3D9DXVA2Manager::Init(nsACString& aFail
   mDecoderService = decoderService;
 
   mResetToken = resetToken;
   mD3D9 = d3d9Ex;
   mDevice = device;
   mDeviceManager = deviceManager;
   mSyncSurface = syncSurf;
 
-  mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
-                                                     mDevice);
-  mTextureClientAllocator->SetMaxPoolSize(5);
+  if (layers::ImageBridgeChild::GetSingleton()) {
+    mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
+                                                       mDevice);
+    mTextureClientAllocator->SetMaxPoolSize(5);
+  }
 
   Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
                         uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D9));
 
   reporter.SetSuccessful();
 
   return S_OK;
 }
@@ -747,19 +749,21 @@ D3D11DXVA2Manager::Init(nsACString& aFai
   desc.Usage = D3D11_USAGE_STAGING;
   desc.BindFlags = 0;
   desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
   desc.MiscFlags = 0;
 
   hr = mDevice->CreateTexture2D(&desc, NULL, getter_AddRefs(mSyncSurface));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
-                                                      mDevice);
-  mTextureClientAllocator->SetMaxPoolSize(5);
+  if (layers::ImageBridgeChild::GetSingleton()) {
+    mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
+                                                        mDevice);
+    mTextureClientAllocator->SetMaxPoolSize(5);
+  }
 
   Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
                         uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11));
 
   reporter.SetSuccessful();
 
   return S_OK;
 }
@@ -790,17 +794,17 @@ D3D11DXVA2Manager::CopyToImage(IMFSample
   NS_ENSURE_TRUE(aOutImage, E_POINTER);
 
   // Our video frame is stored in a non-sharable ID3D11Texture2D. We need
   // to create a copy of that frame as a sharable resource, save its share
   // handle, and put that handle into the rendering pipeline.
 
   RefPtr<D3D11ShareHandleImage> image =
     new D3D11ShareHandleImage(gfx::IntSize(mWidth, mHeight), aRegion);
-  bool ok = image->AllocateTexture(mTextureClientAllocator);
+  bool ok = image->AllocateTexture(mTextureClientAllocator, mDevice);
   NS_ENSURE_TRUE(ok, E_FAIL);
 
   HRESULT hr = mTransform->Input(aVideoSample);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   RefPtr<IMFSample> sample;
   RefPtr<ID3D11Texture2D> texture = image->GetTexture();
   hr = CreateOutputSample(sample, texture);
--- a/gfx/layers/D3D11ShareHandleImage.cpp
+++ b/gfx/layers/D3D11ShareHandleImage.cpp
@@ -20,20 +20,35 @@ D3D11ShareHandleImage::D3D11ShareHandleI
                                              const gfx::IntRect& aRect)
  : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE),
    mSize(aSize),
    mPictureRect(aRect)
 {
 }
 
 bool
-D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator)
+D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator, ID3D11Device* aDevice)
 {
-  mTextureClient = aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::B8G8R8A8, mSize);
-  return !!mTextureClient;
+  if (aAllocator) {
+    mTextureClient = aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::B8G8R8A8, mSize);
+    if (mTextureClient) {
+      mTexture = static_cast<D3D11TextureData*>(mTextureClient->GetInternalData())->GetD3D11Texture();
+      return true;
+    }
+    return false;
+  } else {
+    MOZ_ASSERT(aDevice);
+    CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
+                                  mSize.width, mSize.height, 1, 1,
+                                  D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
+    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+
+    HRESULT hr = aDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(mTexture));
+    return SUCCEEDED(hr);
+  }
 }
 
 gfx::IntSize
 D3D11ShareHandleImage::GetSize()
 {
   return mSize;
 }
 
@@ -110,17 +125,17 @@ D3D11ShareHandleImage::GetAsSourceSurfac
   context->Unmap(softTexture, 0);
   surface->Unmap();
 
   return surface.forget();
 }
 
 ID3D11Texture2D*
 D3D11ShareHandleImage::GetTexture() const {
-  return static_cast<D3D11TextureData*>(mTextureClient->GetInternalData())->GetD3D11Texture();
+  return mTexture;
 }
 
 already_AddRefed<TextureClient>
 D3D11RecycleAllocator::Allocate(gfx::SurfaceFormat aFormat,
                                 gfx::IntSize aSize,
                                 BackendSelector aSelector,
                                 TextureFlags aTextureFlags,
                                 TextureAllocationFlags aAllocFlags)
--- a/gfx/layers/D3D11ShareHandleImage.h
+++ b/gfx/layers/D3D11ShareHandleImage.h
@@ -45,27 +45,28 @@ protected:
 // This class also manages the synchronization of the copy, to ensure the
 // resource is ready to use.
 class D3D11ShareHandleImage final : public Image {
 public:
   D3D11ShareHandleImage(const gfx::IntSize& aSize,
                         const gfx::IntRect& aRect);
   ~D3D11ShareHandleImage() override {}
 
-  bool AllocateTexture(D3D11RecycleAllocator* aAllocator);
+  bool AllocateTexture(D3D11RecycleAllocator* aAllocator, ID3D11Device* aDevice);
 
   gfx::IntSize GetSize() override;
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
   virtual gfx::IntRect GetPictureRect() override { return mPictureRect; }
 
   ID3D11Texture2D* GetTexture() const;
 
 private:
   gfx::IntSize mSize;
   gfx::IntRect mPictureRect;
   RefPtr<TextureClient> mTextureClient;
+  RefPtr<ID3D11Texture2D> mTexture;
 };
 
 } // namepace layers
 } // namespace mozilla
 
 #endif // GFX_D3DSURFACEIMAGE_H
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -13,16 +13,17 @@
 
 namespace mozilla {
 namespace layers {
 
 
 D3D9SurfaceImage::D3D9SurfaceImage()
   : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE)
   , mSize(0, 0)
+  , mShareHandle(0)
   , mValid(true)
 {}
 
 D3D9SurfaceImage::~D3D9SurfaceImage()
 {
 }
 
 HRESULT
@@ -50,49 +51,79 @@ D3D9SurfaceImage::AllocateAndCopy(D3D9Re
                                          D3DDEVTYPE_HAL,
                                          desc.Format,
                                          D3DFMT_A8R8G8B8);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // DXVA surfaces aren't created sharable, so we need to copy the surface
   // to a sharable texture to that it's accessible to the layer manager's
   // device.
-  RefPtr<TextureClient> textureClient =
-    aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::B8G8R8A8, aRegion.Size());
-  if (!textureClient) {
-    return E_FAIL;
+  if (aAllocator) {
+    mTextureClient =
+      aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::B8G8R8A8, aRegion.Size());
+    if (!mTextureClient) {
+      return E_FAIL;
+    }
+
+    DXGID3D9TextureData* texData =
+      static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData());
+    mTexture = texData->GetD3D9Texture();
+    mShareHandle = texData->GetShareHandle();
+    mDesc = texData->GetDesc();
+  } else {
+    hr = device->CreateTexture(aRegion.Size().width, aRegion.Size().height,
+                               1,
+                               D3DUSAGE_RENDERTARGET,
+                               D3DFMT_A8R8G8B8,
+                               D3DPOOL_DEFAULT,
+                               getter_AddRefs(mTexture),
+                               &mShareHandle);
+    if (FAILED(hr) || !mShareHandle) {
+      return E_FAIL;
+    }
+
+    hr = mTexture->GetLevelDesc(0, &mDesc);
+    if (FAILED(hr)) {
+      return E_FAIL;
+    }
   }
 
   // Copy the image onto the texture, preforming YUV -> RGB conversion if necessary.
-  RefPtr<IDirect3DSurface9> textureSurface = static_cast<DXGID3D9TextureData*>(
-    textureClient->GetInternalData())->GetD3D9Surface();
+  RefPtr<IDirect3DSurface9> textureSurface = GetD3D9Surface();
   if (!textureSurface) {
     return E_FAIL;
   }
 
   RECT src = { aRegion.x, aRegion.y, aRegion.x+aRegion.width, aRegion.y+aRegion.height };
   hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  mTextureClient = textureClient;
   mSize = aRegion.Size();
   return S_OK;
 }
 
 already_AddRefed<IDirect3DSurface9>
 D3D9SurfaceImage::GetD3D9Surface()
 {
-  return static_cast<DXGID3D9TextureData*>(
-    mTextureClient->GetInternalData())->GetD3D9Surface();
+  RefPtr<IDirect3DSurface9> textureSurface;
+  HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(textureSurface));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
+  return textureSurface.forget();
 }
 
 const D3DSURFACE_DESC&
 D3D9SurfaceImage::GetDesc() const
 {
-  return static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData())->GetDesc();
+  return mDesc;
+}
+
+HANDLE
+D3D9SurfaceImage::GetShareHandle() const
+{
+  return mShareHandle;
 }
 
 gfx::IntSize
 D3D9SurfaceImage::GetSize()
 {
   return mSize;
 }
 
@@ -102,38 +133,36 @@ D3D9SurfaceImage::GetTextureClient(Compo
   MOZ_ASSERT(mTextureClient);
   MOZ_ASSERT(mTextureClient->GetAllocator() == aClient->GetForwarder());
   return mTextureClient;
 }
 
 already_AddRefed<gfx::SourceSurface>
 D3D9SurfaceImage::GetAsSourceSurface()
 {
-  if (!mTextureClient) {
+  if (!mTexture) {
     return nullptr;
   }
 
   HRESULT hr;
   RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8);
   if (NS_WARN_IF(!surface)) {
     return nullptr;
   }
 
-  DXGID3D9TextureData* texData = static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData());
   // Readback the texture from GPU memory into system memory, so that
   // we can copy it into the Cairo image. This is expensive.
-  RefPtr<IDirect3DSurface9> textureSurface = texData->GetD3D9Surface();
+  RefPtr<IDirect3DSurface9> textureSurface = GetD3D9Surface();
   if (!textureSurface) {
     return nullptr;
   }
 
-  RefPtr<IDirect3DDevice9> device = texData->GetD3D9Device();
-  if (!device) {
-    return nullptr;
-  }
+  RefPtr<IDirect3DDevice9> device;
+  hr = textureSurface->GetDevice(getter_AddRefs(device));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   RefPtr<IDirect3DSurface9> systemMemorySurface;
   hr = device->CreateOffscreenPlainSurface(mSize.width,
                                            mSize.height,
                                            D3DFMT_A8R8G8B8,
                                            D3DPOOL_SYSTEMMEM,
                                            getter_AddRefs(systemMemorySurface),
                                            0);
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -59,23 +59,28 @@ public:
   gfx::IntSize GetSize() override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
 
   already_AddRefed<IDirect3DSurface9> GetD3D9Surface();
 
+  HANDLE GetShareHandle() const;
+
   virtual bool IsValid() override { return mValid; }
 
   void Invalidate() { mValid = false; }
 
 private:
 
   gfx::IntSize mSize;
   RefPtr<TextureClient> mTextureClient;
+  RefPtr<IDirect3DTexture9> mTexture;
+  HANDLE mShareHandle;
+  D3DSURFACE_DESC mDesc;
   bool mValid;
 };
 
 } // namepace layers
 } // namespace mozilla
 
 #endif // GFX_D3DSURFACEIMAGE_H