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 "TextureDIB.h"
8
#include "gfx2DGlue.h"
9
#include "mozilla/gfx/DataSurfaceHelpers.h" // For BufferSizeFromDimensions
10
#include "mozilla/ipc/ProtocolUtils.h"
11
#include "mozilla/layers/ISurfaceAllocator.h"
12
#include "mozilla/layers/TextureForwarder.h" // For LayersIPCChannel
13
14
namespace mozilla {
15
16
using namespace gfx;
17
18
namespace layers {
19
20
/**
21
* Can only be drawn into through Cairo.
22
* The coresponding TextureHost depends on the compositor
23
*/
24
class MemoryDIBTextureData : public DIBTextureData {
25
public:
26
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
27
28
virtual TextureData* CreateSimilar(
29
LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
30
TextureFlags aFlags = TextureFlags::DEFAULT,
31
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
32
33
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
34
35
static DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
36
37
virtual void Deallocate(LayersIPCChannel* aAllocator) override {
38
mSurface = nullptr;
39
}
40
41
MemoryDIBTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
42
gfxWindowsSurface* aSurface)
43
: DIBTextureData(aSize, aFormat, aSurface) {
44
MOZ_COUNT_CTOR(MemoryDIBTextureData);
45
}
46
47
MOZ_COUNTED_DTOR_OVERRIDE(MemoryDIBTextureData)
48
};
49
50
/**
51
* Can only be drawn into through Cairo.
52
* The coresponding TextureHost depends on the compositor
53
*/
54
class ShmemDIBTextureData : public DIBTextureData {
55
public:
56
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
57
58
virtual TextureData* CreateSimilar(
59
LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
60
TextureFlags aFlags = TextureFlags::DEFAULT,
61
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
62
63
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
64
65
static DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
66
LayersIPCChannel* aAllocator);
67
68
void DeallocateData() {
69
if (mSurface) {
70
::DeleteObject(mBitmap);
71
::DeleteDC(mDC);
72
::CloseHandle(mFileMapping);
73
mBitmap = NULL;
74
mDC = NULL;
75
mFileMapping = NULL;
76
mSurface = nullptr;
77
}
78
}
79
80
virtual void Deallocate(LayersIPCChannel* aAllocator) override {
81
DeallocateData();
82
}
83
84
ShmemDIBTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
85
gfxWindowsSurface* aSurface, HANDLE aFileMapping,
86
HANDLE aHostHandle, HDC aDC, HBITMAP aBitmap)
87
: DIBTextureData(aSize, aFormat, aSurface),
88
mFileMapping(aFileMapping),
89
mHostHandle(aHostHandle),
90
mDC(aDC),
91
mBitmap(aBitmap) {
92
MOZ_COUNT_CTOR(ShmemDIBTextureData);
93
}
94
95
virtual ~ShmemDIBTextureData() {
96
MOZ_COUNT_DTOR(ShmemDIBTextureData);
97
98
// The host side has its own references and handles to this data, we can
99
// safely clear ours.
100
DeallocateData();
101
}
102
103
HANDLE mFileMapping;
104
HANDLE mHostHandle;
105
HDC mDC;
106
HBITMAP mBitmap;
107
};
108
109
void DIBTextureData::FillInfo(TextureData::Info& aInfo) const {
110
aInfo.size = mSize;
111
aInfo.format = mFormat;
112
aInfo.hasIntermediateBuffer = true;
113
aInfo.hasSynchronization = false;
114
aInfo.supportsMoz2D = true;
115
aInfo.canExposeMappedData = false;
116
}
117
118
already_AddRefed<gfx::DrawTarget> DIBTextureData::BorrowDrawTarget() {
119
return gfxPlatform::CreateDrawTargetForSurface(mSurface, mSize);
120
}
121
122
DIBTextureData* DIBTextureData::Create(gfx::IntSize aSize,
123
gfx::SurfaceFormat aFormat,
124
LayersIPCChannel* aAllocator) {
125
if (!aAllocator) {
126
return nullptr;
127
}
128
if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
129
return nullptr;
130
}
131
if (aAllocator->IsSameProcess()) {
132
return MemoryDIBTextureData::Create(aSize, aFormat);
133
} else {
134
return ShmemDIBTextureData::Create(aSize, aFormat, aAllocator);
135
}
136
}
137
138
TextureData* MemoryDIBTextureData::CreateSimilar(
139
LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
140
TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
141
if (!aAllocator) {
142
return nullptr;
143
}
144
return MemoryDIBTextureData::Create(mSize, mFormat);
145
}
146
147
bool MemoryDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
148
MOZ_ASSERT(mSurface);
149
// The host will release this ref when it receives the surface descriptor.
150
// We AddRef in case we die before the host receives the pointer.
151
aOutDescriptor =
152
SurfaceDescriptorDIB(reinterpret_cast<uintptr_t>(mSurface.get()));
153
mSurface.get()->AddRef();
154
return true;
155
}
156
157
DIBTextureData* MemoryDIBTextureData::Create(gfx::IntSize aSize,
158
gfx::SurfaceFormat aFormat) {
159
RefPtr<gfxWindowsSurface> surface =
160
new gfxWindowsSurface(aSize, SurfaceFormatToImageFormat(aFormat));
161
if (!surface || surface->CairoStatus()) {
162
NS_WARNING("Could not create DIB surface");
163
return nullptr;
164
}
165
166
return new MemoryDIBTextureData(aSize, aFormat, surface);
167
}
168
169
bool MemoryDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
170
RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
171
172
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
173
174
if (!srcSurf) {
175
gfxCriticalError()
176
<< "Failed to GetDataSurface in UpdateFromSurface (DIB).";
177
return false;
178
}
179
180
DataSourceSurface::MappedSurface sourceMap;
181
if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
182
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
183
return false;
184
}
185
186
for (int y = 0; y < srcSurf->GetSize().height; y++) {
187
memcpy(imgSurf->Data() + imgSurf->Stride() * y,
188
sourceMap.mData + sourceMap.mStride * y,
189
srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
190
}
191
192
srcSurf->Unmap();
193
return true;
194
}
195
196
TextureData* ShmemDIBTextureData::CreateSimilar(
197
LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
198
TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
199
if (!aAllocator) {
200
return nullptr;
201
}
202
return ShmemDIBTextureData::Create(mSize, mFormat, aAllocator);
203
}
204
205
bool ShmemDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
206
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
207
208
if (!srcSurf) {
209
gfxCriticalError()
210
<< "Failed to GetDataSurface in UpdateFromSurface (DTD).";
211
return false;
212
}
213
214
DataSourceSurface::MappedSurface sourceMap;
215
if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
216
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
217
return false;
218
}
219
220
GdiFlush();
221
222
uint32_t stride = mSize.width * BytesPerPixel(mFormat);
223
uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_WRITE, 0, 0,
224
stride * mSize.height);
225
226
if (!data) {
227
gfxCriticalError() << "Failed to map view of file for UpdateFromSurface.";
228
srcSurf->Unmap();
229
return false;
230
}
231
232
for (int y = 0; y < srcSurf->GetSize().height; y++) {
233
memcpy(data + stride * y, sourceMap.mData + sourceMap.mStride * y,
234
srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
235
}
236
237
::UnmapViewOfFile(data);
238
239
srcSurf->Unmap();
240
return true;
241
}
242
243
bool ShmemDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
244
if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
245
return false;
246
}
247
248
::GdiFlush();
249
aOutDescriptor =
250
SurfaceDescriptorFileMapping((WindowsHandle)mHostHandle, mFormat, mSize);
251
return true;
252
}
253
254
DIBTextureData* ShmemDIBTextureData::Create(gfx::IntSize aSize,
255
gfx::SurfaceFormat aFormat,
256
LayersIPCChannel* aAllocator) {
257
MOZ_ASSERT(aAllocator->GetParentPid() != base::ProcessId());
258
259
DWORD mapSize = aSize.width * aSize.height * BytesPerPixel(aFormat);
260
HANDLE fileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
261
PAGE_READWRITE, 0, mapSize, NULL);
262
263
if (!fileMapping) {
264
gfxCriticalError() << "Failed to create memory file mapping for " << mapSize
265
<< " bytes.";
266
return nullptr;
267
}
268
269
BITMAPV4HEADER header;
270
memset(&header, 0, sizeof(BITMAPV4HEADER));
271
header.bV4Size = sizeof(BITMAPV4HEADER);
272
header.bV4Width = aSize.width;
273
header.bV4Height = -LONG(aSize.height); // top-to-buttom DIB
274
header.bV4Planes = 1;
275
header.bV4BitCount = 32;
276
header.bV4V4Compression = BI_BITFIELDS;
277
header.bV4RedMask = 0x00FF0000;
278
header.bV4GreenMask = 0x0000FF00;
279
header.bV4BlueMask = 0x000000FF;
280
281
HDC nulldc = ::GetDC(NULL);
282
283
HDC dc = ::CreateCompatibleDC(nulldc);
284
285
::ReleaseDC(nullptr, nulldc);
286
287
if (!dc) {
288
::CloseHandle(fileMapping);
289
gfxCriticalError() << "Failed to create DC for bitmap.";
290
return nullptr;
291
}
292
293
void* bits;
294
HBITMAP bitmap = ::CreateDIBSection(dc, (BITMAPINFO*)&header, DIB_RGB_COLORS,
295
&bits, fileMapping, 0);
296
297
if (!bitmap) {
298
gfxCriticalError() << "Failed to create DIB section for a bitmap of size "
299
<< aSize << " and mapSize " << mapSize;
300
::CloseHandle(fileMapping);
301
::DeleteDC(dc);
302
return nullptr;
303
}
304
305
::SelectObject(dc, bitmap);
306
307
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(dc, 0);
308
if (surface->CairoStatus()) {
309
::DeleteObject(bitmap);
310
::DeleteDC(dc);
311
::CloseHandle(fileMapping);
312
gfxCriticalError() << "Could not create surface, status: "
313
<< surface->CairoStatus();
314
return nullptr;
315
}
316
317
HANDLE hostHandle = NULL;
318
319
if (!ipc::DuplicateHandle(fileMapping, aAllocator->GetParentPid(),
320
&hostHandle, 0, DUPLICATE_SAME_ACCESS)) {
321
gfxCriticalError()
322
<< "Failed to duplicate handle to parent process for surface.";
323
::DeleteObject(bitmap);
324
::DeleteDC(dc);
325
::CloseHandle(fileMapping);
326
return nullptr;
327
}
328
329
return new ShmemDIBTextureData(aSize, aFormat, surface, fileMapping,
330
hostHandle, dc, bitmap);
331
}
332
333
bool TextureHostDirectUpload::Lock() {
334
MOZ_ASSERT(!mIsLocked);
335
mIsLocked = true;
336
return true;
337
}
338
339
void TextureHostDirectUpload::Unlock() {
340
MOZ_ASSERT(mIsLocked);
341
mIsLocked = false;
342
}
343
344
void TextureHostDirectUpload::SetTextureSourceProvider(
345
TextureSourceProvider* aProvider) {
346
mProvider = aProvider;
347
}
348
349
void TextureHostDirectUpload::DeallocateDeviceData() {
350
if (mTextureSource) {
351
mTextureSource->DeallocateDeviceData();
352
}
353
}
354
355
bool TextureHostDirectUpload::BindTextureSource(
356
CompositableTextureSourceRef& aTexture) {
357
return AcquireTextureSource(aTexture);
358
}
359
360
bool TextureHostDirectUpload::AcquireTextureSource(
361
CompositableTextureSourceRef& aTexture) {
362
if (!mTextureSource) {
363
Updated();
364
}
365
366
aTexture = mTextureSource;
367
return !!aTexture;
368
}
369
370
DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
371
const SurfaceDescriptorDIB& aDescriptor)
372
: TextureHostDirectUpload(aFlags, SurfaceFormat::B8G8R8X8, IntSize()) {
373
// We added an extra ref for transport, so we shouldn't AddRef now.
374
mSurface =
375
dont_AddRef(reinterpret_cast<gfxWindowsSurface*>(aDescriptor.surface()));
376
MOZ_ASSERT(mSurface);
377
378
mSize = mSurface->GetSize();
379
mFormat = mSurface->GetSurfaceFormat();
380
}
381
382
void DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion) {
383
if (!mProvider) {
384
// This can happen if we send textures to a compositable that isn't yet
385
// attached to a layer.
386
return;
387
}
388
389
if (!mTextureSource) {
390
mTextureSource = mProvider->CreateDataTextureSource(mFlags);
391
}
392
393
if (mSurface->CairoStatus()) {
394
gfxWarning() << "Bad Cairo surface internal update "
395
<< mSurface->CairoStatus();
396
mTextureSource = nullptr;
397
return;
398
}
399
RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
400
401
RefPtr<DataSourceSurface> surf = Factory::CreateWrappingDataSourceSurface(
402
imgSurf->Data(), imgSurf->Stride(), mSize, mFormat);
403
404
if (!surf ||
405
!mTextureSource->Update(surf, const_cast<nsIntRegion*>(aRegion))) {
406
mTextureSource = nullptr;
407
}
408
409
ReadUnlock();
410
}
411
412
TextureHostFileMapping::TextureHostFileMapping(
413
TextureFlags aFlags, const SurfaceDescriptorFileMapping& aDescriptor)
414
: TextureHostDirectUpload(aFlags, aDescriptor.format(), aDescriptor.size()),
415
mFileMapping((HANDLE)aDescriptor.handle()) {}
416
417
TextureHostFileMapping::~TextureHostFileMapping() {
418
::CloseHandle(mFileMapping);
419
}
420
421
UserDataKey kFileMappingKey;
422
423
static void UnmapFileData(void* aData) {
424
MOZ_ASSERT(aData);
425
::UnmapViewOfFile(aData);
426
}
427
428
void TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion) {
429
if (!mProvider) {
430
// This can happen if we send textures to a compositable that isn't yet
431
// attached to a layer.
432
return;
433
}
434
435
if (!mTextureSource) {
436
mTextureSource = mProvider->CreateDataTextureSource(mFlags);
437
}
438
439
uint8_t* data = nullptr;
440
int32_t totalBytes = BufferSizeFromDimensions(mSize.width, mSize.height,
441
BytesPerPixel(mFormat));
442
if (totalBytes > 0) {
443
data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_READ, 0, 0,
444
totalBytes);
445
}
446
447
if (data) {
448
RefPtr<DataSourceSurface> surf = Factory::CreateWrappingDataSourceSurface(
449
data, mSize.width * BytesPerPixel(mFormat), mSize, mFormat);
450
if (surf) {
451
surf->AddUserData(&kFileMappingKey, data, UnmapFileData);
452
if (!mTextureSource->Update(surf, const_cast<nsIntRegion*>(aRegion))) {
453
mTextureSource = nullptr;
454
}
455
} else {
456
mTextureSource = nullptr;
457
}
458
} else {
459
mTextureSource = nullptr;
460
}
461
462
ReadUnlock();
463
}
464
465
} // namespace layers
466
} // namespace mozilla