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