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 "BufferTexture.h"
8
9 #include <utility>
10
11 #include "libyuv.h"
12 #include "mozilla/fallible.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/gfx/Logging.h"
15 #include "mozilla/layers/CompositableForwarder.h"
16 #include "mozilla/layers/ISurfaceAllocator.h"
17 #include "mozilla/layers/ImageDataSerializer.h"
18 #include "mozilla/layers/TextureForwarder.h"
19
20 #include "gfxPlatform.h"
21
22 #ifdef MOZ_WIDGET_GTK
23 # include "gfxPlatformGtk.h"
24 #endif
25
26 using mozilla::ipc::IShmemAllocator;
27
28 namespace mozilla {
29 namespace layers {
30
31 class MemoryTextureData : public BufferTextureData {
32 public:
33 static MemoryTextureData* Create(gfx::IntSize aSize,
34 gfx::SurfaceFormat aFormat,
35 gfx::BackendType aMoz2DBackend,
36 LayersBackend aLayersBackend,
37 TextureFlags aFlags,
38 TextureAllocationFlags aAllocFlags,
39 IShmemAllocator* aAllocator);
40
41 virtual TextureData* CreateSimilar(
42 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
43 TextureFlags aFlags = TextureFlags::DEFAULT,
44 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
45
46 virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
47
48 virtual void Deallocate(LayersIPCChannel*) override;
49
MemoryTextureData(const BufferDescriptor & aDesc,gfx::BackendType aMoz2DBackend,uint8_t * aBuffer,size_t aBufferSize)50 MemoryTextureData(const BufferDescriptor& aDesc,
51 gfx::BackendType aMoz2DBackend, uint8_t* aBuffer,
52 size_t aBufferSize)
53 : BufferTextureData(aDesc, aMoz2DBackend),
54 mBuffer(aBuffer),
55 mBufferSize(aBufferSize) {
56 MOZ_ASSERT(aBuffer);
57 MOZ_ASSERT(aBufferSize);
58 }
59
GetBuffer()60 virtual uint8_t* GetBuffer() override { return mBuffer; }
61
GetBufferSize()62 virtual size_t GetBufferSize() override { return mBufferSize; }
63
64 protected:
65 uint8_t* mBuffer;
66 size_t mBufferSize;
67 };
68
69 class ShmemTextureData : public BufferTextureData {
70 public:
71 static ShmemTextureData* Create(gfx::IntSize aSize,
72 gfx::SurfaceFormat aFormat,
73 gfx::BackendType aMoz2DBackend,
74 LayersBackend aLayersBackend,
75 TextureFlags aFlags,
76 TextureAllocationFlags aAllocFlags,
77 IShmemAllocator* aAllocator);
78
79 virtual TextureData* CreateSimilar(
80 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
81 TextureFlags aFlags = TextureFlags::DEFAULT,
82 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
83
84 virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
85
86 virtual void Deallocate(LayersIPCChannel* aAllocator) override;
87
ShmemTextureData(const BufferDescriptor & aDesc,gfx::BackendType aMoz2DBackend,mozilla::ipc::Shmem aShmem)88 ShmemTextureData(const BufferDescriptor& aDesc,
89 gfx::BackendType aMoz2DBackend, mozilla::ipc::Shmem aShmem)
90 : BufferTextureData(aDesc, aMoz2DBackend), mShmem(aShmem) {
91 MOZ_ASSERT(mShmem.Size<uint8_t>());
92 }
93
GetBuffer()94 virtual uint8_t* GetBuffer() override { return mShmem.get<uint8_t>(); }
95
GetBufferSize()96 virtual size_t GetBufferSize() override { return mShmem.Size<uint8_t>(); }
97
98 protected:
99 mozilla::ipc::Shmem mShmem;
100 };
101
UsingX11Compositor()102 static bool UsingX11Compositor() {
103 #ifdef MOZ_WIDGET_GTK
104 return gfx::gfxVars::UseXRender();
105 #endif
106 return false;
107 }
108
ComputeHasIntermediateBuffer(gfx::SurfaceFormat aFormat,LayersBackend aLayersBackend,bool aSupportsTextureDirectMapping)109 bool ComputeHasIntermediateBuffer(gfx::SurfaceFormat aFormat,
110 LayersBackend aLayersBackend,
111 bool aSupportsTextureDirectMapping) {
112 if (aSupportsTextureDirectMapping) {
113 return false;
114 }
115
116 return aLayersBackend != LayersBackend::LAYERS_BASIC ||
117 UsingX11Compositor() || aFormat == gfx::SurfaceFormat::UNKNOWN;
118 }
119
Create(gfx::IntSize aSize,gfx::SurfaceFormat aFormat,gfx::BackendType aMoz2DBackend,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags,mozilla::ipc::IShmemAllocator * aAllocator,bool aIsSameProcess)120 BufferTextureData* BufferTextureData::Create(
121 gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
122 gfx::BackendType aMoz2DBackend, LayersBackend aLayersBackend,
123 TextureFlags aFlags, TextureAllocationFlags aAllocFlags,
124 mozilla::ipc::IShmemAllocator* aAllocator, bool aIsSameProcess) {
125 if (!aAllocator || aIsSameProcess) {
126 return MemoryTextureData::Create(aSize, aFormat, aMoz2DBackend,
127 aLayersBackend, aFlags, aAllocFlags,
128 aAllocator);
129 } else {
130 return ShmemTextureData::Create(aSize, aFormat, aMoz2DBackend,
131 aLayersBackend, aFlags, aAllocFlags,
132 aAllocator);
133 }
134 }
135
CreateInternal(LayersIPCChannel * aAllocator,const BufferDescriptor & aDesc,gfx::BackendType aMoz2DBackend,int32_t aBufferSize,TextureFlags aTextureFlags)136 BufferTextureData* BufferTextureData::CreateInternal(
137 LayersIPCChannel* aAllocator, const BufferDescriptor& aDesc,
138 gfx::BackendType aMoz2DBackend, int32_t aBufferSize,
139 TextureFlags aTextureFlags) {
140 if (!aAllocator || aAllocator->IsSameProcess()) {
141 uint8_t* buffer = new (fallible) uint8_t[aBufferSize];
142 if (!buffer) {
143 return nullptr;
144 }
145
146 GfxMemoryImageReporter::DidAlloc(buffer);
147
148 return new MemoryTextureData(aDesc, aMoz2DBackend, buffer, aBufferSize);
149 } else {
150 ipc::Shmem shm;
151 if (!aAllocator->AllocUnsafeShmem(aBufferSize, OptimalShmemType(), &shm)) {
152 return nullptr;
153 }
154
155 return new ShmemTextureData(aDesc, aMoz2DBackend, shm);
156 }
157 }
158
CreateForYCbCr(KnowsCompositor * aAllocator,const gfx::IntRect & aDisplay,const gfx::IntSize & aYSize,uint32_t aYStride,const gfx::IntSize & aCbCrSize,uint32_t aCbCrStride,StereoMode aStereoMode,gfx::ColorDepth aColorDepth,gfx::YUVColorSpace aYUVColorSpace,gfx::ColorRange aColorRange,TextureFlags aTextureFlags)159 BufferTextureData* BufferTextureData::CreateForYCbCr(
160 KnowsCompositor* aAllocator, const gfx::IntRect& aDisplay,
161 const gfx::IntSize& aYSize, uint32_t aYStride,
162 const gfx::IntSize& aCbCrSize, uint32_t aCbCrStride, StereoMode aStereoMode,
163 gfx::ColorDepth aColorDepth, gfx::YUVColorSpace aYUVColorSpace,
164 gfx::ColorRange aColorRange, TextureFlags aTextureFlags) {
165 uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(
166 aYSize, aYStride, aCbCrSize, aCbCrStride);
167 if (bufSize == 0) {
168 return nullptr;
169 }
170
171 uint32_t yOffset;
172 uint32_t cbOffset;
173 uint32_t crOffset;
174 ImageDataSerializer::ComputeYCbCrOffsets(aYStride, aYSize.height, aCbCrStride,
175 aCbCrSize.height, yOffset, cbOffset,
176 crOffset);
177
178 bool supportsTextureDirectMapping =
179 aAllocator->SupportsTextureDirectMapping() &&
180 aAllocator->GetMaxTextureSize() >
181 std::max(aYSize.width,
182 std::max(aYSize.height,
183 std::max(aCbCrSize.width, aCbCrSize.height)));
184
185 bool hasIntermediateBuffer =
186 aAllocator
187 ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
188 aAllocator->GetCompositorBackendType(),
189 supportsTextureDirectMapping)
190 : true;
191
192 YCbCrDescriptor descriptor =
193 YCbCrDescriptor(aDisplay, aYSize, aYStride, aCbCrSize, aCbCrStride,
194 yOffset, cbOffset, crOffset, aStereoMode, aColorDepth,
195 aYUVColorSpace, aColorRange, hasIntermediateBuffer);
196
197 return CreateInternal(
198 aAllocator ? aAllocator->GetTextureForwarder() : nullptr, descriptor,
199 gfx::BackendType::NONE, bufSize, aTextureFlags);
200 }
201
FillInfo(TextureData::Info & aInfo) const202 void BufferTextureData::FillInfo(TextureData::Info& aInfo) const {
203 aInfo.size = GetSize();
204 aInfo.format = GetFormat();
205 aInfo.hasSynchronization = false;
206 aInfo.canExposeMappedData = true;
207
208 if (mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor) {
209 aInfo.hasIntermediateBuffer =
210 mDescriptor.get_YCbCrDescriptor().hasIntermediateBuffer();
211 } else {
212 aInfo.hasIntermediateBuffer =
213 mDescriptor.get_RGBDescriptor().hasIntermediateBuffer();
214 }
215
216 switch (aInfo.format) {
217 case gfx::SurfaceFormat::YUV:
218 case gfx::SurfaceFormat::UNKNOWN:
219 aInfo.supportsMoz2D = false;
220 break;
221 default:
222 aInfo.supportsMoz2D = true;
223 }
224 }
225
GetSize() const226 gfx::IntSize BufferTextureData::GetSize() const {
227 return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor);
228 }
229
GetPictureRect() const230 gfx::IntRect BufferTextureData::GetPictureRect() const {
231 return ImageDataSerializer::RectFromBufferDescriptor(mDescriptor);
232 }
233
GetCbCrSize() const234 Maybe<gfx::IntSize> BufferTextureData::GetCbCrSize() const {
235 return ImageDataSerializer::CbCrSizeFromBufferDescriptor(mDescriptor);
236 }
237
GetYStride() const238 Maybe<int32_t> BufferTextureData::GetYStride() const {
239 return ImageDataSerializer::YStrideFromBufferDescriptor(mDescriptor);
240 }
241
GetCbCrStride() const242 Maybe<int32_t> BufferTextureData::GetCbCrStride() const {
243 return ImageDataSerializer::CbCrStrideFromBufferDescriptor(mDescriptor);
244 }
245
GetYUVColorSpace() const246 Maybe<gfx::YUVColorSpace> BufferTextureData::GetYUVColorSpace() const {
247 return ImageDataSerializer::YUVColorSpaceFromBufferDescriptor(mDescriptor);
248 }
249
GetColorDepth() const250 Maybe<gfx::ColorDepth> BufferTextureData::GetColorDepth() const {
251 return ImageDataSerializer::ColorDepthFromBufferDescriptor(mDescriptor);
252 }
253
GetStereoMode() const254 Maybe<StereoMode> BufferTextureData::GetStereoMode() const {
255 return ImageDataSerializer::StereoModeFromBufferDescriptor(mDescriptor);
256 }
257
GetFormat() const258 gfx::SurfaceFormat BufferTextureData::GetFormat() const {
259 return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
260 }
261
BorrowDrawTarget()262 already_AddRefed<gfx::DrawTarget> BufferTextureData::BorrowDrawTarget() {
263 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
264 return nullptr;
265 }
266
267 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
268
269 uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
270 RefPtr<gfx::DrawTarget> dt;
271 if (gfx::Factory::DoesBackendSupportDataDrawtarget(mMoz2DBackend)) {
272 dt = gfx::Factory::CreateDrawTargetForData(
273 mMoz2DBackend, GetBuffer(), rgb.size(), stride, rgb.format(), true);
274 }
275 if (!dt) {
276 // Fall back to supported platform backend. Note that mMoz2DBackend
277 // does not match the draw target type.
278 dt = gfxPlatform::CreateDrawTargetForData(GetBuffer(), rgb.size(), stride,
279 rgb.format(), true);
280 }
281
282 if (!dt) {
283 gfxCriticalNote << "BorrowDrawTarget failure, original backend "
284 << (int)mMoz2DBackend;
285 }
286
287 return dt.forget();
288 }
289
BorrowMappedData(MappedTextureData & aData)290 bool BufferTextureData::BorrowMappedData(MappedTextureData& aData) {
291 if (GetFormat() == gfx::SurfaceFormat::YUV) {
292 return false;
293 }
294
295 gfx::IntSize size = GetSize();
296
297 aData.data = GetBuffer();
298 aData.size = size;
299 aData.format = GetFormat();
300 aData.stride =
301 ImageDataSerializer::ComputeRGBStride(aData.format, size.width);
302
303 return true;
304 }
305
BorrowMappedYCbCrData(MappedYCbCrTextureData & aMap)306 bool BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) {
307 if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
308 return false;
309 }
310
311 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
312
313 uint8_t* data = GetBuffer();
314 auto ySize = desc.ySize();
315 auto cbCrSize = desc.cbCrSize();
316
317 aMap.stereoMode = desc.stereoMode();
318 aMap.metadata = nullptr;
319 uint32_t bytesPerPixel =
320 BytesPerPixel(SurfaceFormatForColorDepth(desc.colorDepth()));
321
322 aMap.y.data = data + desc.yOffset();
323 aMap.y.size = ySize;
324 aMap.y.stride = desc.yStride();
325 aMap.y.skip = 0;
326 aMap.y.bytesPerPixel = bytesPerPixel;
327
328 aMap.cb.data = data + desc.cbOffset();
329 aMap.cb.size = cbCrSize;
330 aMap.cb.stride = desc.cbCrStride();
331 aMap.cb.skip = 0;
332 aMap.cb.bytesPerPixel = bytesPerPixel;
333
334 aMap.cr.data = data + desc.crOffset();
335 aMap.cr.size = cbCrSize;
336 aMap.cr.stride = desc.cbCrStride();
337 aMap.cr.skip = 0;
338 aMap.cr.bytesPerPixel = bytesPerPixel;
339
340 return true;
341 }
342
UpdateFromSurface(gfx::SourceSurface * aSurface)343 bool BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
344 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
345 return false;
346 }
347 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
348
349 uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
350 RefPtr<gfx::DataSourceSurface> surface =
351 gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride,
352 rgb.size(), rgb.format());
353
354 if (!surface) {
355 gfxCriticalError() << "Failed to get serializer as surface!";
356 return false;
357 }
358
359 RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();
360
361 if (!srcSurf) {
362 gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT).";
363 return false;
364 }
365
366 if (surface->GetSize() != srcSurf->GetSize() ||
367 surface->GetFormat() != srcSurf->GetFormat()) {
368 gfxCriticalError() << "Attempt to update texture client from a surface "
369 "with a different size or format (BT)! This: "
370 << surface->GetSize() << " " << surface->GetFormat()
371 << " Other: " << aSurface->GetSize() << " "
372 << aSurface->GetFormat();
373 return false;
374 }
375
376 gfx::DataSourceSurface::MappedSurface sourceMap;
377 gfx::DataSourceSurface::MappedSurface destMap;
378 if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
379 gfxCriticalError()
380 << "Failed to map source surface for UpdateFromSurface (BT).";
381 return false;
382 }
383
384 if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) {
385 srcSurf->Unmap();
386 gfxCriticalError()
387 << "Failed to map destination surface for UpdateFromSurface.";
388 return false;
389 }
390
391 for (int y = 0; y < srcSurf->GetSize().height; y++) {
392 memcpy(destMap.mData + destMap.mStride * y,
393 sourceMap.mData + sourceMap.mStride * y,
394 srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
395 }
396
397 srcSurf->Unmap();
398 surface->Unmap();
399
400 return true;
401 }
402
SetDescriptor(BufferDescriptor && aDescriptor)403 void BufferTextureData::SetDescriptor(BufferDescriptor&& aDescriptor) {
404 MOZ_ASSERT(mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor);
405 MOZ_ASSERT(mDescriptor.get_YCbCrDescriptor().ySize() == gfx::IntSize());
406 mDescriptor = std::move(aDescriptor);
407 }
408
Serialize(SurfaceDescriptor & aOutDescriptor)409 bool MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
410 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
411 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
412 return false;
413 }
414
415 uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
416 aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
417
418 return true;
419 }
420
InitBuffer(uint8_t * buf,size_t bufSize,gfx::SurfaceFormat aFormat,TextureAllocationFlags aAllocFlags,bool aAlreadyZero)421 static bool InitBuffer(uint8_t* buf, size_t bufSize, gfx::SurfaceFormat aFormat,
422 TextureAllocationFlags aAllocFlags, bool aAlreadyZero) {
423 if (!buf) {
424 gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize
425 << " bytes";
426 return false;
427 }
428
429 if ((aAllocFlags & ALLOC_CLEAR_BUFFER) ||
430 (aAllocFlags & ALLOC_CLEAR_BUFFER_BLACK)) {
431 if (aFormat == gfx::SurfaceFormat::B8G8R8X8) {
432 // Even though BGRX was requested, XRGB_UINT32 is what is meant,
433 // so use 0xFF000000 to put alpha in the right place.
434 libyuv::ARGBRect(buf, bufSize, 0, 0, bufSize / sizeof(uint32_t), 1,
435 0xFF000000);
436 } else if (!aAlreadyZero) {
437 memset(buf, 0, bufSize);
438 }
439 }
440
441 if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) {
442 memset(buf, 0xFF, bufSize);
443 }
444
445 return true;
446 }
447
Create(gfx::IntSize aSize,gfx::SurfaceFormat aFormat,gfx::BackendType aMoz2DBackend,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags,IShmemAllocator * aAllocator)448 MemoryTextureData* MemoryTextureData::Create(gfx::IntSize aSize,
449 gfx::SurfaceFormat aFormat,
450 gfx::BackendType aMoz2DBackend,
451 LayersBackend aLayersBackend,
452 TextureFlags aFlags,
453 TextureAllocationFlags aAllocFlags,
454 IShmemAllocator* aAllocator) {
455 // Should have used CreateForYCbCr.
456 MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
457
458 if (aSize.width <= 0 || aSize.height <= 0) {
459 gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x"
460 << aSize.height;
461 return nullptr;
462 }
463
464 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
465 if (!bufSize) {
466 return nullptr;
467 }
468
469 uint8_t* buf = new (fallible) uint8_t[bufSize];
470 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, false)) {
471 return nullptr;
472 }
473
474 bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(
475 aFormat, aLayersBackend, aAllocFlags & ALLOC_ALLOW_DIRECT_MAPPING);
476
477 GfxMemoryImageReporter::DidAlloc(buf);
478
479 BufferDescriptor descriptor =
480 RGBDescriptor(aSize, aFormat, hasIntermediateBuffer);
481
482 return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize);
483 }
484
Deallocate(LayersIPCChannel *)485 void MemoryTextureData::Deallocate(LayersIPCChannel*) {
486 MOZ_ASSERT(mBuffer);
487 GfxMemoryImageReporter::WillFree(mBuffer);
488 delete[] mBuffer;
489 mBuffer = nullptr;
490 }
491
CreateSimilar(LayersIPCChannel * aAllocator,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags) const492 TextureData* MemoryTextureData::CreateSimilar(
493 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
494 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
495 return MemoryTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
496 aLayersBackend, aFlags, aAllocFlags,
497 aAllocator);
498 }
499
Serialize(SurfaceDescriptor & aOutDescriptor)500 bool ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
501 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
502 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
503 return false;
504 }
505
506 aOutDescriptor =
507 SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(std::move(mShmem)));
508
509 return true;
510 }
511
Create(gfx::IntSize aSize,gfx::SurfaceFormat aFormat,gfx::BackendType aMoz2DBackend,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags,IShmemAllocator * aAllocator)512 ShmemTextureData* ShmemTextureData::Create(gfx::IntSize aSize,
513 gfx::SurfaceFormat aFormat,
514 gfx::BackendType aMoz2DBackend,
515 LayersBackend aLayersBackend,
516 TextureFlags aFlags,
517 TextureAllocationFlags aAllocFlags,
518 IShmemAllocator* aAllocator) {
519 MOZ_ASSERT(aAllocator);
520 // Should have used CreateForYCbCr.
521 MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
522
523 if (!aAllocator) {
524 return nullptr;
525 }
526
527 if (aSize.width <= 0 || aSize.height <= 0) {
528 gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x"
529 << aSize.height;
530 return nullptr;
531 }
532
533 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
534 if (!bufSize) {
535 return nullptr;
536 }
537
538 mozilla::ipc::Shmem shm;
539 if (!aAllocator->AllocUnsafeShmem(bufSize, OptimalShmemType(), &shm)) {
540 return nullptr;
541 }
542
543 uint8_t* buf = shm.get<uint8_t>();
544 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, true)) {
545 return nullptr;
546 }
547
548 bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(
549 aFormat, aLayersBackend, aAllocFlags & ALLOC_ALLOW_DIRECT_MAPPING);
550
551 BufferDescriptor descriptor =
552 RGBDescriptor(aSize, aFormat, hasIntermediateBuffer);
553
554 return new ShmemTextureData(descriptor, aMoz2DBackend, shm);
555 }
556
CreateSimilar(LayersIPCChannel * aAllocator,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags) const557 TextureData* ShmemTextureData::CreateSimilar(
558 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
559 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
560 return ShmemTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
561 aLayersBackend, aFlags, aAllocFlags,
562 aAllocator);
563 }
564
Deallocate(LayersIPCChannel * aAllocator)565 void ShmemTextureData::Deallocate(LayersIPCChannel* aAllocator) {
566 aAllocator->DeallocShmem(mShmem);
567 }
568
569 } // namespace layers
570 } // namespace mozilla
571