/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/gfx/DeviceManagerDx.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Types.h" #include "mozilla/layers/TextureD3D11.h" #include "mozilla/layers/CompositableClient.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/D3D11YCbCrImage.h" #include "mozilla/layers/TextureClient.h" #include "d3d9.h" namespace mozilla { namespace layers { IMFYCbCrImage::IMFYCbCrImage(IMFMediaBuffer* aBuffer, IMF2DBuffer* a2DBuffer, KnowsCompositor* aKnowsCompositor, ImageContainer* aContainer) : RecyclingPlanarYCbCrImage(nullptr), mBuffer(aBuffer), m2DBuffer(a2DBuffer) { mAllocator = aContainer->GetD3D11YCbCrRecycleAllocator(aKnowsCompositor); } IMFYCbCrImage::~IMFYCbCrImage() { if (m2DBuffer) { m2DBuffer->Unlock2D(); } else { mBuffer->Unlock(); } } /* static */ bool IMFYCbCrImage::CopyDataToTexture(const Data& aData, ID3D11Device* aDevice, DXGIYCbCrTextureData* aTextureData) { MOZ_ASSERT(aTextureData); HRESULT hr; RefPtr mt; hr = aDevice->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt)); if (FAILED(hr)) { return false; } if (!mt->GetMultithreadProtected()) { return false; } if (!gfx::DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) { return false; } ID3D11Texture2D* textureY = aTextureData->GetD3D11Texture(0); ID3D11Texture2D* textureCb = aTextureData->GetD3D11Texture(1); ID3D11Texture2D* textureCr = aTextureData->GetD3D11Texture(2); D3D11MTAutoEnter mtAutoEnter(mt.forget()); RefPtr ctx; aDevice->GetImmediateContext(getter_AddRefs(ctx)); if (!ctx) { gfxCriticalError() << "Failed to get immediate context."; return false; } // The documentation here seems to suggest using the immediate mode context // on more than one thread is not allowed: // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476891(v=vs.85).aspx // The Debug Layer seems to imply it is though. When the ID3D10Multithread // layer is on. The Enter/Leave of the critical section shouldn't even be // required but were added for extra security. { AutoLockD3D11Texture lockY(textureY); AutoLockD3D11Texture lockCr(textureCr); AutoLockD3D11Texture lockCb(textureCb); D3D11MTAutoEnter mtAutoEnter(mt.forget()); D3D11_BOX box; box.front = box.top = box.left = 0; box.back = 1; box.right = aData.YDataSize().width; box.bottom = aData.YDataSize().height; ctx->UpdateSubresource(textureY, 0, &box, aData.mYChannel, aData.mYStride, 0); box.right = aData.CbCrDataSize().width; box.bottom = aData.CbCrDataSize().height; ctx->UpdateSubresource(textureCb, 0, &box, aData.mCbChannel, aData.mCbCrStride, 0); ctx->UpdateSubresource(textureCr, 0, &box, aData.mCrChannel, aData.mCbCrStride, 0); } return true; } TextureClient* IMFYCbCrImage::GetD3D11TextureClient( KnowsCompositor* aKnowsCompositor) { if (!mAllocator) { return nullptr; } RefPtr device = gfx::DeviceManagerDx::Get()->GetImageDevice(); if (!device) { return nullptr; } { DXGIYCbCrTextureAllocationHelper helper(mData, TextureFlags::DEFAULT, device); mTextureClient = mAllocator->CreateOrRecycle(helper); } if (!mTextureClient) { return nullptr; } DXGIYCbCrTextureData* data = mTextureClient->GetInternalData()->AsDXGIYCbCrTextureData(); if (!CopyDataToTexture(mData, device, data)) { // Failed to copy data mTextureClient = nullptr; return nullptr; } return mTextureClient; } TextureClient* IMFYCbCrImage::GetTextureClient( KnowsCompositor* aKnowsCompositor) { if (mTextureClient) { return mTextureClient; } RefPtr device = gfx::DeviceManagerDx::Get()->GetImageDevice(); if (!device || !aKnowsCompositor->SupportsD3D11()) { return nullptr; } return GetD3D11TextureClient(aKnowsCompositor); } } // namespace layers } // namespace mozilla