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/. */
8 #include "D3D11ShareHandleImage.h"
9 #include "gfxImageSurface.h"
10 #include "gfxWindowsPlatform.h"
11 #include "mozilla/layers/TextureClient.h"
12 #include "mozilla/layers/TextureD3D11.h"
13 #include "mozilla/layers/CompositableClient.h"
14 #include "mozilla/layers/CompositableForwarder.h"
15 #include "mozilla/gfx/DeviceManagerDx.h"
18 #include "DXVA2Manager.h"
26 D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize
& aSize
,
27 const gfx::IntRect
& aRect
,
28 const GUID
& aSourceFormat
)
29 : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE
),
32 mSourceFormat(aSourceFormat
)
36 bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator
* aAllocator
,
37 ID3D11Device
* aDevice
) {
39 if (mSourceFormat
== MFVideoFormat_NV12
&&
40 gfxPrefs::PDMWMFUseNV12Format() &&
41 gfx::DeviceManagerDx::Get()->CanUseNV12()) {
43 aAllocator
->CreateOrRecycleClient(gfx::SurfaceFormat::NV12
, mSize
);
44 } else if (((mSourceFormat
== MFVideoFormat_P010
&&
45 gfx::DeviceManagerDx::Get()->CanUseP010()) ||
46 (mSourceFormat
== MFVideoFormat_P016
&&
47 gfx::DeviceManagerDx::Get()->CanUseP016())) &&
48 gfxPrefs::PDMWMFUseNV12Format()) {
49 mTextureClient
= aAllocator
->CreateOrRecycleClient(
50 mSourceFormat
== MFVideoFormat_P010
? gfx::SurfaceFormat::P010
51 : gfx::SurfaceFormat::P016
,
54 mTextureClient
= aAllocator
->CreateOrRecycleClient(
55 gfx::SurfaceFormat::B8G8R8A8
, mSize
);
59 static_cast<D3D11TextureData
*>(mTextureClient
->GetInternalData())
66 CD3D11_TEXTURE2D_DESC
newDesc(
67 DXGI_FORMAT_B8G8R8A8_UNORM
, mSize
.width
, mSize
.height
, 1, 1,
68 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
);
69 newDesc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED
;
72 aDevice
->CreateTexture2D(&newDesc
, nullptr, getter_AddRefs(mTexture
));
77 gfx::IntSize
D3D11ShareHandleImage::GetSize() const { return mSize
; }
79 TextureClient
* D3D11ShareHandleImage::GetTextureClient(
80 KnowsCompositor
* aForwarder
) {
81 return mTextureClient
;
84 already_AddRefed
<gfx::SourceSurface
>
85 D3D11ShareHandleImage::GetAsSourceSurface() {
86 RefPtr
<ID3D11Texture2D
> texture
= GetTexture();
88 gfxWarning() << "Cannot readback from shared texture because no texture is "
93 RefPtr
<ID3D11Device
> device
;
94 texture
->GetDevice(getter_AddRefs(device
));
96 D3D11_TEXTURE2D_DESC desc
;
97 texture
->GetDesc(&desc
);
101 if (desc
.Format
!= DXGI_FORMAT_B8G8R8A8_UNORM
) {
103 std::unique_ptr
<DXVA2Manager
> manager(
104 DXVA2Manager::CreateD3D11DXVA(nullptr, error
, device
));
107 gfxWarning() << "Failed to create DXVA2 manager!";
111 RefPtr
<ID3D11Texture2D
> outTexture
;
113 hr
= manager
->CopyToBGRATexture(texture
, mSourceFormat
,
114 getter_AddRefs(outTexture
));
117 gfxWarning() << "Failed to copy to BGRA texture.";
121 texture
= outTexture
;
122 texture
->GetDesc(&desc
);
125 CD3D11_TEXTURE2D_DESC
softDesc(desc
.Format
, desc
.Width
, desc
.Height
);
126 softDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
127 softDesc
.BindFlags
= 0;
128 softDesc
.MiscFlags
= 0;
129 softDesc
.MipLevels
= 1;
130 softDesc
.Usage
= D3D11_USAGE_STAGING
;
132 RefPtr
<ID3D11Texture2D
> softTexture
;
133 hr
= device
->CreateTexture2D(
135 static_cast<ID3D11Texture2D
**>(getter_AddRefs(softTexture
)));
138 NS_WARNING("Failed to create 2D staging texture.");
142 RefPtr
<ID3D11DeviceContext
> context
;
143 device
->GetImmediateContext(getter_AddRefs(context
));
145 gfxCriticalError() << "Failed to get immediate context.";
149 RefPtr
<IDXGIKeyedMutex
> mutex
;
150 hr
= texture
->QueryInterface((IDXGIKeyedMutex
**)getter_AddRefs(mutex
));
152 if (SUCCEEDED(hr
) && mutex
) {
153 hr
= mutex
->AcquireSync(0, 2000);
155 NS_WARNING("Acquire sync didn't manage to return within 2 seconds.");
158 context
->CopyResource(softTexture
, texture
);
159 if (SUCCEEDED(hr
) && mutex
) {
160 mutex
->ReleaseSync(0);
163 RefPtr
<gfx::DataSourceSurface
> surface
=
164 gfx::Factory::CreateDataSourceSurface(mSize
,
165 gfx::SurfaceFormat::B8G8R8A8
);
166 if (NS_WARN_IF(!surface
)) {
170 gfx::DataSourceSurface::MappedSurface mappedSurface
;
171 if (!surface
->Map(gfx::DataSourceSurface::WRITE
, &mappedSurface
)) {
175 D3D11_MAPPED_SUBRESOURCE map
;
176 hr
= context
->Map(softTexture
, 0, D3D11_MAP_READ
, 0, &map
);
177 if (!SUCCEEDED(hr
)) {
182 for (int y
= 0; y
< mSize
.height
; y
++) {
183 memcpy(mappedSurface
.mData
+ mappedSurface
.mStride
* y
,
184 (unsigned char*)(map
.pData
) + map
.RowPitch
* y
, mSize
.width
* 4);
187 context
->Unmap(softTexture
, 0);
190 return surface
.forget();
193 ID3D11Texture2D
* D3D11ShareHandleImage::GetTexture() const { return mTexture
; }
195 already_AddRefed
<TextureClient
> D3D11RecycleAllocator::Allocate(
196 gfx::SurfaceFormat aFormat
, gfx::IntSize aSize
, BackendSelector aSelector
,
197 TextureFlags aTextureFlags
, TextureAllocationFlags aAllocFlags
) {
198 return CreateD3D11TextureClientWithDevice(
199 aSize
, aFormat
, aTextureFlags
, aAllocFlags
, mDevice
,
200 mSurfaceAllocator
->GetTextureForwarder());
203 already_AddRefed
<TextureClient
> D3D11RecycleAllocator::CreateOrRecycleClient(
204 gfx::SurfaceFormat aFormat
, const gfx::IntSize
& aSize
) {
205 // When CompositorDevice or ContentDevice is updated,
206 // we could not reuse old D3D11Textures. It could cause video flickering.
207 RefPtr
<ID3D11Device
> device
= gfx::DeviceManagerDx::Get()->GetImageDevice();
208 if (!!mImageDevice
&& mImageDevice
!= device
) {
209 ShrinkToMinimumSize();
211 mImageDevice
= device
;
213 TextureAllocationFlags allocFlags
= TextureAllocationFlags::ALLOC_DEFAULT
;
214 if (gfxPrefs::PDMWMFUseSyncTexture() ||
215 mDevice
== DeviceManagerDx::Get()->GetCompositorDevice()) {
216 // If our device is the compositor device, we don't need any synchronization
218 allocFlags
= TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION
;
220 RefPtr
<TextureClient
> textureClient
=
221 CreateOrRecycle(aFormat
, aSize
, BackendSelector::Content
,
222 layers::TextureFlags::DEFAULT
, allocFlags
);
223 return textureClient
.forget();
226 } // namespace layers
227 } // namespace mozilla