Bug 1138967 - Part 3: Add D3D11 YCbCr texture clients and upload on the client side. r=nical

This commit is contained in:
Matt Woodrow 2015-03-19 10:17:13 +13:00
parent b7da7cb76d
commit 1fd763f827
9 changed files with 441 additions and 14 deletions

View File

@ -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 */

View File

@ -16,32 +16,23 @@ 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

View File

@ -232,6 +232,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
case SurfaceDescriptor::TSurfaceDescriptorD3D10:
case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
if (Compositor::GetBackend() == LayersBackend::LAYERS_D3D9) {
return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
} else {

View File

@ -158,6 +158,11 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
aDesc.get_SurfaceDescriptorD3D10());
break;
}
case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
result = new DXGIYCbCrTextureHostD3D11(aFlags,
aDesc.get_SurfaceDescriptorDXGIYCbCr());
break;
}
default: {
NS_WARNING("Unsupported SurfaceDescriptor type");
}
@ -499,6 +504,82 @@ TextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
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)
@ -579,6 +660,108 @@ DXGITextureHostD3D11::GetTextureSources()
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,

View File

@ -78,6 +78,59 @@ protected:
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.
@ -213,6 +266,45 @@ protected:
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
{

View File

@ -50,6 +50,13 @@ struct SurfaceDescriptorD3D10 {
IntSize size;
};
struct SurfaceDescriptorDXGIYCbCr {
WindowsHandle handleY;
WindowsHandle handleCb;
WindowsHandle handleCr;
IntSize size;
};
struct SurfaceDescriptorMacIOSurface {
uint32_t surface;
double scaleFactor;
@ -104,6 +111,7 @@ union SurfaceDescriptor {
SurfaceDescriptorD3D9;
SurfaceDescriptorDIB;
SurfaceDescriptorD3D10;
SurfaceDescriptorDXGIYCbCr;
SurfaceDescriptorX11;
SurfaceTextureDescriptor;
EGLImageDescriptor;

View File

@ -48,6 +48,7 @@ EXPORTS += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
UNIFIED_SOURCES += [
'D3D9SurfaceImage.cpp',
'IMFYCbCrImage.cpp',
'TextureDIB.cpp',
]
EXPORTS.mozilla.layers += [

View File

@ -1582,6 +1582,19 @@ gfxWindowsPlatform::GetD3D11ContentDevice()
return mD3D11ContentDevice;
}
ID3D11Device*
gfxWindowsPlatform::GetD3D11MediaDevice()
{
if (mD3D11DeviceInitialized) {
return mD3D11MediaDevice;
}
InitD3D11Devices();
return mD3D11MediaDevice;
}
ReadbackManagerD3D11*
gfxWindowsPlatform::GetReadbackManager()
{
@ -1942,6 +1955,25 @@ gfxWindowsPlatform::InitD3D11Devices()
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();

View File

@ -246,6 +246,7 @@ public:
#endif
ID3D11Device *GetD3D11Device();
ID3D11Device *GetD3D11ContentDevice();
ID3D11Device *GetD3D11MediaDevice();
mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
@ -286,6 +287,7 @@ private:
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;