1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "D3D11YCbCrImage.h"
9 #include "YCbCrUtils.h"
10 #include "gfx2DGlue.h"
11 #include "mozilla/gfx/DeviceManagerDx.h"
12 #include "mozilla/gfx/gfxVars.h"
13 #include "mozilla/layers/CompositableClient.h"
14 #include "mozilla/layers/CompositableForwarder.h"
15 #include "mozilla/layers/TextureD3D11.h"
17 using namespace mozilla::gfx
;
22 class AutoCheckLockD3D11Texture final
{
24 explicit AutoCheckLockD3D11Texture(ID3D11Texture2D
* aTexture
)
26 aTexture
->QueryInterface((IDXGIKeyedMutex
**)getter_AddRefs(mMutex
));
28 // If D3D11Texture does not have keyed mutex, we think that the
29 // D3D11Texture could be locked.
34 // Test to see if the keyed mutex has been released
35 HRESULT hr
= mMutex
->AcquireSync(0, 0);
36 if (hr
== S_OK
|| hr
== WAIT_ABANDONED
) {
38 // According to Microsoft documentation:
39 // WAIT_ABANDONED - The shared surface and keyed mutex are no longer in a
40 // consistent state. If AcquireSync returns this value, you should release
41 // and recreate both the keyed mutex and the shared surface
42 // So even if we do get WAIT_ABANDONED, the keyed mutex will have to be
48 ~AutoCheckLockD3D11Texture() {
52 HRESULT hr
= mMutex
->ReleaseSync(0);
54 NS_WARNING("Failed to unlock the texture");
58 bool IsLocked() const { return mIsLocked
; }
62 bool mSyncAcquired
= false;
63 RefPtr
<IDXGIKeyedMutex
> mMutex
;
66 DXGIYCbCrTextureAllocationHelper::DXGIYCbCrTextureAllocationHelper(
67 const PlanarYCbCrData
& aData
, TextureFlags aTextureFlags
,
68 ID3D11Device
* aDevice
)
69 : ITextureClientAllocationHelper(
70 gfx::SurfaceFormat::YUV420
, aData
.mPictureRect
.Size(),
71 BackendSelector::Content
, aTextureFlags
, ALLOC_DEFAULT
),
75 bool DXGIYCbCrTextureAllocationHelper::IsCompatible(
76 TextureClient
* aTextureClient
) {
77 MOZ_ASSERT(aTextureClient
->GetFormat() == gfx::SurfaceFormat::YUV420
);
79 DXGIYCbCrTextureData
* dxgiData
=
80 aTextureClient
->GetInternalData()->AsDXGIYCbCrTextureData();
81 if (!dxgiData
|| aTextureClient
->GetSize() != mData
.mPictureRect
.Size() ||
82 dxgiData
->GetYSize() != mData
.YDataSize() ||
83 dxgiData
->GetCbCrSize() != mData
.CbCrDataSize() ||
84 dxgiData
->GetColorDepth() != mData
.mColorDepth
||
85 dxgiData
->GetYUVColorSpace() != mData
.mYUVColorSpace
) {
89 ID3D11Texture2D
* textureY
= dxgiData
->GetD3D11Texture(0);
90 ID3D11Texture2D
* textureCb
= dxgiData
->GetD3D11Texture(1);
91 ID3D11Texture2D
* textureCr
= dxgiData
->GetD3D11Texture(2);
93 RefPtr
<ID3D11Device
> device
;
94 textureY
->GetDevice(getter_AddRefs(device
));
95 if (!device
|| device
!= gfx::DeviceManagerDx::Get()->GetImageDevice()) {
99 // Test to see if the keyed mutex has been released.
100 // If D3D11Texture failed to lock, do not recycle the DXGIYCbCrTextureData.
102 AutoCheckLockD3D11Texture
lockY(textureY
);
103 AutoCheckLockD3D11Texture
lockCr(textureCr
);
104 AutoCheckLockD3D11Texture
lockCb(textureCb
);
106 if (!lockY
.IsLocked() || !lockCr
.IsLocked() || !lockCb
.IsLocked()) {
113 already_AddRefed
<TextureClient
> DXGIYCbCrTextureAllocationHelper::Allocate(
114 KnowsCompositor
* aAllocator
) {
115 auto ySize
= mData
.YDataSize();
116 auto cbcrSize
= mData
.CbCrDataSize();
117 CD3D11_TEXTURE2D_DESC
newDesc(mData
.mColorDepth
== gfx::ColorDepth::COLOR_8
118 ? DXGI_FORMAT_R8_UNORM
119 : DXGI_FORMAT_R16_UNORM
,
120 ySize
.width
, ySize
.height
, 1, 1);
121 newDesc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED_NTHANDLE
|
122 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
;
124 RefPtr
<ID3D10Multithread
> mt
;
125 HRESULT hr
= mDevice
->QueryInterface((ID3D10Multithread
**)getter_AddRefs(mt
));
127 if (FAILED(hr
) || !mt
) {
128 gfxCriticalError() << "Multithread safety interface not supported. " << hr
;
132 if (!mt
->GetMultithreadProtected()) {
133 gfxCriticalError() << "Device used not marked as multithread-safe.";
137 D3D11MTAutoEnter
mtAutoEnter(mt
.forget());
139 RefPtr
<ID3D11Texture2D
> textureY
;
140 hr
= mDevice
->CreateTexture2D(&newDesc
, nullptr, getter_AddRefs(textureY
));
141 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
143 newDesc
.Width
= cbcrSize
.width
;
144 newDesc
.Height
= cbcrSize
.height
;
146 RefPtr
<ID3D11Texture2D
> textureCb
;
147 hr
= mDevice
->CreateTexture2D(&newDesc
, nullptr, getter_AddRefs(textureCb
));
148 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
150 RefPtr
<ID3D11Texture2D
> textureCr
;
151 hr
= mDevice
->CreateTexture2D(&newDesc
, nullptr, getter_AddRefs(textureCr
));
152 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
154 TextureForwarder
* forwarder
=
155 aAllocator
? aAllocator
->GetTextureForwarder() : nullptr;
157 return TextureClient::CreateWithData(
158 DXGIYCbCrTextureData::Create(
159 textureY
, textureCb
, textureCr
, mData
.mPictureRect
.Size(), ySize
,
160 cbcrSize
, mData
.mColorDepth
, mData
.mYUVColorSpace
, mData
.mColorRange
),
161 mTextureFlags
, forwarder
);
164 already_AddRefed
<TextureClient
> D3D11YCbCrRecycleAllocator::Allocate(
165 SurfaceFormat aFormat
, IntSize aSize
, BackendSelector aSelector
,
166 TextureFlags aTextureFlags
, TextureAllocationFlags aAllocFlags
) {
167 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
171 } // namespace layers
172 } // namespace mozilla