diff --git a/gfx/layers/D3D11YCbCrImage.cpp b/gfx/layers/D3D11YCbCrImage.cpp new file mode 100644 index 0000000000..590d55fcb9 --- /dev/null +++ b/gfx/layers/D3D11YCbCrImage.cpp @@ -0,0 +1,351 @@ +/* -*- 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 "D3D11YCbCrImage.h" + +#include "gfx2DGlue.h" +#include "YCbCrUtils.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/layers/CompositableClient.h" +#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/TextureD3D11.h" + +using namespace mozilla::gfx; + +namespace mozilla { +namespace layers { + +D3D11YCbCrImage::D3D11YCbCrImage() + : Image(NULL, ImageFormat::D3D11_YCBCR_IMAGE) +{ +} + +D3D11YCbCrImage::~D3D11YCbCrImage() { } + +bool +D3D11YCbCrImage::SetData(KnowsCompositor* aAllocator, + ImageContainer* aContainer, + const PlanarYCbCrData& aData) +{ + mPictureRect = IntRect( + aData.mPicX, aData.mPicY, aData.mPicSize.width, aData.mPicSize.height); + mYSize = aData.mYSize; + mCbCrSize = aData.mCbCrSize; + mColorSpace = aData.mYUVColorSpace; + + D3D11YCbCrRecycleAllocator* allocator = + aContainer->GetD3D11YCbCrRecycleAllocator(aAllocator); + if (!allocator) { + return false; + } + allocator->SetSizes(aData.mYSize, aData.mCbCrSize); + + mTextureClient = allocator->CreateOrRecycle(SurfaceFormat::A8, + mYSize, + BackendSelector::Content, + TextureFlags::DEFAULT); + if (!mTextureClient) { + return false; + } + + DXGIYCbCrTextureData *data = + static_cast(mTextureClient->GetInternalData()); + + ID3D11Texture2D* textureY = data->GetD3D11Texture(0); + ID3D11Texture2D* textureCb = data->GetD3D11Texture(1); + ID3D11Texture2D* textureCr = data->GetD3D11Texture(2); + + RefPtr mt; + HRESULT hr = allocator->GetDevice()->QueryInterface( + (ID3D10Multithread**)getter_AddRefs(mt)); + + if (FAILED(hr) || !mt) { + gfxCriticalError() << "Multithread safety interface not supported. " << hr; + return false; + } + + if (!mt->GetMultithreadProtected()) { + gfxCriticalError() << "Device used not marked as multithread-safe."; + return false; + } + + mt->Enter(); + + RefPtr ctx; + allocator->GetDevice()->GetImmediateContext(getter_AddRefs(ctx)); + + AutoLockD3D11Texture lockY(textureY); + AutoLockD3D11Texture lockCb(textureCb); + AutoLockD3D11Texture lockCr(textureCr); + + ctx->UpdateSubresource(textureY, + 0, + nullptr, + aData.mYChannel, + aData.mYStride, + aData.mYStride * aData.mYSize.height); + ctx->UpdateSubresource(textureCb, + 0, + nullptr, + aData.mCbChannel, + aData.mCbCrStride, + aData.mCbCrStride * aData.mCbCrSize.height); + ctx->UpdateSubresource(textureCr, + 0, + nullptr, + aData.mCrChannel, + aData.mCbCrStride, + aData.mCbCrStride * aData.mCbCrSize.height); + + mt->Leave(); + + return true; +} + +IntSize +D3D11YCbCrImage::GetSize() +{ + return mPictureRect.Size(); +} + +TextureClient* +D3D11YCbCrImage::GetTextureClient(KnowsCompositor* aForwarder) +{ + return mTextureClient; +} + +already_AddRefed +D3D11YCbCrImage::GetAsSourceSurface() +{ + if (!mTextureClient) { + gfxWarning() + << "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage."; + return nullptr; + } + + gfx::IntSize size(mPictureRect.Size()); + gfx::SurfaceFormat format = + gfx::ImageFormatToSurfaceFormat(gfxVars::OffscreenFormat()); + HRESULT hr; + + PlanarYCbCrData data; + + DXGIYCbCrTextureData *dxgiData = + static_cast(mTextureClient->GetInternalData()); + + if (!dxgiData) { + gfxCriticalError() << "Failed to get texture client internal data."; + return nullptr; + } + + RefPtr texY = dxgiData->GetD3D11Texture(0); + RefPtr texCb = dxgiData->GetD3D11Texture(1); + RefPtr texCr = dxgiData->GetD3D11Texture(2); + RefPtr softTexY, softTexCb, softTexCr; + D3D11_TEXTURE2D_DESC desc; + + RefPtr dev; + texY->GetDevice(getter_AddRefs(dev)); + + RefPtr mt; + hr = dev->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt)); + + if (FAILED(hr) || !mt) { + gfxCriticalError() << "Multithread safety interface not supported."; + return nullptr; + } + + if (!mt->GetMultithreadProtected()) { + gfxCriticalError() << "Device used not marked as multithread-safe."; + return nullptr; + } + + class D3D11MTAutoEnter + { + public: + explicit D3D11MTAutoEnter(already_AddRefed aMT) + : mMT(aMT) + { + mMT->Enter(); + } + ~D3D11MTAutoEnter() + { + mMT->Leave(); + } + private: + RefPtr mMT; + } mtAutoEnter(mt.forget()); + + texY->GetDesc(&desc); + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexY)); + + texCb->GetDesc(&desc); + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCb)); + + texCr->GetDesc(&desc); + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCr)); + + RefPtr ctx; + dev->GetImmediateContext(getter_AddRefs(ctx)); + + { + AutoLockD3D11Texture lockY(texY); + AutoLockD3D11Texture lockCb(texCb); + AutoLockD3D11Texture lockCr(texCr); + ctx->CopyResource(softTexY, texY); + ctx->CopyResource(softTexCb, texCb); + ctx->CopyResource(softTexCr, texCr); + } + + D3D11_MAPPED_SUBRESOURCE mapY, mapCb, mapCr; + RefPtr surface; + mapY.pData = mapCb.pData = mapCr.pData = nullptr; + + hr = ctx->Map(softTexY, 0, D3D11_MAP_READ, 0, &mapY); + if (FAILED(hr)) { + gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; + return nullptr; + } + hr = ctx->Map(softTexCb, 0, D3D11_MAP_READ, 0, &mapCb); + if (FAILED(hr)) { + gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; + return nullptr; + } + hr = ctx->Map(softTexCr, 0, D3D11_MAP_READ, 0, &mapCr); + if (FAILED(hr)) { + gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; + return nullptr; + } + + MOZ_ASSERT(mapCb.RowPitch == mapCr.RowPitch); + + data.mPicX = mPictureRect.x; + data.mPicY = mPictureRect.y; + data.mPicSize = mPictureRect.Size(); + data.mStereoMode = StereoMode::MONO; + data.mYUVColorSpace = mColorSpace; + data.mYSkip = data.mCbSkip = data.mCrSkip = 0; + data.mYSize = mYSize; + data.mCbCrSize = mCbCrSize; + data.mYChannel = static_cast(mapY.pData); + data.mYStride = mapY.RowPitch; + data.mCbChannel = static_cast(mapCb.pData); + data.mCrChannel = static_cast(mapCr.pData); + data.mCbCrStride = mapCb.RowPitch; + + gfx::GetYCbCrToRGBDestFormatAndSize(data, format, size); + if (size.width > PlanarYCbCrImage::MAX_DIMENSION || + size.height > PlanarYCbCrImage::MAX_DIMENSION) { + gfxCriticalError() << "Illegal image dest width or height"; + return nullptr; + } + + surface = gfx::Factory::CreateDataSourceSurface(size, format); + if (!surface) { + gfxCriticalError() << "Failed to create DataSourceSurface for image: " + << size << " " << format; + return nullptr; + } + + DataSourceSurface::ScopedMap mapping(surface, DataSourceSurface::WRITE); + if (!mapping.IsMapped()) { + gfxCriticalError() << "Failed to map DataSourceSurface for D3D11YCbCrImage"; + return nullptr; + } + + gfx::ConvertYCbCrToRGB( + data, format, size, mapping.GetData(), mapping.GetStride()); + + ctx->Unmap(softTexY, 0); + ctx->Unmap(softTexCb, 0); + ctx->Unmap(softTexCr, 0); + + return surface.forget(); +} + +void +D3D11YCbCrRecycleAllocator::SetSizes(const gfx::IntSize& aYSize, + const gfx::IntSize& aCbCrSize) +{ + mYSize = Some(aYSize); + mCbCrSize = Some(aCbCrSize); +} + +already_AddRefed +D3D11YCbCrRecycleAllocator::Allocate(SurfaceFormat aFormat, + IntSize aSize, + BackendSelector aSelector, + TextureFlags aTextureFlags, + TextureAllocationFlags aAllocFlags) +{ + MOZ_ASSERT(aFormat == SurfaceFormat::A8); + + gfx::IntSize YSize = mYSize.refOr(aSize); + gfx::IntSize CbCrSize = + mCbCrSize.refOr(gfx::IntSize(YSize.width, YSize.height)); + CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM, YSize.width, YSize.height, + 1, 1); + newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; + + RefPtr mt; + HRESULT hr = mDevice->QueryInterface( + (ID3D10Multithread**)getter_AddRefs(mt)); + + if (FAILED(hr) || !mt) { + gfxCriticalError() << "Multithread safety interface not supported. " << hr; + return nullptr; + } + + if (!mt->GetMultithreadProtected()) { + gfxCriticalError() << "Device used not marked as multithread-safe."; + return nullptr; + } + + D3D11MTAutoEnter mtAutoEnter(mt.forget()); + + RefPtr textureY; + hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY)); + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); + + newDesc.Width = CbCrSize.width; + newDesc.Height = CbCrSize.height; + + RefPtr textureCb; + hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCb)); + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); + + RefPtr textureCr; + hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCr)); + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); + + return TextureClient::CreateWithData( + DXGIYCbCrTextureData::Create( + textureY, + textureCb, + textureCr, + aSize, + YSize, + CbCrSize), + TextureFlags::DEFAULT, + mSurfaceAllocator->GetTextureForwarder()); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/D3D11YCbCrImage.h b/gfx/layers/D3D11YCbCrImage.h new file mode 100644 index 0000000000..060b647501 --- /dev/null +++ b/gfx/layers/D3D11YCbCrImage.h @@ -0,0 +1,78 @@ +/* -*- 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/. */ + +#ifndef GFX_D3D11_YCBCR_IMAGE_H +#define GFX_D3D11_YCBCR_IMAGE_H + +#include "d3d11.h" +#include "mozilla/layers/TextureClientRecycleAllocator.h" +#include "mozilla/Maybe.h" +#include "ImageContainer.h" + +namespace mozilla { +namespace layers { + +class ImageContainer; +class DXGIYCbCrTextureClient; + +class D3D11YCbCrRecycleAllocator : public TextureClientRecycleAllocator +{ +public: + explicit D3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator, + ID3D11Device* aDevice) + : TextureClientRecycleAllocator(aAllocator) + , mDevice(aDevice) + { + } + + ID3D11Device* GetDevice() { return mDevice; } + KnowsCompositor* GetAllocator() { return mSurfaceAllocator; } + void SetSizes(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize); + +protected: + already_AddRefed + Allocate(gfx::SurfaceFormat aFormat, + gfx::IntSize aSize, + BackendSelector aSelector, + TextureFlags aTextureFlags, + TextureAllocationFlags aAllocFlags) override; + + RefPtr mDevice; + Maybe mYSize; + Maybe mCbCrSize; +}; + +class D3D11YCbCrImage : public Image +{ +public: + D3D11YCbCrImage(); + virtual ~D3D11YCbCrImage(); + + // Copies the surface into a sharable texture's surface, and initializes + // the image. + bool SetData(KnowsCompositor* aAllocator, + ImageContainer* aContainer, + const PlanarYCbCrData& aData); + + gfx::IntSize GetSize() override; + + already_AddRefed GetAsSourceSurface() override; + + TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override; + + gfx::IntRect GetPictureRect() override { return mPictureRect; } + +private: + gfx::IntSize mYSize; + gfx::IntSize mCbCrSize; + gfx::IntRect mPictureRect; + YUVColorSpace mColorSpace; + RefPtr mTextureClient; +}; + +} // namepace layers +} // namespace mozilla + +#endif // GFX_D3D11_YCBCR_IMAGE_H diff --git a/gfx/layers/IMFYCbCrImage.cpp b/gfx/layers/IMFYCbCrImage.cpp index 0f1ec5f295..e0f64b9c65 100644 --- a/gfx/layers/IMFYCbCrImage.cpp +++ b/gfx/layers/IMFYCbCrImage.cpp @@ -34,38 +34,6 @@ IMFYCbCrImage::~IMFYCbCrImage() } } -struct AutoLockTexture -{ - AutoLockTexture(ID3D11Texture2D* aTexture) - { - aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex)); - if (!mMutex) { - return; - } - HRESULT hr = mMutex->AcquireSync(0, 10000); - if (hr == WAIT_TIMEOUT) { - MOZ_CRASH("GFX: IMFYCbCrImage timeout"); - } - - if (FAILED(hr)) { - NS_WARNING("Failed to lock the texture"); - } - } - - ~AutoLockTexture() - { - if (!mMutex) { - return; - } - HRESULT hr = mMutex->ReleaseSync(0); - if (FAILED(hr)) { - NS_WARNING("Failed to unlock the texture"); - } - } - - RefPtr mMutex; -}; - static already_AddRefed InitTextures(IDirect3DDevice9* aDevice, const IntSize &aSize, @@ -302,9 +270,9 @@ IMFYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder) // required but were added for extra security. { - AutoLockTexture lockY(textureY); - AutoLockTexture lockCr(textureCr); - AutoLockTexture lockCb(textureCb); + AutoLockD3D11Texture lockY(textureY); + AutoLockD3D11Texture lockCr(textureCr); + AutoLockD3D11Texture lockCb(textureCb); mt->Enter(); @@ -327,9 +295,9 @@ IMFYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder) } mTextureClient = TextureClient::CreateWithData( - DXGIYCbCrTextureData::Create(TextureFlags::DEFAULT, - textureY, textureCb, textureCr, - GetSize(), mData.mYSize, mData.mCbCrSize), + DXGIYCbCrTextureData::Create(textureY, textureCb, textureCr, + aSize, aData.mYSize, aData.mCbCrSize); + TextureFlags::DEFAULT, aForwarder->GetTextureForwarder() ); diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index 5e4019e861..c982b5cb8f 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -35,6 +35,8 @@ #ifdef XP_WIN #include "gfxWindowsPlatform.h" #include +#include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/layers/D3D11YCbCrImage.h" #endif namespace mozilla { @@ -395,6 +397,40 @@ ImageContainer::NotifyCompositeInternal(const ImageCompositeNotification& aNotif } } +#ifdef XP_WIN +D3D11YCbCrRecycleAllocator* +ImageContainer::GetD3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator) +{ + if (mD3D11YCbCrRecycleAllocator && + aAllocator == mD3D11YCbCrRecycleAllocator->GetAllocator()) { + return mD3D11YCbCrRecycleAllocator; + } + + RefPtr device = gfx::DeviceManagerDx::Get()->GetContentDevice(); + if (!device) { + device = gfx::DeviceManagerDx::Get()->GetCompositorDevice(); + } + + LayersBackend backend = aAllocator->GetCompositorBackendType(); + if (!device || backend != LayersBackend::LAYERS_D3D11) { + return nullptr; + } + + RefPtr multi; + HRESULT hr = + device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi)); + if (FAILED(hr) || !multi) { + gfxWarning() << "Multithread safety interface not supported. " << hr; + return nullptr; + } + multi->SetMultithreadProtected(TRUE); + + mD3D11YCbCrRecycleAllocator = + new D3D11YCbCrRecycleAllocator(aAllocator, device); + return mD3D11YCbCrRecycleAllocator; +} +#endif + PlanarYCbCrImage::PlanarYCbCrImage() : Image(nullptr, ImageFormat::PLANAR_YCBCR) , mOffscreenFormat(SurfaceFormat::UNKNOWN) diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index f3e88665fb..79f27bed7a 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -153,6 +153,9 @@ class PlanarYCbCrImage; class TextureClient; class KnowsCompositor; class NVImage; +#ifdef XP_WIN +class D3D11YCbCrRecycleAllocator; +#endif struct ImageBackendData { @@ -173,14 +176,14 @@ class MacIOSurfaceImage; /** * A class representing a buffer of pixel data. The data can be in one * of various formats including YCbCr. - * + * * Create an image using an ImageContainer. Fill the image with data, and * then call ImageContainer::SetImage to display it. An image must not be * modified after calling SetImage. Image implementations do not need to * perform locking; when filling an Image, the Image client is responsible * for ensuring only one thread accesses the Image at a time, and after * SetImage the image is immutable. - * + * * When resampling an Image, only pixels within the buffer should be * sampled. For example, cairo images should be sampled in EXTEND_PAD mode. */ @@ -254,7 +257,7 @@ protected: /** * A RecycleBin is owned by an ImageContainer. We store buffers in it that we - * want to recycle from one image to the next.It's a separate object from + * want to recycle from one image to the next.It's a separate object from * ImageContainer because images need to store a strong ref to their RecycleBin * and we must avoid creating a reference loop between an ImageContainer and * its active image. @@ -319,7 +322,7 @@ protected: const gfx::IntSize& aScaleHint, BufferRecycleBin *aRecycleBin); }; - + /** * A class that manages Images for an ImageLayer. The only reason * we need a separate class here is that ImageLayers aren't threadsafe @@ -399,7 +402,7 @@ public: * mProducerID is a unique ID for the stream of images. A change in the * mProducerID means changing to a new mFrameID namespace. All frames in * aImages must have the same mProducerID. - * + * * The Image data must not be modified after this method is called! * Note that this must not be called if ENABLE_ASYNC has not been set. * @@ -435,11 +438,11 @@ public: * Set an Image as the current image to display. The Image must have * been created by this ImageContainer. * Must be called on the main thread, within a layers transaction. - * + * * This method takes mReentrantMonitor * when accessing thread-shared state. * aImage can be null. While it's null, nothing will be painted. - * + * * The Image data must not be modified after this method is called! * Note that this must not be called if ENABLE_ASYNC been set. * @@ -521,6 +524,11 @@ public: return mImageFactory; } +#ifdef XP_WIN + D3D11YCbCrRecycleAllocator* GetD3D11YCbCrRecycleAllocator( + KnowsCompositor* aAllocator); +#endif + /** * Returns the delay between the last composited image's presentation * timestamp and when it was first composited. It's possible for the delay @@ -587,6 +595,10 @@ private: // image", and any other state which is shared between threads. ReentrantMonitor mReentrantMonitor; +#ifdef XP_WIN + RefPtr mD3D11YCbCrRecycleAllocator; +#endif + nsTArray mCurrentImages; // Updates every time mActiveImage changes @@ -703,7 +715,7 @@ struct PlanarYCbCrData { * * The color format is detected based on the height/width ratios * defined above. - * + * * The Image that is rendered is the picture region defined by * mPicX, mPicY and mPicSize. The size of the rendered image is * mPicSize, not mYSize or mCbCrSize. diff --git a/gfx/layers/ImageTypes.h b/gfx/layers/ImageTypes.h index 5f6981fef7..078c94989c 100644 --- a/gfx/layers/ImageTypes.h +++ b/gfx/layers/ImageTypes.h @@ -99,6 +99,11 @@ enum class ImageFormat { */ TEXTURE_WRAPPER, + /** + * A D3D11 backed YUV image. + */ + D3D11_YCBCR_IMAGE, + /** * An opaque handle that refers to an Image stored in the GPU * process. diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 628ca12882..57c08e8037 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -516,10 +516,9 @@ D3D11TextureData::GetDXGIResource(IDXGIResource** aOutResource) } DXGIYCbCrTextureData* -DXGIYCbCrTextureData::Create(TextureFlags aFlags, - IUnknown* aTextureY, - IUnknown* aTextureCb, - IUnknown* aTextureCr, +DXGIYCbCrTextureData::Create(IDirect3DTexture9* aTextureY, + IDirect3DTexture9* aTextureCb, + IDirect3DTexture9* aTextureCr, HANDLE aHandleY, HANDLE aHandleCb, HANDLE aHandleCr, @@ -536,9 +535,9 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags, texture->mHandles[0] = aHandleY; texture->mHandles[1] = aHandleCb; texture->mHandles[2] = aHandleCr; - texture->mHoldRefs[0] = aTextureY; - texture->mHoldRefs[1] = aTextureCb; - texture->mHoldRefs[2] = aTextureCr; + texture->mD3D9Textures[0] = aTextureY; + texture->mD3D9Textures[1] = aTextureCb; + texture->mD3D9Textures[2] = aTextureCr; texture->mSize = aSize; texture->mSizeY = aSizeY; texture->mSizeCbCr = aSizeCbCr; @@ -547,8 +546,7 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags, } DXGIYCbCrTextureData* -DXGIYCbCrTextureData::Create(TextureFlags aFlags, - ID3D11Texture2D* aTextureY, +DXGIYCbCrTextureData::Create(ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCb, ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize, @@ -591,10 +589,18 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags, return nullptr; } - return DXGIYCbCrTextureData::Create(aFlags, - aTextureY, aTextureCb, aTextureCr, - handleY, handleCb, handleCr, - aSize, aSizeY, aSizeCbCr); + DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData(); + texture->mHandles[0] = handleY; + texture->mHandles[1] = handleCb; + texture->mHandles[2] = handleCr; + texture->mD3D11Textures[0] = aTextureY; + texture->mD3D11Textures[1] = aTextureCb; + texture->mD3D11Textures[2] = aTextureCr; + texture->mSize = aSize; + texture->mSizeY = aSizeY; + texture->mSizeCbCr = aSizeCbCr; + + return texture; } void @@ -620,9 +626,12 @@ DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) void DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*) { - mHoldRefs[0] = nullptr; - mHoldRefs[1] = nullptr; - mHoldRefs[2] = nullptr; + mD3D9Textures[0] = nullptr; + mD3D9Textures[1] = nullptr; + mD3D9Textures[2] = nullptr; + mD3D11Textures[0] = nullptr; + mD3D11Textures[1] = nullptr; + mD3D11Textures[2] = nullptr; } already_AddRefed @@ -1282,5 +1291,32 @@ SyncObjectD3D11::FinalizeFrame() } } +AutoLockD3D11Texture::AutoLockD3D11Texture(ID3D11Texture2D* aTexture) +{ + aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex)); + if (!mMutex) { + return; + } + HRESULT hr = mMutex->AcquireSync(0, 10000); + if (hr == WAIT_TIMEOUT) { + MOZ_CRASH("GFX: IMFYCbCrImage timeout"); + } + + if (FAILED(hr)) { + NS_WARNING("Failed to lock the texture"); + } +} + +AutoLockD3D11Texture::~AutoLockD3D11Texture() +{ + if (!mMutex) { + return; + } + HRESULT hr = mMutex->ReleaseSync(0); + if (FAILED(hr)) { + NS_WARNING("Failed to unlock the texture"); + } +} + } } diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h index 7e24410f3d..001444fae1 100644 --- a/gfx/layers/d3d11/TextureD3D11.h +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -127,10 +127,9 @@ class DXGIYCbCrTextureData : public TextureData { public: static DXGIYCbCrTextureData* - Create(TextureFlags aFlags, - IUnknown* aTextureY, - IUnknown* aTextureCb, - IUnknown* aTextureCr, + Create(IDirect3DTexture9* aTextureY, + IDirect3DTexture9* aTextureCb, + IDirect3DTexture9* aTextureCr, HANDLE aHandleY, HANDLE aHandleCb, HANDLE aHandleCr, @@ -139,8 +138,7 @@ public: const gfx::IntSize& aSizeCbCr); static DXGIYCbCrTextureData* - Create(TextureFlags aFlags, - ID3D11Texture2D* aTextureCb, + Create(ID3D11Texture2D* aTextureCb, ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize, @@ -166,8 +164,11 @@ public: return TextureFlags::DEALLOCATE_MAIN_THREAD; } + ID3D11Texture2D* GetD3D11Texture(size_t index) { return mD3D11Textures[index]; } + protected: - RefPtr mHoldRefs[3]; + RefPtr mD3D11Textures[3]; + RefPtr mD3D9Textures[3]; HANDLE mHandles[3]; gfx::IntSize mSize; gfx::IntSize mSizeY; @@ -450,6 +451,16 @@ inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel return maxTextureSize; } +class AutoLockD3D11Texture +{ +public: + explicit AutoLockD3D11Texture(ID3D11Texture2D* aTexture); + ~AutoLockD3D11Texture(); + +private: + RefPtr mMutex; +}; + } } diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 318be2a3f7..1f1caa058b 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -48,6 +48,7 @@ EXPORTS += [ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': SOURCES += [ 'D3D11ShareHandleImage.cpp', + 'D3D11YCbCrImage.cpp', ] UNIFIED_SOURCES += [ 'D3D9SurfaceImage.cpp', @@ -153,6 +154,7 @@ EXPORTS.mozilla.layers += [ 'Compositor.h', 'CompositorTypes.h', 'D3D11ShareHandleImage.h', + 'D3D11YCbCrImage.h', 'D3D9SurfaceImage.h', 'Effects.h', 'ImageDataSerializer.h',