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 "D3D9SurfaceImage.h"
9 #include "gfxWindowsPlatform.h"
10 #include "mozilla/layers/CompositableClient.h"
11 #include "mozilla/layers/CompositableForwarder.h"
12 #include "mozilla/layers/ImageBridgeChild.h"
13 #include "mozilla/gfx/Types.h"
14 #include "mozilla/ProfilerLabels.h"
19 DXGID3D9TextureData::DXGID3D9TextureData(gfx::SurfaceFormat aFormat
,
20 IDirect3DTexture9
* aTexture
,
22 IDirect3DDevice9
* aDevice
)
23 : mDevice(aDevice
), mTexture(aTexture
), mFormat(aFormat
), mHandle(aHandle
) {
24 MOZ_COUNT_CTOR(DXGID3D9TextureData
);
27 DXGID3D9TextureData::~DXGID3D9TextureData() {
28 gfxWindowsPlatform::sD3D9SharedTextures
-= mDesc
.Width
* mDesc
.Height
* 4;
29 MOZ_COUNT_DTOR(DXGID3D9TextureData
);
33 DXGID3D9TextureData
* DXGID3D9TextureData::Create(gfx::IntSize aSize
,
34 gfx::SurfaceFormat aFormat
,
36 IDirect3DDevice9
* aDevice
) {
37 AUTO_PROFILER_LABEL("DXGID3D9TextureData::Create", GRAPHICS
);
38 MOZ_ASSERT(aFormat
== gfx::SurfaceFormat::B8G8R8A8
);
39 if (aFormat
!= gfx::SurfaceFormat::B8G8R8A8
) {
43 RefPtr
<IDirect3DTexture9
> texture
;
44 HANDLE shareHandle
= nullptr;
45 HRESULT hr
= aDevice
->CreateTexture(
46 aSize
.width
, aSize
.height
, 1, D3DUSAGE_RENDERTARGET
, D3DFMT_A8R8G8B8
,
47 D3DPOOL_DEFAULT
, getter_AddRefs(texture
), &shareHandle
);
48 if (FAILED(hr
) || !shareHandle
) {
52 D3DSURFACE_DESC surfaceDesc
;
53 hr
= texture
->GetLevelDesc(0, &surfaceDesc
);
57 DXGID3D9TextureData
* data
=
58 new DXGID3D9TextureData(aFormat
, texture
, shareHandle
, aDevice
);
59 data
->mDesc
= surfaceDesc
;
61 gfxWindowsPlatform::sD3D9SharedTextures
+= aSize
.width
* aSize
.height
* 4;
65 void DXGID3D9TextureData::FillInfo(TextureData::Info
& aInfo
) const {
66 aInfo
.size
= GetSize();
67 aInfo
.format
= mFormat
;
68 aInfo
.supportsMoz2D
= false;
69 aInfo
.canExposeMappedData
= false;
70 aInfo
.hasSynchronization
= false;
73 already_AddRefed
<IDirect3DSurface9
> DXGID3D9TextureData::GetD3D9Surface()
75 RefPtr
<IDirect3DSurface9
> textureSurface
;
76 HRESULT hr
= mTexture
->GetSurfaceLevel(0, getter_AddRefs(textureSurface
));
77 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
79 return textureSurface
.forget();
82 bool DXGID3D9TextureData::Serialize(SurfaceDescriptor
& aOutDescriptor
) {
83 SurfaceDescriptorD3D10
desc((WindowsHandle
)(mHandle
),
84 /* gpuProcessTextureId */ Nothing(),
85 /* arrayIndex */ 0, mFormat
, GetSize(),
86 gfx::ColorSpace2::SRGB
, gfx::ColorRange::FULL
,
87 /* hasKeyedMutex */ false);
88 // In reality, with D3D9 we will only ever deal with RGBA textures.
89 bool isYUV
= mFormat
== gfx::SurfaceFormat::NV12
||
90 mFormat
== gfx::SurfaceFormat::P010
||
91 mFormat
== gfx::SurfaceFormat::P016
;
93 gfxCriticalError() << "Unexpected YUV format for DXGID3D9TextureData: "
95 desc
.colorSpace() = gfx::ColorSpace2::BT601_525
;
96 desc
.colorRange() = gfx::ColorRange::LIMITED
;
98 aOutDescriptor
= desc
;
102 D3D9SurfaceImage::D3D9SurfaceImage()
103 : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE
),
108 D3D9SurfaceImage::~D3D9SurfaceImage() {}
111 D3D9SurfaceImage::AllocateAndCopy(D3D9RecycleAllocator
* aAllocator
,
112 IDirect3DSurface9
* aSurface
,
113 const gfx::IntRect
& aRegion
) {
114 NS_ENSURE_TRUE(aSurface
, E_POINTER
);
116 RefPtr
<IDirect3DSurface9
> surface
= aSurface
;
118 RefPtr
<IDirect3DDevice9
> device
;
119 hr
= surface
->GetDevice(getter_AddRefs(device
));
120 NS_ENSURE_TRUE(SUCCEEDED(hr
), E_FAIL
);
122 RefPtr
<IDirect3D9
> d3d9
;
123 hr
= device
->GetDirect3D(getter_AddRefs(d3d9
));
124 NS_ENSURE_TRUE(SUCCEEDED(hr
), E_FAIL
);
126 D3DSURFACE_DESC desc
;
127 surface
->GetDesc(&desc
);
128 // Ensure we can convert the textures format to RGB conversion
129 // in StretchRect. Fail if we can't.
130 hr
= d3d9
->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT
, D3DDEVTYPE_HAL
,
131 desc
.Format
, D3DFMT_A8R8G8B8
);
132 NS_ENSURE_TRUE(SUCCEEDED(hr
), hr
);
134 // DXVA surfaces aren't created sharable, so we need to copy the surface
135 // to a sharable texture to that it's accessible to the layer manager's
138 mTextureClient
= aAllocator
->CreateOrRecycleClient(
139 gfx::SurfaceFormat::B8G8R8A8
, aRegion
.Size());
140 if (!mTextureClient
) {
144 DXGID3D9TextureData
* texData
=
145 static_cast<DXGID3D9TextureData
*>(mTextureClient
->GetInternalData());
146 mTexture
= texData
->GetD3D9Texture();
147 mShareHandle
= texData
->GetShareHandle();
148 mDesc
= texData
->GetDesc();
150 hr
= device
->CreateTexture(aRegion
.Size().width
, aRegion
.Size().height
, 1,
151 D3DUSAGE_RENDERTARGET
, D3DFMT_A8R8G8B8
,
152 D3DPOOL_DEFAULT
, getter_AddRefs(mTexture
),
154 if (FAILED(hr
) || !mShareHandle
) {
158 hr
= mTexture
->GetLevelDesc(0, &mDesc
);
164 // Copy the image onto the texture, preforming YUV -> RGB conversion if
166 RefPtr
<IDirect3DSurface9
> textureSurface
= GetD3D9Surface();
167 if (!textureSurface
) {
171 RECT src
= {aRegion
.X(), aRegion
.Y(), aRegion
.XMost(), aRegion
.YMost()};
173 device
->StretchRect(surface
, &src
, textureSurface
, nullptr, D3DTEXF_NONE
);
174 NS_ENSURE_TRUE(SUCCEEDED(hr
), hr
);
176 mSize
= aRegion
.Size();
180 already_AddRefed
<IDirect3DSurface9
> D3D9SurfaceImage::GetD3D9Surface() const {
181 RefPtr
<IDirect3DSurface9
> textureSurface
;
182 HRESULT hr
= mTexture
->GetSurfaceLevel(0, getter_AddRefs(textureSurface
));
183 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
184 return textureSurface
.forget();
188 D3D9SurfaceImage::GetShareHandle() const { return mShareHandle
; }
190 gfx::IntSize
D3D9SurfaceImage::GetSize() const { return mSize
; }
192 TextureClient
* D3D9SurfaceImage::GetTextureClient(
193 KnowsCompositor
* aKnowsCompositor
) {
194 MOZ_ASSERT(mTextureClient
);
195 MOZ_ASSERT(mTextureClient
->GetAllocator() ==
196 aKnowsCompositor
->GetTextureForwarder());
197 return mTextureClient
;
200 already_AddRefed
<gfx::SourceSurface
> D3D9SurfaceImage::GetAsSourceSurface() {
206 RefPtr
<gfx::DataSourceSurface
> surface
=
207 gfx::Factory::CreateDataSourceSurface(mSize
,
208 gfx::SurfaceFormat::B8G8R8X8
);
209 if (NS_WARN_IF(!surface
)) {
213 // Readback the texture from GPU memory into system memory, so that
214 // we can copy it into the Cairo image. This is expensive.
215 RefPtr
<IDirect3DSurface9
> textureSurface
= GetD3D9Surface();
216 if (!textureSurface
) {
220 RefPtr
<IDirect3DDevice9
> device
;
221 hr
= textureSurface
->GetDevice(getter_AddRefs(device
));
222 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
224 RefPtr
<IDirect3DSurface9
> systemMemorySurface
;
225 hr
= device
->CreateOffscreenPlainSurface(
226 mSize
.width
, mSize
.height
, D3DFMT_A8R8G8B8
, D3DPOOL_SYSTEMMEM
,
227 getter_AddRefs(systemMemorySurface
), 0);
228 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
230 hr
= device
->GetRenderTargetData(textureSurface
, systemMemorySurface
);
231 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
234 hr
= systemMemorySurface
->LockRect(&rect
, nullptr, 0);
235 NS_ENSURE_TRUE(SUCCEEDED(hr
), nullptr);
237 gfx::DataSourceSurface::MappedSurface mappedSurface
;
238 if (!surface
->Map(gfx::DataSourceSurface::WRITE
, &mappedSurface
)) {
239 systemMemorySurface
->UnlockRect();
243 const unsigned char* src
= (const unsigned char*)(rect
.pBits
);
244 const unsigned srcPitch
= rect
.Pitch
;
245 for (int y
= 0; y
< mSize
.height
; y
++) {
246 memcpy(mappedSurface
.mData
+ mappedSurface
.mStride
* y
,
247 (unsigned char*)(src
) + srcPitch
* y
, mSize
.width
* 4);
250 systemMemorySurface
->UnlockRect();
253 return surface
.forget();
256 already_AddRefed
<TextureClient
> D3D9RecycleAllocator::Allocate(
257 gfx::SurfaceFormat aFormat
, gfx::IntSize aSize
, BackendSelector aSelector
,
258 TextureFlags aTextureFlags
, TextureAllocationFlags aAllocFlags
) {
260 DXGID3D9TextureData::Create(aSize
, aFormat
, aTextureFlags
, mDevice
);
265 return MakeAndAddRef
<TextureClient
>(data
, aTextureFlags
,
266 mKnowsCompositor
->GetTextureForwarder());
269 already_AddRefed
<TextureClient
> D3D9RecycleAllocator::CreateOrRecycleClient(
270 gfx::SurfaceFormat aFormat
, const gfx::IntSize
& aSize
) {
271 return CreateOrRecycle(aFormat
, aSize
, BackendSelector::Content
,
272 TextureFlags::DEFAULT
);
275 } // namespace layers
276 } // namespace mozilla