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 "BufferTexture.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"
20 #include "gfxPlatform.h"
23 # include "gfxPlatformGtk.h"
26 using mozilla::ipc::IShmemAllocator
;
31 class MemoryTextureData
: public BufferTextureData
{
33 static MemoryTextureData
* Create(gfx::IntSize aSize
,
34 gfx::SurfaceFormat aFormat
,
35 gfx::BackendType aMoz2DBackend
,
36 LayersBackend aLayersBackend
,
38 TextureAllocationFlags aAllocFlags
,
39 IShmemAllocator
* aAllocator
);
41 virtual TextureData
* CreateSimilar(
42 LayersIPCChannel
* aAllocator
, LayersBackend aLayersBackend
,
43 TextureFlags aFlags
= TextureFlags::DEFAULT
,
44 TextureAllocationFlags aAllocFlags
= ALLOC_DEFAULT
) const override
;
46 virtual bool Serialize(SurfaceDescriptor
& aOutDescriptor
) override
;
48 virtual void Deallocate(LayersIPCChannel
*) override
;
50 MemoryTextureData(const BufferDescriptor
& aDesc
,
51 gfx::BackendType aMoz2DBackend
, uint8_t* aBuffer
,
52 size_t aBufferSize
, bool aAutoDeallocate
= false)
53 : BufferTextureData(aDesc
, aMoz2DBackend
),
55 mBufferSize(aBufferSize
),
56 mAutoDeallocate(aAutoDeallocate
) {
58 MOZ_ASSERT(aBufferSize
);
61 virtual ~MemoryTextureData() override
{
62 if (mAutoDeallocate
) {
67 virtual uint8_t* GetBuffer() override
{ return mBuffer
; }
69 virtual size_t GetBufferSize() override
{ return mBufferSize
; }
77 class ShmemTextureData
: public BufferTextureData
{
79 static ShmemTextureData
* Create(gfx::IntSize aSize
,
80 gfx::SurfaceFormat aFormat
,
81 gfx::BackendType aMoz2DBackend
,
82 LayersBackend aLayersBackend
,
84 TextureAllocationFlags aAllocFlags
,
85 IShmemAllocator
* aAllocator
);
87 virtual TextureData
* CreateSimilar(
88 LayersIPCChannel
* aAllocator
, LayersBackend aLayersBackend
,
89 TextureFlags aFlags
= TextureFlags::DEFAULT
,
90 TextureAllocationFlags aAllocFlags
= ALLOC_DEFAULT
) const override
;
92 virtual bool Serialize(SurfaceDescriptor
& aOutDescriptor
) override
;
94 virtual void Deallocate(LayersIPCChannel
* aAllocator
) override
;
96 ShmemTextureData(const BufferDescriptor
& aDesc
,
97 gfx::BackendType aMoz2DBackend
, mozilla::ipc::Shmem aShmem
)
98 : BufferTextureData(aDesc
, aMoz2DBackend
), mShmem(aShmem
) {
99 MOZ_ASSERT(mShmem
.Size
<uint8_t>());
102 virtual uint8_t* GetBuffer() override
{ return mShmem
.get
<uint8_t>(); }
104 virtual size_t GetBufferSize() override
{ return mShmem
.Size
<uint8_t>(); }
107 mozilla::ipc::Shmem mShmem
;
110 BufferTextureData
* BufferTextureData::Create(
111 gfx::IntSize aSize
, gfx::SurfaceFormat aFormat
,
112 gfx::BackendType aMoz2DBackend
, LayersBackend aLayersBackend
,
113 TextureFlags aFlags
, TextureAllocationFlags aAllocFlags
,
114 mozilla::ipc::IShmemAllocator
* aAllocator
, bool aIsSameProcess
) {
115 if (!aAllocator
|| aIsSameProcess
) {
116 return MemoryTextureData::Create(aSize
, aFormat
, aMoz2DBackend
,
117 aLayersBackend
, aFlags
, aAllocFlags
,
120 return ShmemTextureData::Create(aSize
, aFormat
, aMoz2DBackend
,
121 aLayersBackend
, aFlags
, aAllocFlags
,
126 BufferTextureData
* BufferTextureData::CreateInternal(
127 LayersIPCChannel
* aAllocator
, const BufferDescriptor
& aDesc
,
128 gfx::BackendType aMoz2DBackend
, int32_t aBufferSize
,
129 TextureFlags aTextureFlags
) {
130 if (!aAllocator
|| aAllocator
->IsSameProcess()) {
131 uint8_t* buffer
= new (fallible
) uint8_t[aBufferSize
];
136 GfxMemoryImageReporter::DidAlloc(buffer
);
138 return new MemoryTextureData(aDesc
, aMoz2DBackend
, buffer
, aBufferSize
);
141 if (!aAllocator
->AllocUnsafeShmem(aBufferSize
, &shm
)) {
145 return new ShmemTextureData(aDesc
, aMoz2DBackend
, shm
);
149 BufferTextureData
* BufferTextureData::CreateForYCbCr(
150 KnowsCompositor
* aAllocator
, const gfx::IntRect
& aDisplay
,
151 const gfx::IntSize
& aYSize
, uint32_t aYStride
,
152 const gfx::IntSize
& aCbCrSize
, uint32_t aCbCrStride
, StereoMode aStereoMode
,
153 gfx::ColorDepth aColorDepth
, gfx::YUVColorSpace aYUVColorSpace
,
154 gfx::ColorRange aColorRange
, gfx::ChromaSubsampling aSubsampling
,
155 TextureFlags aTextureFlags
) {
156 uint32_t bufSize
= ImageDataSerializer::ComputeYCbCrBufferSize(
157 aYSize
, aYStride
, aCbCrSize
, aCbCrStride
);
165 ImageDataSerializer::ComputeYCbCrOffsets(aYStride
, aYSize
.height
, aCbCrStride
,
166 aCbCrSize
.height
, yOffset
, cbOffset
,
169 YCbCrDescriptor descriptor
=
170 YCbCrDescriptor(aDisplay
, aYSize
, aYStride
, aCbCrSize
, aCbCrStride
,
171 yOffset
, cbOffset
, crOffset
, aStereoMode
, aColorDepth
,
172 aYUVColorSpace
, aColorRange
, aSubsampling
);
174 return CreateInternal(
175 aAllocator
? aAllocator
->GetTextureForwarder() : nullptr, descriptor
,
176 gfx::BackendType::NONE
, bufSize
, aTextureFlags
);
179 void BufferTextureData::FillInfo(TextureData::Info
& aInfo
) const {
180 aInfo
.size
= GetSize();
181 aInfo
.format
= GetFormat();
182 aInfo
.hasSynchronization
= false;
183 aInfo
.canExposeMappedData
= true;
185 switch (aInfo
.format
) {
186 case gfx::SurfaceFormat::YUV
:
187 case gfx::SurfaceFormat::UNKNOWN
:
188 aInfo
.supportsMoz2D
= false;
191 aInfo
.supportsMoz2D
= true;
195 gfx::IntSize
BufferTextureData::GetSize() const {
196 return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor
);
199 gfx::IntRect
BufferTextureData::GetPictureRect() const {
200 return ImageDataSerializer::RectFromBufferDescriptor(mDescriptor
);
203 Maybe
<gfx::IntSize
> BufferTextureData::GetYSize() const {
204 return ImageDataSerializer::YSizeFromBufferDescriptor(mDescriptor
);
207 Maybe
<gfx::IntSize
> BufferTextureData::GetCbCrSize() const {
208 return ImageDataSerializer::CbCrSizeFromBufferDescriptor(mDescriptor
);
211 Maybe
<int32_t> BufferTextureData::GetYStride() const {
212 return ImageDataSerializer::YStrideFromBufferDescriptor(mDescriptor
);
215 Maybe
<int32_t> BufferTextureData::GetCbCrStride() const {
216 return ImageDataSerializer::CbCrStrideFromBufferDescriptor(mDescriptor
);
219 Maybe
<gfx::YUVColorSpace
> BufferTextureData::GetYUVColorSpace() const {
220 return ImageDataSerializer::YUVColorSpaceFromBufferDescriptor(mDescriptor
);
223 Maybe
<gfx::ColorDepth
> BufferTextureData::GetColorDepth() const {
224 return ImageDataSerializer::ColorDepthFromBufferDescriptor(mDescriptor
);
227 Maybe
<StereoMode
> BufferTextureData::GetStereoMode() const {
228 return ImageDataSerializer::StereoModeFromBufferDescriptor(mDescriptor
);
231 Maybe
<gfx::ChromaSubsampling
> BufferTextureData::GetChromaSubsampling() const {
232 return ImageDataSerializer::ChromaSubsamplingFromBufferDescriptor(
236 gfx::SurfaceFormat
BufferTextureData::GetFormat() const {
237 return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor
);
240 already_AddRefed
<gfx::DrawTarget
> BufferTextureData::BorrowDrawTarget() {
241 if (mDescriptor
.type() != BufferDescriptor::TRGBDescriptor
) {
245 const RGBDescriptor
& rgb
= mDescriptor
.get_RGBDescriptor();
247 uint32_t stride
= ImageDataSerializer::GetRGBStride(rgb
);
248 RefPtr
<gfx::DrawTarget
> dt
;
249 if (gfx::Factory::DoesBackendSupportDataDrawtarget(mMoz2DBackend
)) {
250 dt
= gfx::Factory::CreateDrawTargetForData(
251 mMoz2DBackend
, GetBuffer(), rgb
.size(), stride
, rgb
.format(), true);
254 // Fall back to supported platform backend. Note that mMoz2DBackend
255 // does not match the draw target type.
256 dt
= gfxPlatform::CreateDrawTargetForData(GetBuffer(), rgb
.size(), stride
,
261 gfxCriticalNote
<< "BorrowDrawTarget failure, original backend "
262 << (int)mMoz2DBackend
;
268 bool BufferTextureData::BorrowMappedData(MappedTextureData
& aData
) {
269 if (GetFormat() == gfx::SurfaceFormat::YUV
) {
273 gfx::IntSize size
= GetSize();
275 aData
.data
= GetBuffer();
277 aData
.format
= GetFormat();
279 ImageDataSerializer::ComputeRGBStride(aData
.format
, size
.width
);
284 bool BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData
& aMap
) {
285 if (mDescriptor
.type() != BufferDescriptor::TYCbCrDescriptor
) {
289 const YCbCrDescriptor
& desc
= mDescriptor
.get_YCbCrDescriptor();
291 uint8_t* data
= GetBuffer();
292 auto ySize
= desc
.ySize();
293 auto cbCrSize
= desc
.cbCrSize();
295 aMap
.stereoMode
= desc
.stereoMode();
296 aMap
.metadata
= nullptr;
297 uint32_t bytesPerPixel
=
298 BytesPerPixel(SurfaceFormatForColorDepth(desc
.colorDepth()));
300 aMap
.y
.data
= data
+ desc
.yOffset();
302 aMap
.y
.stride
= desc
.yStride();
304 aMap
.y
.bytesPerPixel
= bytesPerPixel
;
306 aMap
.cb
.data
= data
+ desc
.cbOffset();
307 aMap
.cb
.size
= cbCrSize
;
308 aMap
.cb
.stride
= desc
.cbCrStride();
310 aMap
.cb
.bytesPerPixel
= bytesPerPixel
;
312 aMap
.cr
.data
= data
+ desc
.crOffset();
313 aMap
.cr
.size
= cbCrSize
;
314 aMap
.cr
.stride
= desc
.cbCrStride();
316 aMap
.cr
.bytesPerPixel
= bytesPerPixel
;
321 bool BufferTextureData::UpdateFromSurface(gfx::SourceSurface
* aSurface
) {
322 if (mDescriptor
.type() != BufferDescriptor::TRGBDescriptor
) {
325 const RGBDescriptor
& rgb
= mDescriptor
.get_RGBDescriptor();
327 uint32_t stride
= ImageDataSerializer::GetRGBStride(rgb
);
328 RefPtr
<gfx::DataSourceSurface
> surface
=
329 gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride
,
330 rgb
.size(), rgb
.format());
333 gfxCriticalError() << "Failed to get serializer as surface!";
337 RefPtr
<gfx::DataSourceSurface
> srcSurf
= aSurface
->GetDataSurface();
340 gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT).";
344 if (surface
->GetSize() != srcSurf
->GetSize() ||
345 surface
->GetFormat() != srcSurf
->GetFormat()) {
346 gfxCriticalError() << "Attempt to update texture client from a surface "
347 "with a different size or format (BT)! This: "
348 << surface
->GetSize() << " " << surface
->GetFormat()
349 << " Other: " << aSurface
->GetSize() << " "
350 << aSurface
->GetFormat();
354 gfx::DataSourceSurface::MappedSurface sourceMap
;
355 gfx::DataSourceSurface::MappedSurface destMap
;
356 if (!srcSurf
->Map(gfx::DataSourceSurface::READ
, &sourceMap
)) {
358 << "Failed to map source surface for UpdateFromSurface (BT).";
362 if (!surface
->Map(gfx::DataSourceSurface::WRITE
, &destMap
)) {
365 << "Failed to map destination surface for UpdateFromSurface.";
369 for (int y
= 0; y
< srcSurf
->GetSize().height
; y
++) {
370 memcpy(destMap
.mData
+ destMap
.mStride
* y
,
371 sourceMap
.mData
+ sourceMap
.mStride
* y
,
372 srcSurf
->GetSize().width
* BytesPerPixel(srcSurf
->GetFormat()));
381 bool MemoryTextureData::Serialize(SurfaceDescriptor
& aOutDescriptor
) {
382 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN
);
383 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN
) {
387 uintptr_t ptr
= reinterpret_cast<uintptr_t>(mBuffer
);
388 aOutDescriptor
= SurfaceDescriptorBuffer(mDescriptor
, MemoryOrShmem(ptr
));
393 static bool InitBuffer(uint8_t* buf
, size_t bufSize
, gfx::SurfaceFormat aFormat
,
394 TextureAllocationFlags aAllocFlags
, bool aAlreadyZero
) {
396 gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize
401 if (aAllocFlags
& ALLOC_CLEAR_BUFFER
) {
402 if (aFormat
== gfx::SurfaceFormat::B8G8R8X8
) {
403 // Even though BGRX was requested, XRGB_UINT32 is what is meant,
404 // so use 0xFF000000 to put alpha in the right place.
405 libyuv::ARGBRect(buf
, bufSize
, 0, 0, bufSize
/ sizeof(uint32_t), 1,
407 } else if (!aAlreadyZero
) {
408 memset(buf
, 0, bufSize
);
415 MemoryTextureData
* MemoryTextureData::Create(gfx::IntSize aSize
,
416 gfx::SurfaceFormat aFormat
,
417 gfx::BackendType aMoz2DBackend
,
418 LayersBackend aLayersBackend
,
420 TextureAllocationFlags aAllocFlags
,
421 IShmemAllocator
* aAllocator
) {
422 // Should have used CreateForYCbCr.
423 MOZ_ASSERT(aFormat
!= gfx::SurfaceFormat::YUV
);
425 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
426 gfxDebug() << "Asking for buffer of invalid size " << aSize
.width
<< "x"
431 uint32_t bufSize
= ImageDataSerializer::ComputeRGBBufferSize(aSize
, aFormat
);
436 uint8_t* buf
= new (fallible
) uint8_t[bufSize
];
437 if (!InitBuffer(buf
, bufSize
, aFormat
, aAllocFlags
, false)) {
441 GfxMemoryImageReporter::DidAlloc(buf
);
443 BufferDescriptor descriptor
= RGBDescriptor(aSize
, aFormat
);
445 // Remote textures are not managed by a texture client, so we need to ensure
446 // that memory is freed when the owning MemoryTextureData goes away.
447 bool autoDeallocate
= !!(aFlags
& TextureFlags::REMOTE_TEXTURE
);
448 return new MemoryTextureData(descriptor
, aMoz2DBackend
, buf
, bufSize
,
452 void MemoryTextureData::Deallocate(LayersIPCChannel
*) {
454 GfxMemoryImageReporter::WillFree(mBuffer
);
459 TextureData
* MemoryTextureData::CreateSimilar(
460 LayersIPCChannel
* aAllocator
, LayersBackend aLayersBackend
,
461 TextureFlags aFlags
, TextureAllocationFlags aAllocFlags
) const {
462 return MemoryTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend
,
463 aLayersBackend
, aFlags
, aAllocFlags
,
467 bool ShmemTextureData::Serialize(SurfaceDescriptor
& aOutDescriptor
) {
468 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN
);
469 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN
) {
474 SurfaceDescriptorBuffer(mDescriptor
, MemoryOrShmem(std::move(mShmem
)));
479 ShmemTextureData
* ShmemTextureData::Create(gfx::IntSize aSize
,
480 gfx::SurfaceFormat aFormat
,
481 gfx::BackendType aMoz2DBackend
,
482 LayersBackend aLayersBackend
,
484 TextureAllocationFlags aAllocFlags
,
485 IShmemAllocator
* aAllocator
) {
486 MOZ_ASSERT(aAllocator
);
487 // Should have used CreateForYCbCr.
488 MOZ_ASSERT(aFormat
!= gfx::SurfaceFormat::YUV
);
494 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
495 gfxDebug() << "Asking for buffer of invalid size " << aSize
.width
<< "x"
500 uint32_t bufSize
= ImageDataSerializer::ComputeRGBBufferSize(aSize
, aFormat
);
505 mozilla::ipc::Shmem shm
;
506 if (!aAllocator
->AllocUnsafeShmem(bufSize
, &shm
)) {
510 uint8_t* buf
= shm
.get
<uint8_t>();
511 if (!InitBuffer(buf
, bufSize
, aFormat
, aAllocFlags
, true)) {
515 BufferDescriptor descriptor
= RGBDescriptor(aSize
, aFormat
);
517 return new ShmemTextureData(descriptor
, aMoz2DBackend
, shm
);
520 TextureData
* ShmemTextureData::CreateSimilar(
521 LayersIPCChannel
* aAllocator
, LayersBackend aLayersBackend
,
522 TextureFlags aFlags
, TextureAllocationFlags aAllocFlags
) const {
523 return ShmemTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend
,
524 aLayersBackend
, aFlags
, aAllocFlags
,
528 void ShmemTextureData::Deallocate(LayersIPCChannel
* aAllocator
) {
529 aAllocator
->DeallocShmem(mShmem
);
532 } // namespace layers
533 } // namespace mozilla