Bug 1891710: part 2) Enable <Element-outerHTML.html> WPT for Trusted Types. r=smaug
[gecko.git] / gfx / layers / BufferTexture.cpp
blob61d63874dc1cd1af14dc7992fc42f85c8993f7ef
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 TextureType GetTextureType() const override { return TextureType::Unknown; }
73 protected:
74 uint8_t* mBuffer;
75 size_t mBufferSize;
76 bool mAutoDeallocate;
79 class ShmemTextureData : public BufferTextureData {
80 public:
81 static ShmemTextureData* Create(gfx::IntSize aSize,
82 gfx::SurfaceFormat aFormat,
83 gfx::BackendType aMoz2DBackend,
84 LayersBackend aLayersBackend,
85 TextureFlags aFlags,
86 TextureAllocationFlags aAllocFlags,
87 IShmemAllocator* aAllocator);
89 virtual TextureData* CreateSimilar(
90 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
91 TextureFlags aFlags = TextureFlags::DEFAULT,
92 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
94 virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
96 virtual void Deallocate(LayersIPCChannel* aAllocator) override;
98 ShmemTextureData(const BufferDescriptor& aDesc,
99 gfx::BackendType aMoz2DBackend, mozilla::ipc::Shmem aShmem)
100 : BufferTextureData(aDesc, aMoz2DBackend), mShmem(aShmem) {
101 MOZ_ASSERT(mShmem.Size<uint8_t>());
104 virtual uint8_t* GetBuffer() override { return mShmem.get<uint8_t>(); }
106 virtual size_t GetBufferSize() override { return mShmem.Size<uint8_t>(); }
108 protected:
109 mozilla::ipc::Shmem mShmem;
112 BufferTextureData* BufferTextureData::Create(
113 gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
114 gfx::BackendType aMoz2DBackend, LayersBackend aLayersBackend,
115 TextureFlags aFlags, TextureAllocationFlags aAllocFlags,
116 mozilla::ipc::IShmemAllocator* aAllocator, bool aIsSameProcess) {
117 if (!aAllocator || aIsSameProcess) {
118 return MemoryTextureData::Create(aSize, aFormat, aMoz2DBackend,
119 aLayersBackend, aFlags, aAllocFlags,
120 aAllocator);
121 } else {
122 return ShmemTextureData::Create(aSize, aFormat, aMoz2DBackend,
123 aLayersBackend, aFlags, aAllocFlags,
124 aAllocator);
128 BufferTextureData* BufferTextureData::CreateInternal(
129 LayersIPCChannel* aAllocator, const BufferDescriptor& aDesc,
130 gfx::BackendType aMoz2DBackend, int32_t aBufferSize,
131 TextureFlags aTextureFlags) {
132 if (!aAllocator || aAllocator->IsSameProcess()) {
133 uint8_t* buffer = new (fallible) uint8_t[aBufferSize];
134 if (!buffer) {
135 return nullptr;
138 GfxMemoryImageReporter::DidAlloc(buffer);
140 return new MemoryTextureData(aDesc, aMoz2DBackend, buffer, aBufferSize);
141 } else {
142 ipc::Shmem shm;
143 if (!aAllocator->AllocUnsafeShmem(aBufferSize, &shm)) {
144 return nullptr;
147 return new ShmemTextureData(aDesc, aMoz2DBackend, shm);
151 BufferTextureData* BufferTextureData::CreateForYCbCr(
152 KnowsCompositor* aAllocator, const gfx::IntRect& aDisplay,
153 const gfx::IntSize& aYSize, uint32_t aYStride,
154 const gfx::IntSize& aCbCrSize, uint32_t aCbCrStride, StereoMode aStereoMode,
155 gfx::ColorDepth aColorDepth, gfx::YUVColorSpace aYUVColorSpace,
156 gfx::ColorRange aColorRange, gfx::ChromaSubsampling aSubsampling,
157 TextureFlags aTextureFlags) {
158 uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(
159 aYSize, aYStride, aCbCrSize, aCbCrStride);
160 if (bufSize == 0) {
161 return nullptr;
164 uint32_t yOffset;
165 uint32_t cbOffset;
166 uint32_t crOffset;
167 ImageDataSerializer::ComputeYCbCrOffsets(aYStride, aYSize.height, aCbCrStride,
168 aCbCrSize.height, yOffset, cbOffset,
169 crOffset);
171 YCbCrDescriptor descriptor =
172 YCbCrDescriptor(aDisplay, aYSize, aYStride, aCbCrSize, aCbCrStride,
173 yOffset, cbOffset, crOffset, aStereoMode, aColorDepth,
174 aYUVColorSpace, aColorRange, aSubsampling);
176 return CreateInternal(
177 aAllocator ? aAllocator->GetTextureForwarder() : nullptr, descriptor,
178 gfx::BackendType::NONE, bufSize, aTextureFlags);
181 void BufferTextureData::FillInfo(TextureData::Info& aInfo) const {
182 aInfo.size = GetSize();
183 aInfo.format = GetFormat();
184 aInfo.hasSynchronization = false;
185 aInfo.canExposeMappedData = true;
187 switch (aInfo.format) {
188 case gfx::SurfaceFormat::YUV:
189 case gfx::SurfaceFormat::UNKNOWN:
190 aInfo.supportsMoz2D = false;
191 break;
192 default:
193 aInfo.supportsMoz2D = true;
197 gfx::IntSize BufferTextureData::GetSize() const {
198 return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor);
201 gfx::IntRect BufferTextureData::GetPictureRect() const {
202 return ImageDataSerializer::RectFromBufferDescriptor(mDescriptor);
205 Maybe<gfx::IntSize> BufferTextureData::GetYSize() const {
206 return ImageDataSerializer::YSizeFromBufferDescriptor(mDescriptor);
209 Maybe<gfx::IntSize> BufferTextureData::GetCbCrSize() const {
210 return ImageDataSerializer::CbCrSizeFromBufferDescriptor(mDescriptor);
213 Maybe<int32_t> BufferTextureData::GetYStride() const {
214 return ImageDataSerializer::YStrideFromBufferDescriptor(mDescriptor);
217 Maybe<int32_t> BufferTextureData::GetCbCrStride() const {
218 return ImageDataSerializer::CbCrStrideFromBufferDescriptor(mDescriptor);
221 Maybe<gfx::YUVColorSpace> BufferTextureData::GetYUVColorSpace() const {
222 return ImageDataSerializer::YUVColorSpaceFromBufferDescriptor(mDescriptor);
225 Maybe<gfx::ColorDepth> BufferTextureData::GetColorDepth() const {
226 return ImageDataSerializer::ColorDepthFromBufferDescriptor(mDescriptor);
229 Maybe<StereoMode> BufferTextureData::GetStereoMode() const {
230 return ImageDataSerializer::StereoModeFromBufferDescriptor(mDescriptor);
233 Maybe<gfx::ChromaSubsampling> BufferTextureData::GetChromaSubsampling() const {
234 return ImageDataSerializer::ChromaSubsamplingFromBufferDescriptor(
235 mDescriptor);
238 gfx::SurfaceFormat BufferTextureData::GetFormat() const {
239 return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
242 already_AddRefed<gfx::DrawTarget> BufferTextureData::BorrowDrawTarget() {
243 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
244 return nullptr;
247 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
249 uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
250 RefPtr<gfx::DrawTarget> dt;
251 if (gfx::Factory::DoesBackendSupportDataDrawtarget(mMoz2DBackend)) {
252 dt = gfx::Factory::CreateDrawTargetForData(
253 mMoz2DBackend, GetBuffer(), rgb.size(), stride, rgb.format(), true);
255 if (!dt) {
256 // Fall back to supported platform backend. Note that mMoz2DBackend
257 // does not match the draw target type.
258 dt = gfxPlatform::CreateDrawTargetForData(GetBuffer(), rgb.size(), stride,
259 rgb.format(), true);
262 if (!dt) {
263 gfxCriticalNote << "BorrowDrawTarget failure, original backend "
264 << (int)mMoz2DBackend;
267 return dt.forget();
270 bool BufferTextureData::BorrowMappedData(MappedTextureData& aData) {
271 if (GetFormat() == gfx::SurfaceFormat::YUV) {
272 return false;
275 gfx::IntSize size = GetSize();
277 aData.data = GetBuffer();
278 aData.size = size;
279 aData.format = GetFormat();
280 aData.stride =
281 ImageDataSerializer::ComputeRGBStride(aData.format, size.width);
283 return true;
286 bool BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) {
287 if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
288 return false;
291 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
293 uint8_t* data = GetBuffer();
294 auto ySize = desc.ySize();
295 auto cbCrSize = desc.cbCrSize();
297 aMap.stereoMode = desc.stereoMode();
298 aMap.metadata = nullptr;
299 uint32_t bytesPerPixel =
300 BytesPerPixel(SurfaceFormatForColorDepth(desc.colorDepth()));
302 aMap.y.data = data + desc.yOffset();
303 aMap.y.size = ySize;
304 aMap.y.stride = desc.yStride();
305 aMap.y.skip = 0;
306 aMap.y.bytesPerPixel = bytesPerPixel;
308 aMap.cb.data = data + desc.cbOffset();
309 aMap.cb.size = cbCrSize;
310 aMap.cb.stride = desc.cbCrStride();
311 aMap.cb.skip = 0;
312 aMap.cb.bytesPerPixel = bytesPerPixel;
314 aMap.cr.data = data + desc.crOffset();
315 aMap.cr.size = cbCrSize;
316 aMap.cr.stride = desc.cbCrStride();
317 aMap.cr.skip = 0;
318 aMap.cr.bytesPerPixel = bytesPerPixel;
320 return true;
323 bool BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
324 if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
325 return false;
327 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
329 uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
330 RefPtr<gfx::DataSourceSurface> surface =
331 gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride,
332 rgb.size(), rgb.format());
334 if (!surface) {
335 gfxCriticalError() << "Failed to get serializer as surface!";
336 return false;
339 RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();
341 if (!srcSurf) {
342 gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT).";
343 return false;
346 if (surface->GetSize() != srcSurf->GetSize() ||
347 surface->GetFormat() != srcSurf->GetFormat()) {
348 gfxCriticalError() << "Attempt to update texture client from a surface "
349 "with a different size or format (BT)! This: "
350 << surface->GetSize() << " " << surface->GetFormat()
351 << " Other: " << aSurface->GetSize() << " "
352 << aSurface->GetFormat();
353 return false;
356 gfx::DataSourceSurface::MappedSurface sourceMap;
357 gfx::DataSourceSurface::MappedSurface destMap;
358 if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
359 gfxCriticalError()
360 << "Failed to map source surface for UpdateFromSurface (BT).";
361 return false;
364 if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) {
365 srcSurf->Unmap();
366 gfxCriticalError()
367 << "Failed to map destination surface for UpdateFromSurface.";
368 return false;
371 for (int y = 0; y < srcSurf->GetSize().height; y++) {
372 memcpy(destMap.mData + destMap.mStride * y,
373 sourceMap.mData + sourceMap.mStride * y,
374 srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
377 srcSurf->Unmap();
378 surface->Unmap();
380 return true;
383 bool MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
384 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
385 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
386 return false;
389 uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
390 aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
392 return true;
395 static bool InitBuffer(uint8_t* buf, size_t bufSize, gfx::SurfaceFormat aFormat,
396 TextureAllocationFlags aAllocFlags, bool aAlreadyZero) {
397 if (!buf) {
398 gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize
399 << " bytes";
400 return false;
403 if (aAllocFlags & ALLOC_CLEAR_BUFFER) {
404 if (aFormat == gfx::SurfaceFormat::B8G8R8X8) {
405 // Even though BGRX was requested, XRGB_UINT32 is what is meant,
406 // so use 0xFF000000 to put alpha in the right place.
407 libyuv::ARGBRect(buf, bufSize, 0, 0, bufSize / sizeof(uint32_t), 1,
408 0xFF000000);
409 } else if (!aAlreadyZero) {
410 memset(buf, 0, bufSize);
414 return true;
417 MemoryTextureData* MemoryTextureData::Create(gfx::IntSize aSize,
418 gfx::SurfaceFormat aFormat,
419 gfx::BackendType aMoz2DBackend,
420 LayersBackend aLayersBackend,
421 TextureFlags aFlags,
422 TextureAllocationFlags aAllocFlags,
423 IShmemAllocator* aAllocator) {
424 // Should have used CreateForYCbCr.
425 MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
427 if (aSize.width <= 0 || aSize.height <= 0) {
428 gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x"
429 << aSize.height;
430 return nullptr;
433 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
434 if (!bufSize) {
435 return nullptr;
438 uint8_t* buf = new (fallible) uint8_t[bufSize];
439 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, false)) {
440 return nullptr;
443 GfxMemoryImageReporter::DidAlloc(buf);
445 BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
447 // Remote textures are not managed by a texture client, so we need to ensure
448 // that memory is freed when the owning MemoryTextureData goes away.
449 bool autoDeallocate = !!(aFlags & TextureFlags::REMOTE_TEXTURE);
450 return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize,
451 autoDeallocate);
454 void MemoryTextureData::Deallocate(LayersIPCChannel*) {
455 MOZ_ASSERT(mBuffer);
456 GfxMemoryImageReporter::WillFree(mBuffer);
457 delete[] mBuffer;
458 mBuffer = nullptr;
461 TextureData* MemoryTextureData::CreateSimilar(
462 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
463 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
464 return MemoryTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
465 aLayersBackend, aFlags, aAllocFlags,
466 aAllocator);
469 bool ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
470 MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
471 if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
472 return false;
475 aOutDescriptor =
476 SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(std::move(mShmem)));
478 return true;
481 ShmemTextureData* ShmemTextureData::Create(gfx::IntSize aSize,
482 gfx::SurfaceFormat aFormat,
483 gfx::BackendType aMoz2DBackend,
484 LayersBackend aLayersBackend,
485 TextureFlags aFlags,
486 TextureAllocationFlags aAllocFlags,
487 IShmemAllocator* aAllocator) {
488 MOZ_ASSERT(aAllocator);
489 // Should have used CreateForYCbCr.
490 MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
492 if (!aAllocator) {
493 return nullptr;
496 if (aSize.width <= 0 || aSize.height <= 0) {
497 gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x"
498 << aSize.height;
499 return nullptr;
502 uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
503 if (!bufSize) {
504 return nullptr;
507 mozilla::ipc::Shmem shm;
508 if (!aAllocator->AllocUnsafeShmem(bufSize, &shm)) {
509 return nullptr;
512 uint8_t* buf = shm.get<uint8_t>();
513 if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, true)) {
514 return nullptr;
517 BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
519 return new ShmemTextureData(descriptor, aMoz2DBackend, shm);
522 TextureData* ShmemTextureData::CreateSimilar(
523 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
524 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
525 return ShmemTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
526 aLayersBackend, aFlags, aAllocFlags,
527 aAllocator);
530 void ShmemTextureData::Deallocate(LayersIPCChannel* aAllocator) {
531 aAllocator->DeallocShmem(mShmem);
534 } // namespace layers
535 } // namespace mozilla