Skip to content
Permalink
Browse files

Bug 1145513 - Upload YCbCr image data on the client side when using d…

…3d9 layers.
  • Loading branch information...
rmottola committed Dec 29, 2018
1 parent 2ca4912 commit 50f7a69fa9a36634aef1ae5a221415ca98284435
@@ -9,6 +9,7 @@
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/TextureClient.h"
#include "d3d9.h"

namespace mozilla {
namespace layers {
@@ -55,12 +56,161 @@ struct AutoLockTexture
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;
}

@@ -104,9 +254,25 @@ IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
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;
@@ -30,6 +30,8 @@ class IMFYCbCrImage : public PlanarYCbCrImage
return nullptr;
}

TextureClient* GetD3D9TextureClient(CompositableClient* aClient);

This comment has been minimized.

Copy link
@roytam1

roytam1 Jan 10, 2019

@rmottola breaks build. patch is available here:

diff --git a/gfx/layers/IMFYCbCrImage.h b/gfx/layers/IMFYCbCrImage.h
index 8cec0cb10..95dec144f 100644
--- a/gfx/layers/IMFYCbCrImage.h
+++ b/gfx/layers/IMFYCbCrImage.h
@@ -16,34 +16,21 @@ 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) 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()
-  {
-    if (m2DBuffer) {
-      m2DBuffer->Unlock2D();
-    }
-    else {
-      mBuffer->Unlock();
-    }
-  }
+  ~IMFYCbCrImage();

   RefPtr<IMFMediaBuffer> mBuffer;
   RefPtr<IMF2DBuffer> m2DBuffer;
+  RefPtr<TextureClient> mTextureClient;
 };

 } // namepace layers

This comment has been minimized.

Copy link
@rmottola

rmottola Jan 10, 2019

Author Contributor

How do you catch this bug? I did a complete build and had no issues (Linux, MacOS, NetBSD).

@roytam1 : May it be actually that a complete successive patch is missing, of which your is part? I have identified this:
Bug 1138967 - Part 3
mozilla/gecko-dev@67c8f78#diff-8f651edd16b72cab940635ff657febf2

This comment has been minimized.

Copy link
@roytam1

roytam1 Jan 10, 2019

this component is windows-only and I build win32 builds. (I'm not directly build source from this repo, but importing change from here to my pm27 win32 source repo to build: https://github.com/roytam1/palemoon27/commits/master )

This comment has been minimized.

Copy link
@rmottola

rmottola Jan 11, 2019

Author Contributor

@roytam1 Original patch was unfortunatley partly applied, so missing the window part - checked against official gecko-dev. I backported it blindly and commited it on my tree. Please try. It is similar to your proposed butch and missed some stuff more.

This comment has been minimized.

Copy link
@roytam1

roytam1 Jan 11, 2019

and MOZ_OVERRIDE define is still missing: 2e42181#r31893045

This comment has been minimized.

Copy link
@rmottola

rmottola Jan 11, 2019

Author Contributor

@roytam1 I added MOZ_OVERRIDE, taking it from Mozilla directly, I hope it is equivalent to yours. Interestingly, TenFourFox does not have it and also Mozilla upstream removed it with. Builds fine here for me, but MOZ_OVERRIDE is not used elsewere apparently in the code!

This comment has been minimized.

Copy link
@rmottola

rmottola Jan 11, 2019

Author Contributor

Would the current ArcticFox compile on Windows?
Can it be compiled with mingw? mingw64? or are MS tools needed.

This comment has been minimized.

Copy link
@roytam1

roytam1 Jan 11, 2019

never tried building ArcticFox in windows, or building with mingw(64).
official win32 builds are using MSVC2013, and so do my builds.

This comment has been minimized.

Copy link
@roytam1

roytam1 Jan 11, 2019

I added MOZ_OVERRIDE, taking it from Mozilla directly, I hope it is equivalent to yours. Interestingly, TenFourFox does not have it and also Mozilla upstream removed it with. Builds fine here for me, but MOZ_OVERRIDE is not used elsewere apparently in the code!

but it is not the same as my diff, since _MSC_VER >= 1400 has override support, and your patch just ignore this condition and define MOZ_OVERRIDE as empty.


~IMFYCbCrImage()
{
if (m2DBuffer) {
@@ -501,38 +501,38 @@ TextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
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()) {
@@ -543,37 +543,22 @@ DXGIYCbCrTextureClientD3D11::Lock(OpenMode)
}

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;
}

@@ -84,17 +84,17 @@ class TextureClientD3D11 : public TextureClient
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 MOZ_OVERRIDE{ return !!mTextures[0]; }
virtual bool IsAllocated() const MOZ_OVERRIDE{ return !!mHoldRefs[0]; }

virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;

@@ -104,17 +104,25 @@ class DXGIYCbCrTextureClientD3D11 : public TextureClient

virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_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
@@ -131,8 +139,11 @@ class DXGIYCbCrTextureClientD3D11 : public TextureClient
CreateSimilar(TextureFlags, TextureAllocationFlags) const MOZ_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;
};

Oops, something went wrong.

0 comments on commit 50f7a69

Please sign in to comment.
You can’t perform that action at this time.