Source code

Revision control

Other Tools

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/. */
6
7
#include "D3D9SurfaceImage.h"
8
#include "gfx2DGlue.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
15
namespace mozilla {
16
namespace layers {
17
18
DXGID3D9TextureData::DXGID3D9TextureData(gfx::SurfaceFormat aFormat,
19
IDirect3DTexture9* aTexture,
20
HANDLE aHandle,
21
IDirect3DDevice9* aDevice)
22
: mDevice(aDevice), mTexture(aTexture), mFormat(aFormat), mHandle(aHandle) {
23
MOZ_COUNT_CTOR(DXGID3D9TextureData);
24
}
25
26
DXGID3D9TextureData::~DXGID3D9TextureData() {
27
gfxWindowsPlatform::sD3D9SharedTextures -= mDesc.Width * mDesc.Height * 4;
28
MOZ_COUNT_DTOR(DXGID3D9TextureData);
29
}
30
31
// static
32
DXGID3D9TextureData* DXGID3D9TextureData::Create(gfx::IntSize aSize,
33
gfx::SurfaceFormat aFormat,
34
TextureFlags aFlags,
35
IDirect3DDevice9* aDevice) {
36
AUTO_PROFILER_LABEL("DXGID3D9TextureData::Create", GRAPHICS);
37
MOZ_ASSERT(aFormat == gfx::SurfaceFormat::B8G8R8A8);
38
if (aFormat != gfx::SurfaceFormat::B8G8R8A8) {
39
return nullptr;
40
}
41
42
RefPtr<IDirect3DTexture9> texture;
43
HANDLE shareHandle = nullptr;
44
HRESULT hr = aDevice->CreateTexture(
45
aSize.width, aSize.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
46
D3DPOOL_DEFAULT, getter_AddRefs(texture), &shareHandle);
47
if (FAILED(hr) || !shareHandle) {
48
return nullptr;
49
}
50
51
D3DSURFACE_DESC surfaceDesc;
52
hr = texture->GetLevelDesc(0, &surfaceDesc);
53
if (FAILED(hr)) {
54
return nullptr;
55
}
56
DXGID3D9TextureData* data =
57
new DXGID3D9TextureData(aFormat, texture, shareHandle, aDevice);
58
data->mDesc = surfaceDesc;
59
60
gfxWindowsPlatform::sD3D9SharedTextures += aSize.width * aSize.height * 4;
61
return data;
62
}
63
64
void DXGID3D9TextureData::FillInfo(TextureData::Info& aInfo) const {
65
aInfo.size = GetSize();
66
aInfo.format = mFormat;
67
aInfo.supportsMoz2D = false;
68
aInfo.canExposeMappedData = false;
69
aInfo.hasIntermediateBuffer = false;
70
aInfo.hasSynchronization = false;
71
}
72
73
already_AddRefed<IDirect3DSurface9> DXGID3D9TextureData::GetD3D9Surface()
74
const {
75
RefPtr<IDirect3DSurface9> textureSurface;
76
HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(textureSurface));
77
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
78
79
return textureSurface.forget();
80
}
81
82
bool DXGID3D9TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
83
// In reality, with D3D9 we will only ever deal with RGBA textures.
84
bool isYUV = mFormat == SurfaceFormat::NV12 ||
85
mFormat == SurfaceFormat::P010 || mFormat == SurfaceFormat::P016;
86
aOutDescriptor = SurfaceDescriptorD3D10(
87
(WindowsHandle)(mHandle), mFormat, GetSize(),
88
isYUV ? gfx::YUVColorSpace::BT601 : gfx::YUVColorSpace::UNKNOWN,
89
gfx::ColorRange::LIMITED);
90
return true;
91
}
92
93
D3D9SurfaceImage::D3D9SurfaceImage()
94
: Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE),
95
mSize(0, 0),
96
mShareHandle(0),
97
mValid(true) {}
98
99
D3D9SurfaceImage::~D3D9SurfaceImage() {}
100
101
HRESULT
102
D3D9SurfaceImage::AllocateAndCopy(D3D9RecycleAllocator* aAllocator,
103
IDirect3DSurface9* aSurface,
104
const gfx::IntRect& aRegion) {
105
NS_ENSURE_TRUE(aSurface, E_POINTER);
106
HRESULT hr;
107
RefPtr<IDirect3DSurface9> surface = aSurface;
108
109
RefPtr<IDirect3DDevice9> device;
110
hr = surface->GetDevice(getter_AddRefs(device));
111
NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
112
113
RefPtr<IDirect3D9> d3d9;
114
hr = device->GetDirect3D(getter_AddRefs(d3d9));
115
NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
116
117
D3DSURFACE_DESC desc;
118
surface->GetDesc(&desc);
119
// Ensure we can convert the textures format to RGB conversion
120
// in StretchRect. Fail if we can't.
121
hr = d3d9->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
122
desc.Format, D3DFMT_A8R8G8B8);
123
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
124
125
// DXVA surfaces aren't created sharable, so we need to copy the surface
126
// to a sharable texture to that it's accessible to the layer manager's
127
// device.
128
if (aAllocator) {
129
mTextureClient = aAllocator->CreateOrRecycleClient(
130
gfx::SurfaceFormat::B8G8R8A8, aRegion.Size());
131
if (!mTextureClient) {
132
return E_FAIL;
133
}
134
135
DXGID3D9TextureData* texData =
136
static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData());
137
mTexture = texData->GetD3D9Texture();
138
mShareHandle = texData->GetShareHandle();
139
mDesc = texData->GetDesc();
140
} else {
141
hr = device->CreateTexture(aRegion.Size().width, aRegion.Size().height, 1,
142
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
143
D3DPOOL_DEFAULT, getter_AddRefs(mTexture),
144
&mShareHandle);
145
if (FAILED(hr) || !mShareHandle) {
146
return E_FAIL;
147
}
148
149
hr = mTexture->GetLevelDesc(0, &mDesc);
150
if (FAILED(hr)) {
151
return E_FAIL;
152
}
153
}
154
155
// Copy the image onto the texture, preforming YUV -> RGB conversion if
156
// necessary.
157
RefPtr<IDirect3DSurface9> textureSurface = GetD3D9Surface();
158
if (!textureSurface) {
159
return E_FAIL;
160
}
161
162
RECT src = {aRegion.X(), aRegion.Y(), aRegion.XMost(), aRegion.YMost()};
163
hr =
164
device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE);
165
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
166
167
mSize = aRegion.Size();
168
return S_OK;
169
}
170
171
already_AddRefed<IDirect3DSurface9> D3D9SurfaceImage::GetD3D9Surface() const {
172
RefPtr<IDirect3DSurface9> textureSurface;
173
HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(textureSurface));
174
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
175
return textureSurface.forget();
176
}
177
178
const D3DSURFACE_DESC& D3D9SurfaceImage::GetDesc() const { return mDesc; }
179
180
HANDLE
181
D3D9SurfaceImage::GetShareHandle() const { return mShareHandle; }
182
183
gfx::IntSize D3D9SurfaceImage::GetSize() const { return mSize; }
184
185
TextureClient* D3D9SurfaceImage::GetTextureClient(
186
KnowsCompositor* aKnowsCompositor) {
187
MOZ_ASSERT(mTextureClient);
188
MOZ_ASSERT(mTextureClient->GetAllocator() ==
189
aKnowsCompositor->GetTextureForwarder());
190
return mTextureClient;
191
}
192
193
already_AddRefed<gfx::SourceSurface> D3D9SurfaceImage::GetAsSourceSurface() {
194
if (!mTexture) {
195
return nullptr;
196
}
197
198
HRESULT hr;
199
RefPtr<gfx::DataSourceSurface> surface =
200
gfx::Factory::CreateDataSourceSurface(mSize,
201
gfx::SurfaceFormat::B8G8R8X8);
202
if (NS_WARN_IF(!surface)) {
203
return nullptr;
204
}
205
206
// Readback the texture from GPU memory into system memory, so that
207
// we can copy it into the Cairo image. This is expensive.
208
RefPtr<IDirect3DSurface9> textureSurface = GetD3D9Surface();
209
if (!textureSurface) {
210
return nullptr;
211
}
212
213
RefPtr<IDirect3DDevice9> device;
214
hr = textureSurface->GetDevice(getter_AddRefs(device));
215
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
216
217
RefPtr<IDirect3DSurface9> systemMemorySurface;
218
hr = device->CreateOffscreenPlainSurface(
219
mSize.width, mSize.height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
220
getter_AddRefs(systemMemorySurface), 0);
221
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
222
223
hr = device->GetRenderTargetData(textureSurface, systemMemorySurface);
224
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
225
226
D3DLOCKED_RECT rect;
227
hr = systemMemorySurface->LockRect(&rect, nullptr, 0);
228
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
229
230
gfx::DataSourceSurface::MappedSurface mappedSurface;
231
if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
232
systemMemorySurface->UnlockRect();
233
return nullptr;
234
}
235
236
const unsigned char* src = (const unsigned char*)(rect.pBits);
237
const unsigned srcPitch = rect.Pitch;
238
for (int y = 0; y < mSize.height; y++) {
239
memcpy(mappedSurface.mData + mappedSurface.mStride * y,
240
(unsigned char*)(src) + srcPitch * y, mSize.width * 4);
241
}
242
243
systemMemorySurface->UnlockRect();
244
surface->Unmap();
245
246
return surface.forget();
247
}
248
249
already_AddRefed<TextureClient> D3D9RecycleAllocator::Allocate(
250
gfx::SurfaceFormat aFormat, gfx::IntSize aSize, BackendSelector aSelector,
251
TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) {
252
TextureData* data =
253
DXGID3D9TextureData::Create(aSize, aFormat, aTextureFlags, mDevice);
254
if (!data) {
255
return nullptr;
256
}
257
258
return MakeAndAddRef<TextureClient>(data, aTextureFlags,
259
mKnowsCompositor->GetTextureForwarder());
260
}
261
262
already_AddRefed<TextureClient> D3D9RecycleAllocator::CreateOrRecycleClient(
263
gfx::SurfaceFormat aFormat, const gfx::IntSize& aSize) {
264
return CreateOrRecycle(aFormat, aSize, BackendSelector::Content,
265
TextureFlags::DEFAULT);
266
}
267
268
} // namespace layers
269
} // namespace mozilla