Bug 1835804 - Completely block from doing audio decoding on Content and RDD r=alwu
[gecko.git] / gfx / layers / BufferTexture.cpp
bloba3cedc18407ecce2fd7ffce76862067010e93c9a
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"
9 #include <utility>
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"
20 #include "gfxPlatform.h"
22 #ifdef MOZ_WIDGET_GTK
23 # include "gfxPlatformGtk.h"
24 #endif
26 using mozilla::ipc::IShmemAllocator;
28 namespace mozilla {
29 namespace layers {
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);
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),
54 mBuffer(aBuffer),
55 mBufferSize(aBufferSize),
56 mAutoDeallocate(aAutoDeallocate) {
57 MOZ_ASSERT(aBuffer);
58 MOZ_ASSERT(aBufferSize);
61 virtual ~MemoryTextureData() override {
62 if (mAutoDeallocate) {
63 Deallocate(nullptr);
67 virtual uint8_t* GetBuffer() override { return mBuffer; }
69 virtual size_t GetBufferSize() override { return mBufferSize; }
71 protected:
72 uint8_t* mBuffer;
73 size_t mBufferSize;
74 bool mAutoDeallocate;
77 class ShmemTextureData : public BufferTextureData {
78 public:
79 static ShmemTextureData* Create(gfx::IntSize aSize,
80 gfx::SurfaceFormat aFormat,
81 gfx::BackendType aMoz2DBackend,
82 LayersBackend aLayersBackend,
83 TextureFlags aFlags,
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>(); }
106 protected:
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,
118 aAllocator);
119 } else {
120 return ShmemTextureData::Create(aSize, aFormat, aMoz2DBackend,
121 aLayersBackend, aFlags, aAllocFlags,
122 aAllocator);
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];
132 if (!buffer) {
133 return nullptr;
136 GfxMemoryImageReporter::DidAlloc(buffer);
138 return new MemoryTextureData(aDesc, aMoz2DBackend, buffer, aBufferSize);
139 } else {
140 ipc::Shmem shm;
141 if (!aAllocator->AllocUnsafeShmem(aBufferSize, &shm)) {
142 return nullptr;
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);
158 if (bufSize == 0) {
159 return nullptr;
162 uint32_t yOffset;
163 uint32_t cbOffset;
164 uint32_t crOffset;
165 ImageDataSerializer::ComputeYCbCrOffsets(aYStride, aYSize.height, aCbCrStride,
166 aCbCrSize.height, yOffset, cbOffset,
167 crOffset);
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;
189 break;
190 default:
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(
233 mDescriptor);
236 gfx::SurfaceFormat BufferTextureData::GetFormat() const {
237 return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
240 already_AddRefed<gfx::DrawTarget> BufferTextureData::BorrowDrawTarget() {
241 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
242 return nullptr;
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);
253 if (!dt) {
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,
257 rgb.format(), true);
260 if (!dt) {
261 gfxCriticalNote << "BorrowDrawTarget failure, original backend "
262 << (int)mMoz2DBackend;
265 return dt.forget();
268 bool BufferTextureData::BorrowMappedData(MappedTextureData& aData) {
269 if (GetFormat() == gfx::SurfaceFormat::YUV) {
270 return false;
273 gfx::IntSize size = GetSize();
275 aData.data = GetBuffer();
276 aData.size = size;
277 aData.format = GetFormat();
278 aData.stride =
279 ImageDataSerializer::ComputeRGBStride(aData.format, size.width);
281 return true;
284 bool BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) {
285 if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
286 return false;
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();
301 aMap.y.size = ySize;
302 aMap.y.stride = desc.yStride();
303 aMap.y.skip = 0;
304 aMap.y.bytesPerPixel = bytesPerPixel;
306 aMap.cb.data = data + desc.cbOffset();
307 aMap.cb.size = cbCrSize;
308 aMap.cb.stride = desc.cbCrStride();
309 aMap.cb.skip = 0;
310 aMap.cb.bytesPerPixel = bytesPerPixel;
312 aMap.cr.data = data + desc.crOffset();
313 aMap.cr.size = cbCrSize;
314 aMap.cr.stride = desc.cbCrStride();
315 aMap.cr.skip = 0;
316 aMap.cr.bytesPerPixel = bytesPerPixel;
318 return true;
321 bool BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
322 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
323 return false;
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());
332 if (!surface) {
333 gfxCriticalError() << "Failed to get serializer as surface!";
334 return false;
337 RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();
339 if (!srcSurf) {
340 gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT).";
341 return false;
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();
351 return false;
354 gfx::DataSourceSurface::MappedSurface sourceMap;
355 gfx::DataSourceSurface::MappedSurface destMap;
356 if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
357 gfxCriticalError()
358 << "Failed to map source surface for UpdateFromSurface (BT).";
359 return false;
362 if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) {
363 srcSurf->Unmap();
364 gfxCriticalError()
365 << "Failed to map destination surface for UpdateFromSurface.";
366 return false;
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()));
375 srcSurf->Unmap();
376 surface->Unmap();
378 return true;
381 bool MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
382 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
383 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
384 return false;
387 uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
388 aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
390 return true;
393 static bool InitBuffer(uint8_t* buf, size_t bufSize, gfx::SurfaceFormat aFormat,
394 TextureAllocationFlags aAllocFlags, bool aAlreadyZero) {
395 if (!buf) {
396 gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize
397 << " bytes";
398 return false;
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,
406 0xFF000000);
407 } else if (!aAlreadyZero) {
408 memset(buf, 0, bufSize);
412 return true;
415 MemoryTextureData* MemoryTextureData::Create(gfx::IntSize aSize,
416 gfx::SurfaceFormat aFormat,
417 gfx::BackendType aMoz2DBackend,
418 LayersBackend aLayersBackend,
419 TextureFlags aFlags,
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"
427 << aSize.height;
428 return nullptr;
431 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
432 if (!bufSize) {
433 return nullptr;
436 uint8_t* buf = new (fallible) uint8_t[bufSize];
437 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, false)) {
438 return nullptr;
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,
449 autoDeallocate);
452 void MemoryTextureData::Deallocate(LayersIPCChannel*) {
453 MOZ_ASSERT(mBuffer);
454 GfxMemoryImageReporter::WillFree(mBuffer);
455 delete[] mBuffer;
456 mBuffer = nullptr;
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,
464 aAllocator);
467 bool ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
468 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
469 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
470 return false;
473 aOutDescriptor =
474 SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(std::move(mShmem)));
476 return true;
479 ShmemTextureData* ShmemTextureData::Create(gfx::IntSize aSize,
480 gfx::SurfaceFormat aFormat,
481 gfx::BackendType aMoz2DBackend,
482 LayersBackend aLayersBackend,
483 TextureFlags aFlags,
484 TextureAllocationFlags aAllocFlags,
485 IShmemAllocator* aAllocator) {
486 MOZ_ASSERT(aAllocator);
487 // Should have used CreateForYCbCr.
488 MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
490 if (!aAllocator) {
491 return nullptr;
494 if (aSize.width <= 0 || aSize.height <= 0) {
495 gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x"
496 << aSize.height;
497 return nullptr;
500 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
501 if (!bufSize) {
502 return nullptr;
505 mozilla::ipc::Shmem shm;
506 if (!aAllocator->AllocUnsafeShmem(bufSize, &shm)) {
507 return nullptr;
510 uint8_t* buf = shm.get<uint8_t>();
511 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, true)) {
512 return nullptr;
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,
525 aAllocator);
528 void ShmemTextureData::Deallocate(LayersIPCChannel* aAllocator) {
529 aAllocator->DeallocShmem(mShmem);
532 } // namespace layers
533 } // namespace mozilla