2015-03-19 00:17:13 +03:00
|
|
|
/* -*- 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"
|
2016-08-23 03:23:38 +03:00
|
|
|
#include "DeviceManagerD3D9.h"
|
2015-03-19 00:17:13 +03:00
|
|
|
#include "mozilla/layers/TextureD3D11.h"
|
|
|
|
#include "mozilla/layers/CompositableClient.h"
|
|
|
|
#include "mozilla/layers/CompositableForwarder.h"
|
2016-08-08 12:53:51 +03:00
|
|
|
#include "mozilla/gfx/DeviceManagerD3D11.h"
|
2015-03-19 00:17:13 +03:00
|
|
|
#include "mozilla/gfx/Types.h"
|
|
|
|
#include "mozilla/layers/TextureClient.h"
|
2015-03-23 05:13:56 +03:00
|
|
|
#include "d3d9.h"
|
2015-03-19 00:17:13 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
|
|
|
|
|
|
|
IMFYCbCrImage::IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer)
|
2015-11-06 21:55:31 +03:00
|
|
|
: RecyclingPlanarYCbCrImage(nullptr)
|
2015-03-19 00:17:13 +03:00
|
|
|
, mBuffer(aBuffer)
|
|
|
|
, m2DBuffer(a2DBuffer)
|
|
|
|
{}
|
|
|
|
|
|
|
|
IMFYCbCrImage::~IMFYCbCrImage()
|
|
|
|
{
|
|
|
|
if (m2DBuffer) {
|
|
|
|
m2DBuffer->Unlock2D();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mBuffer->Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct AutoLockTexture
|
|
|
|
{
|
|
|
|
AutoLockTexture(ID3D11Texture2D* aTexture)
|
|
|
|
{
|
2015-10-18 07:40:10 +03:00
|
|
|
aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
|
2015-03-19 00:17:13 +03:00
|
|
|
HRESULT hr = mMutex->AcquireSync(0, 10000);
|
|
|
|
if (hr == WAIT_TIMEOUT) {
|
2015-12-10 15:01:00 +03:00
|
|
|
MOZ_CRASH("GFX: IMFYCbCrImage timeout");
|
2015-03-19 00:17:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDXGIKeyedMutex> mMutex;
|
2015-03-19 00:17:13 +03:00
|
|
|
};
|
|
|
|
|
2015-06-17 17:00:52 +03:00
|
|
|
static already_AddRefed<IDirect3DTexture9>
|
2015-03-23 05:13:56 +03:00
|
|
|
InitTextures(IDirect3DDevice9* aDevice,
|
|
|
|
const IntSize &aSize,
|
|
|
|
_D3DFORMAT aFormat,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DSurface9>& aSurface,
|
2015-03-23 05:13:56 +03:00
|
|
|
HANDLE& aHandle,
|
|
|
|
D3DLOCKED_RECT& aLockedRect)
|
|
|
|
{
|
|
|
|
if (!aDevice) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9> result;
|
2015-03-23 05:13:56 +03:00
|
|
|
if (FAILED(aDevice->CreateTexture(aSize.width, aSize.height,
|
|
|
|
1, 0, aFormat, D3DPOOL_DEFAULT,
|
2015-10-18 07:40:10 +03:00
|
|
|
getter_AddRefs(result), &aHandle))) {
|
2015-03-23 05:13:56 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9> tmpTexture;
|
2015-03-23 05:13:56 +03:00
|
|
|
if (FAILED(aDevice->CreateTexture(aSize.width, aSize.height,
|
|
|
|
1, 0, aFormat, D3DPOOL_SYSTEMMEM,
|
2015-10-18 07:40:10 +03:00
|
|
|
getter_AddRefs(tmpTexture), nullptr))) {
|
2015-03-23 05:13:56 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!tmpTexture) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 07:40:10 +03:00
|
|
|
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(aSurface));
|
2015-08-10 16:47:22 +03:00
|
|
|
if (FAILED(aSurface->LockRect(&aLockedRect, nullptr, 0)) ||
|
|
|
|
!aLockedRect.pBits) {
|
2015-03-23 05:13:56 +03:00
|
|
|
NS_WARNING("Could not lock surface");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-05-01 16:14:16 +03:00
|
|
|
return result.forget();
|
2015-03-23 05:13:56 +03:00
|
|
|
}
|
|
|
|
|
2015-06-05 17:19:11 +03:00
|
|
|
static bool
|
2015-03-23 05:13:56 +03:00
|
|
|
FinishTextures(IDirect3DDevice9* aDevice,
|
|
|
|
IDirect3DTexture9* aTexture,
|
|
|
|
IDirect3DSurface9* aSurface)
|
|
|
|
{
|
|
|
|
if (!aDevice) {
|
2015-06-05 17:56:06 +03:00
|
|
|
return false;
|
2015-03-23 05:13:56 +03:00
|
|
|
}
|
|
|
|
|
2015-06-05 17:19:11 +03:00
|
|
|
HRESULT hr = aSurface->UnlockRect();
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DSurface9> dstSurface;
|
2015-06-05 17:19:11 +03:00
|
|
|
hr = aTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = aDevice->UpdateSurface(aSurface, nullptr, dstSurface, nullptr);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2015-03-23 05:13:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool UploadData(IDirect3DDevice9* aDevice,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9>& aTexture,
|
2015-03-23 05:13:56 +03:00
|
|
|
HANDLE& aHandle,
|
|
|
|
uint8_t* aSrc,
|
|
|
|
const gfx::IntSize& aSrcSize,
|
|
|
|
int32_t aSrcStride)
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DSurface9> surf;
|
2015-03-23 05:13:56 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-05 17:19:11 +03:00
|
|
|
return FinishTextures(aDevice, aTexture, surf);
|
2015-03-23 05:13:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TextureClient*
|
|
|
|
IMFYCbCrImage::GetD3D9TextureClient(CompositableClient* aClient)
|
|
|
|
{
|
2016-08-23 03:23:38 +03:00
|
|
|
RefPtr<IDirect3DDevice9> device = DeviceManagerD3D9::GetDevice();
|
2015-09-10 20:21:43 +03:00
|
|
|
if (!device) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-03-23 05:13:56 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9> textureY;
|
2015-03-23 05:13:56 +03:00
|
|
|
HANDLE shareHandleY = 0;
|
|
|
|
if (!UploadData(device, textureY, shareHandleY,
|
|
|
|
mData.mYChannel, mData.mYSize, mData.mYStride)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9> textureCb;
|
2015-03-23 05:13:56 +03:00
|
|
|
HANDLE shareHandleCb = 0;
|
|
|
|
if (!UploadData(device, textureCb, shareHandleCb,
|
|
|
|
mData.mCbChannel, mData.mCbCrSize, mData.mCbCrStride)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DTexture9> textureCr;
|
2015-03-23 05:13:56 +03:00
|
|
|
HANDLE shareHandleCr = 0;
|
|
|
|
if (!UploadData(device, textureCr, shareHandleCr,
|
|
|
|
mData.mCrChannel, mData.mCbCrSize, mData.mCbCrStride)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDirect3DQuery9> query;
|
2015-10-18 07:40:10 +03:00
|
|
|
HRESULT hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
|
2015-03-23 05:13:56 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
mTextureClient = TextureClient::CreateWithData(
|
|
|
|
DXGIYCbCrTextureData::Create(aClient->GetForwarder(),
|
|
|
|
TextureFlags::DEFAULT,
|
|
|
|
textureY, textureCb, textureCr,
|
|
|
|
shareHandleY, shareHandleCb, shareHandleCr,
|
|
|
|
GetSize(), mData.mYSize, mData.mCbCrSize),
|
|
|
|
TextureFlags::DEFAULT,
|
|
|
|
aClient->GetForwarder()
|
|
|
|
);
|
2015-03-23 05:13:56 +03:00
|
|
|
|
|
|
|
return mTextureClient;
|
|
|
|
}
|
|
|
|
|
2015-03-19 00:17:13 +03:00
|
|
|
TextureClient*
|
|
|
|
IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
|
|
|
|
{
|
2016-01-12 08:08:21 +03:00
|
|
|
if (mTextureClient) {
|
|
|
|
return mTextureClient;
|
|
|
|
}
|
|
|
|
|
2016-07-26 22:50:30 +03:00
|
|
|
RefPtr<ID3D11Device> device =
|
2016-08-08 12:53:51 +03:00
|
|
|
gfx::DeviceManagerD3D11::Get()->GetContentDevice();
|
2015-03-23 05:13:56 +03:00
|
|
|
|
2016-03-21 10:14:05 +03:00
|
|
|
LayersBackend backend = aClient->GetForwarder()->GetCompositorBackendType();
|
2015-09-10 20:21:43 +03:00
|
|
|
if (!device || backend != LayersBackend::LAYERS_D3D11) {
|
|
|
|
if (backend == LayersBackend::LAYERS_D3D9 ||
|
|
|
|
backend == LayersBackend::LAYERS_D3D11) {
|
2015-03-23 05:13:56 +03:00
|
|
|
return GetD3D9TextureClient(aClient);
|
|
|
|
}
|
2015-03-19 00:17:13 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-08-02 08:53:06 +03:00
|
|
|
if (mData.mYStride < 0 || mData.mCbCrStride < 0) {
|
|
|
|
// D3D11 only supports unsigned stride values.
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-03-19 00:17:13 +03:00
|
|
|
|
2015-06-15 19:30:34 +03:00
|
|
|
CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM,
|
2015-03-19 00:17:13 +03:00
|
|
|
mData.mYSize.width, mData.mYSize.height, 1, 1);
|
|
|
|
|
|
|
|
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ID3D11Texture2D> textureY;
|
2016-08-02 08:53:06 +03:00
|
|
|
D3D11_SUBRESOURCE_DATA yData = { mData.mYChannel, (UINT)mData.mYStride, 0 };
|
|
|
|
HRESULT hr = device->CreateTexture2D(&newDesc, &yData, getter_AddRefs(textureY));
|
2015-03-19 00:17:13 +03:00
|
|
|
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
|
|
|
|
|
|
|
newDesc.Width = mData.mCbCrSize.width;
|
|
|
|
newDesc.Height = mData.mCbCrSize.height;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ID3D11Texture2D> textureCb;
|
2016-08-02 08:53:06 +03:00
|
|
|
D3D11_SUBRESOURCE_DATA cbData = { mData.mCbChannel, (UINT)mData.mCbCrStride, 0 };
|
|
|
|
hr = device->CreateTexture2D(&newDesc, &cbData, getter_AddRefs(textureCb));
|
2015-03-19 00:17:13 +03:00
|
|
|
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ID3D11Texture2D> textureCr;
|
2016-08-02 08:53:06 +03:00
|
|
|
D3D11_SUBRESOURCE_DATA crData = { mData.mCrChannel, (UINT)mData.mCbCrStride, 0 };
|
|
|
|
hr = device->CreateTexture2D(&newDesc, &crData, getter_AddRefs(textureCr));
|
2015-03-19 00:17:13 +03:00
|
|
|
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
|
|
|
|
2016-08-02 08:53:06 +03:00
|
|
|
// Even though the textures we created are meant to be protected by a keyed mutex,
|
|
|
|
// it appears that D3D doesn't include the initial memory upload within this
|
|
|
|
// synchronization. Add an empty lock/unlock pair since that appears to
|
|
|
|
// be sufficient to make sure we synchronize.
|
2015-03-19 00:17:13 +03:00
|
|
|
{
|
|
|
|
AutoLockTexture lockCr(textureCr);
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
mTextureClient = TextureClient::CreateWithData(
|
|
|
|
DXGIYCbCrTextureData::Create(aClient->GetForwarder(),
|
|
|
|
TextureFlags::DEFAULT,
|
|
|
|
textureY, textureCb, textureCr,
|
|
|
|
GetSize(), mData.mYSize, mData.mCbCrSize),
|
|
|
|
TextureFlags::DEFAULT,
|
|
|
|
aClient->GetForwarder()
|
|
|
|
);
|
2015-03-19 00:17:13 +03:00
|
|
|
|
|
|
|
return mTextureClient;
|
|
|
|
}
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace layers
|
|
|
|
} // namespace mozilla
|