summaryrefslogtreecommitdiffstats
path: root/gfx/layers/IMFYCbCrImage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/IMFYCbCrImage.cpp')
-rw-r--r--gfx/layers/IMFYCbCrImage.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/gfx/layers/IMFYCbCrImage.cpp b/gfx/layers/IMFYCbCrImage.cpp
new file mode 100644
index 0000000000..0534b2126e
--- /dev/null
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -0,0 +1,151 @@
+/* -*- 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<ID3D10Multithread> 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<ID3D11DeviceContext> 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<ID3D11Device> 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<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
+ if (!device || !aKnowsCompositor->SupportsD3D11()) {
+ return nullptr;
+ }
+ return GetD3D11TextureClient(aKnowsCompositor);
+}
+
+} // namespace layers
+} // namespace mozilla