Bug 1934292 - Implement Enhanced Tracking Protection toggle. r=gl,android-reviewers
[gecko.git] / gfx / layers / composite / TextureHost.cpp
blobe4d8449cacae00b0b1d83d8ef1dd7cb8ab764541
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 "TextureHost.h"
9 #include "CompositableHost.h" // for CompositableHost
10 #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
11 #include "mozilla/gfx/CanvasManagerParent.h"
12 #include "mozilla/gfx/gfxVars.h"
13 #include "mozilla/ipc/Shmem.h" // for Shmem
14 #include "mozilla/layers/AsyncImagePipelineManager.h"
15 #include "mozilla/layers/BufferTexture.h"
16 #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
17 #include "mozilla/layers/CompositorBridgeParent.h"
18 #include "mozilla/layers/Compositor.h" // for Compositor
19 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
20 #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
21 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
22 #include "mozilla/layers/RemoteTextureMap.h"
23 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
24 #include "mozilla/layers/ImageDataSerializer.h"
25 #include "mozilla/layers/TextureClient.h"
26 #include "mozilla/layers/GPUVideoTextureHost.h"
27 #include "mozilla/layers/WebRenderTextureHost.h"
28 #include "mozilla/StaticPrefs_layers.h"
29 #include "mozilla/StaticPrefs_gfx.h"
30 #include "mozilla/webrender/RenderBufferTextureHost.h"
31 #include "mozilla/webrender/RenderExternalTextureHost.h"
32 #include "mozilla/webrender/RenderThread.h"
33 #include "mozilla/webrender/WebRenderAPI.h"
34 #include "nsAString.h"
35 #include "mozilla/RefPtr.h" // for nsRefPtr
36 #include "nsPrintfCString.h" // for nsPrintfCString
37 #include "mozilla/layers/PTextureParent.h"
38 #include "mozilla/Unused.h"
39 #include <limits>
40 #include "../opengl/CompositorOGL.h"
42 #include "gfxUtils.h"
43 #include "IPDLActor.h"
45 #ifdef XP_MACOSX
46 # include "../opengl/MacIOSurfaceTextureHostOGL.h"
47 #endif
49 #ifdef XP_WIN
50 # include "../d3d11/CompositorD3D11.h"
51 # include "mozilla/layers/TextureD3D11.h"
52 # ifdef MOZ_WMF_MEDIA_ENGINE
53 # include "mozilla/layers/DcompSurfaceImage.h"
54 # endif
55 #endif
57 #if 0
58 # define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
59 #else
60 # define RECYCLE_LOG(...) \
61 do { \
62 } while (0)
63 #endif
65 namespace mozilla {
66 namespace layers {
68 /**
69 * TextureParent is the host-side IPDL glue between TextureClient and
70 * TextureHost. It is an IPDL actor just like LayerParent, CompositableParent,
71 * etc.
73 class TextureParent : public ParentActor<PTextureParent> {
74 public:
75 TextureParent(HostIPCAllocator* aAllocator,
76 const dom::ContentParentId& aContentId, uint64_t aSerial,
77 const wr::MaybeExternalImageId& aExternalImageId);
79 virtual ~TextureParent();
81 bool Init(const SurfaceDescriptor& aSharedData,
82 ReadLockDescriptor&& aReadLock, const LayersBackend& aLayersBackend,
83 const TextureFlags& aFlags);
85 void NotifyNotUsed(uint64_t aTransactionId);
87 mozilla::ipc::IPCResult RecvRecycleTexture(
88 const TextureFlags& aTextureFlags) final;
90 TextureHost* GetTextureHost() { return mTextureHost; }
92 void Destroy() override;
94 const dom::ContentParentId& GetContentId() const { return mContentId; }
96 uint64_t GetSerial() const { return mSerial; }
98 HostIPCAllocator* mSurfaceAllocator;
99 RefPtr<TextureHost> mTextureHost;
100 dom::ContentParentId mContentId;
101 // mSerial is unique in TextureClient's process.
102 const uint64_t mSerial;
103 wr::MaybeExternalImageId mExternalImageId;
106 static bool WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
107 LayersBackend aBackend,
108 TextureFlags aFlags) {
109 if (!aDeallocator) {
110 return false;
112 if ((aFlags & TextureFlags::SNAPSHOT) ||
113 (!aDeallocator->UsesImageBridge() &&
114 !aDeallocator->AsCompositorBridgeParentBase())) {
115 return false;
117 return true;
120 ////////////////////////////////////////////////////////////////////////////////
121 PTextureParent* TextureHost::CreateIPDLActor(
122 HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData,
123 ReadLockDescriptor&& aReadLock, LayersBackend aLayersBackend,
124 TextureFlags aFlags, const dom::ContentParentId& aContentId,
125 uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId) {
126 TextureParent* actor =
127 new TextureParent(aAllocator, aContentId, aSerial, aExternalImageId);
128 if (!actor->Init(aSharedData, std::move(aReadLock), aLayersBackend, aFlags)) {
129 actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
130 delete actor;
131 return nullptr;
133 return actor;
136 // static
137 bool TextureHost::DestroyIPDLActor(PTextureParent* actor) {
138 delete actor;
139 return true;
142 // static
143 bool TextureHost::SendDeleteIPDLActor(PTextureParent* actor) {
144 return PTextureParent::Send__delete__(actor);
147 // static
148 TextureHost* TextureHost::AsTextureHost(PTextureParent* actor) {
149 if (!actor) {
150 return nullptr;
152 return static_cast<TextureParent*>(actor)->mTextureHost;
155 // static
156 uint64_t TextureHost::GetTextureSerial(PTextureParent* actor) {
157 if (!actor) {
158 return UINT64_MAX;
160 return static_cast<TextureParent*>(actor)->mSerial;
163 // static
164 dom::ContentParentId TextureHost::GetTextureContentId(PTextureParent* actor) {
165 if (!actor) {
166 return dom::ContentParentId();
168 return static_cast<TextureParent*>(actor)->mContentId;
171 PTextureParent* TextureHost::GetIPDLActor() { return mActor; }
173 void TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) {
174 MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
175 mFwdTransactionId = aTransactionId;
178 already_AddRefed<TextureHost> CreateDummyBufferTextureHost(
179 mozilla::layers::LayersBackend aBackend,
180 mozilla::layers::TextureFlags aFlags) {
181 // Ensure that the host will delete the memory.
182 aFlags &= ~TextureFlags::DEALLOCATE_CLIENT;
183 aFlags |= TextureFlags::DUMMY_TEXTURE;
184 UniquePtr<TextureData> textureData(BufferTextureData::Create(
185 gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA,
186 aBackend, aFlags, TextureAllocationFlags::ALLOC_DEFAULT, nullptr));
187 SurfaceDescriptor surfDesc;
188 textureData->Serialize(surfDesc);
189 const SurfaceDescriptorBuffer& bufferDesc =
190 surfDesc.get_SurfaceDescriptorBuffer();
191 const MemoryOrShmem& data = bufferDesc.data();
192 RefPtr<TextureHost> host =
193 new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
194 bufferDesc.desc(), aFlags);
195 return host.forget();
198 already_AddRefed<TextureHost> TextureHost::Create(
199 const SurfaceDescriptor& aDesc, ReadLockDescriptor&& aReadLock,
200 HostIPCAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags,
201 wr::MaybeExternalImageId& aExternalImageId) {
202 RefPtr<TextureHost> result;
204 switch (aDesc.type()) {
205 case SurfaceDescriptor::TSurfaceDescriptorBuffer:
206 case SurfaceDescriptor::TSurfaceDescriptorGPUVideo:
207 result = CreateBackendIndependentTextureHost(aDesc, aDeallocator,
208 aBackend, aFlags);
209 break;
211 case SurfaceDescriptor::TEGLImageDescriptor:
212 case SurfaceDescriptor::TSurfaceTextureDescriptor:
213 case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer:
214 case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
215 case SurfaceDescriptor::TSurfaceDescriptorDMABuf:
216 result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
217 break;
219 case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
220 result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
221 break;
223 #ifdef XP_WIN
224 case SurfaceDescriptor::TSurfaceDescriptorD3D10:
225 case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
226 result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
227 break;
228 # ifdef MOZ_WMF_MEDIA_ENGINE
229 case SurfaceDescriptor::TSurfaceDescriptorDcompSurface:
230 result =
231 CreateTextureHostDcompSurface(aDesc, aDeallocator, aBackend, aFlags);
232 break;
233 # endif
234 #endif
235 default:
236 MOZ_CRASH("GFX: Unsupported Surface type host");
239 if (!result) {
240 gfxCriticalNote << "TextureHost creation failure type=" << aDesc.type();
243 if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
244 MOZ_ASSERT(aExternalImageId.isSome());
245 result = new WebRenderTextureHost(aFlags, result, aExternalImageId.ref());
248 if (result) {
249 result->DeserializeReadLock(std::move(aReadLock), aDeallocator);
252 return result.forget();
255 already_AddRefed<TextureHost> CreateBackendIndependentTextureHost(
256 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
257 LayersBackend aBackend, TextureFlags aFlags) {
258 RefPtr<TextureHost> result;
259 switch (aDesc.type()) {
260 case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
261 const SurfaceDescriptorBuffer& bufferDesc =
262 aDesc.get_SurfaceDescriptorBuffer();
263 const MemoryOrShmem& data = bufferDesc.data();
264 switch (data.type()) {
265 case MemoryOrShmem::TShmem: {
266 const ipc::Shmem& shmem = data.get_Shmem();
267 const BufferDescriptor& desc = bufferDesc.desc();
268 if (!shmem.IsReadable()) {
269 // We failed to map the shmem so we can't verify its size. This
270 // should not be a fatal error, so just create the texture with
271 // nothing backing it.
272 result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
273 break;
276 size_t bufSize = shmem.Size<char>();
277 size_t reqSize = SIZE_MAX;
278 switch (desc.type()) {
279 case BufferDescriptor::TYCbCrDescriptor: {
280 const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor();
281 reqSize = ImageDataSerializer::ComputeYCbCrBufferSize(
282 ycbcr.ySize(), ycbcr.yStride(), ycbcr.cbCrSize(),
283 ycbcr.cbCrStride(), ycbcr.yOffset(), ycbcr.cbOffset(),
284 ycbcr.crOffset());
285 break;
287 case BufferDescriptor::TRGBDescriptor: {
288 const RGBDescriptor& rgb = desc.get_RGBDescriptor();
289 reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(),
290 rgb.format());
291 break;
293 default:
294 gfxCriticalError()
295 << "Bad buffer host descriptor " << (int)desc.type();
296 MOZ_CRASH("GFX: Bad descriptor");
299 if (reqSize == 0 || bufSize < reqSize) {
300 NS_ERROR(
301 "A client process gave a shmem too small to fit for its "
302 "descriptor!");
303 return nullptr;
306 result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
307 break;
309 case MemoryOrShmem::Tuintptr_t: {
310 if (aDeallocator && !aDeallocator->IsSameProcess()) {
311 NS_ERROR(
312 "A client process is trying to peek at our address space using "
313 "a MemoryTexture!");
314 return nullptr;
317 result = new MemoryTextureHost(
318 reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
319 bufferDesc.desc(), aFlags);
320 break;
322 default:
323 gfxCriticalError()
324 << "Failed texture host for backend " << (int)data.type();
325 MOZ_CRASH("GFX: No texture host for backend");
327 break;
329 case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
330 MOZ_ASSERT(aDesc.get_SurfaceDescriptorGPUVideo().type() ==
331 SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder);
332 result = GPUVideoTextureHost::CreateFromDescriptor(
333 aDeallocator->GetContentId(), aFlags,
334 aDesc.get_SurfaceDescriptorGPUVideo());
335 break;
337 default: {
338 NS_WARNING("No backend independent TextureHost for this descriptor type");
341 return result.forget();
344 TextureHost::TextureHost(TextureHostType aType, TextureFlags aFlags)
345 : AtomicRefCountedWithFinalize("TextureHost"),
346 mTextureHostType(aType),
347 mActor(nullptr),
348 mFlags(aFlags),
349 mCompositableCount(0),
350 mFwdTransactionId(0),
351 mReadLocked(false) {}
353 TextureHost::~TextureHost() {
354 MOZ_ASSERT(mExternalImageId.isNothing());
356 if (mReadLocked) {
357 // If we still have a ReadLock, unlock it. At this point we don't care about
358 // the texture client being written into on the other side since it should
359 // be destroyed by now. But we will hit assertions if we don't ReadUnlock
360 // before destroying the lock itself.
361 ReadUnlock();
363 if (mDestroyedCallback) {
364 mDestroyedCallback();
368 void TextureHost::Finalize() {
369 MaybeDestroyRenderTexture();
371 if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) {
372 DeallocateSharedData();
373 DeallocateDeviceData();
377 void TextureHost::UnbindTextureSource() {
378 if (mReadLocked) {
379 ReadUnlock();
383 void TextureHost::RecycleTexture(TextureFlags aFlags) {
384 MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
385 MOZ_ASSERT(aFlags & TextureFlags::RECYCLE);
386 mFlags = aFlags;
389 void TextureHost::PrepareForUse() {}
391 void TextureHost::NotifyNotUsed() {
392 if (!mActor) {
393 if ((mFlags & TextureFlags::REMOTE_TEXTURE) && AsSurfaceTextureHost()) {
394 MOZ_ASSERT(mExternalImageId.isSome());
395 wr::RenderThread::Get()->NotifyNotUsed(*mExternalImageId);
397 return;
400 // Do not need to call NotifyNotUsed() if TextureHost does not have
401 // TextureFlags::RECYCLE flag nor TextureFlags::WAIT_HOST_USAGE_END flag.
402 if (!(GetFlags() & TextureFlags::RECYCLE) &&
403 !(GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
404 return;
407 static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
410 void TextureHost::CallNotifyNotUsed() {
411 if (!mActor) {
412 return;
414 static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
417 void TextureHost::MaybeDestroyRenderTexture() {
418 if (mExternalImageId.isNothing()) {
419 // RenderTextureHost was not created
420 return;
422 // When TextureHost created RenderTextureHost, delete it here.
423 TextureHost::DestroyRenderTexture(mExternalImageId.ref());
424 mExternalImageId = Nothing();
427 void TextureHost::DestroyRenderTexture(
428 const wr::ExternalImageId& aExternalImageId) {
429 wr::RenderThread::Get()->UnregisterExternalImage(aExternalImageId);
432 void TextureHost::EnsureRenderTexture(
433 const wr::MaybeExternalImageId& aExternalImageId) {
434 if (aExternalImageId.isNothing()) {
435 // TextureHost is wrapped by GPUVideoTextureHost.
436 if (mExternalImageId.isSome()) {
437 // RenderTextureHost was already created.
438 return;
440 mExternalImageId =
441 Some(AsyncImagePipelineManager::GetNextExternalImageId());
442 } else {
443 // TextureHost is wrapped by WebRenderTextureHost.
444 if (aExternalImageId == mExternalImageId) {
445 // The texture has already been created.
446 return;
448 MOZ_ASSERT(mExternalImageId.isNothing());
449 mExternalImageId = aExternalImageId;
451 CreateRenderTexture(mExternalImageId.ref());
454 TextureSource::TextureSource() : mCompositableCount(0) {}
456 TextureSource::~TextureSource() = default;
457 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
458 TextureFlags aFlags)
459 : TextureHost(TextureHostType::Buffer, aFlags), mLocked(false) {
460 mDescriptor = aDesc;
461 switch (mDescriptor.type()) {
462 case BufferDescriptor::TYCbCrDescriptor: {
463 const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
464 mSize = ycbcr.display().Size();
465 mFormat = gfx::SurfaceFormat::YUV420;
466 break;
468 case BufferDescriptor::TRGBDescriptor: {
469 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
470 mSize = rgb.size();
471 mFormat = rgb.format();
472 break;
474 default:
475 gfxCriticalError() << "Bad buffer host descriptor "
476 << (int)mDescriptor.type();
477 MOZ_CRASH("GFX: Bad descriptor");
480 #ifdef XP_MACOSX
481 const int kMinSize = 1024;
482 const int kMaxSize = 4096;
483 mUseExternalTextures =
484 kMaxSize >= mSize.width && mSize.width >= kMinSize &&
485 kMaxSize >= mSize.height && mSize.height >= kMinSize &&
486 StaticPrefs::gfx_webrender_enable_client_storage_AtStartup();
487 #else
488 mUseExternalTextures = false;
489 #endif
492 BufferTextureHost::~BufferTextureHost() = default;
494 void BufferTextureHost::DeallocateDeviceData() {}
496 void BufferTextureHost::CreateRenderTexture(
497 const wr::ExternalImageId& aExternalImageId) {
498 MOZ_ASSERT(mExternalImageId.isSome());
500 RefPtr<wr::RenderTextureHost> texture;
502 if (UseExternalTextures()) {
503 texture =
504 new wr::RenderExternalTextureHost(GetBuffer(), GetBufferDescriptor());
505 } else {
506 texture =
507 new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor());
510 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
511 texture.forget());
514 uint32_t BufferTextureHost::NumSubTextures() {
515 if (GetFormat() == gfx::SurfaceFormat::YUV420) {
516 return 3;
519 return 1;
522 void BufferTextureHost::PushResourceUpdates(
523 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
524 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
525 auto method = aOp == TextureHost::ADD_IMAGE
526 ? &wr::TransactionBuilder::AddExternalImage
527 : &wr::TransactionBuilder::UpdateExternalImage;
529 // Use native textures if our backend requires it, or if our backend doesn't
530 // forbid it and we want to use them.
531 NativeTexturePolicy policy =
532 BackendNativeTexturePolicy(aResources.GetBackendType(), GetSize());
533 bool useNativeTexture =
534 (policy == REQUIRE) || (policy != FORBID && UseExternalTextures());
535 auto imageType = useNativeTexture ? wr::ExternalImageType::TextureHandle(
536 wr::ImageBufferKind::TextureRect)
537 : wr::ExternalImageType::Buffer();
539 if (GetFormat() != gfx::SurfaceFormat::YUV420) {
540 MOZ_ASSERT(aImageKeys.length() == 1);
542 wr::ImageDescriptor descriptor(
543 GetSize(),
544 ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
545 GetFormat());
546 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
547 /* aNormalizedUvs */ false);
548 } else {
549 MOZ_ASSERT(aImageKeys.length() == 3);
551 const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
552 gfx::IntSize ySize = desc.display().Size();
553 gfx::IntSize cbcrSize = ImageDataSerializer::GetCroppedCbCrSize(desc);
554 wr::ImageDescriptor yDescriptor(
555 ySize, desc.yStride(), SurfaceFormatForColorDepth(desc.colorDepth()));
556 wr::ImageDescriptor cbcrDescriptor(
557 cbcrSize, desc.cbCrStride(),
558 SurfaceFormatForColorDepth(desc.colorDepth()));
559 (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0,
560 /* aNormalizedUvs */ false);
561 (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1,
562 /* aNormalizedUvs */ false);
563 (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2,
564 /* aNormalizedUvs */ false);
568 void BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
569 const wr::LayoutRect& aBounds,
570 const wr::LayoutRect& aClip,
571 wr::ImageRendering aFilter,
572 const Range<wr::ImageKey>& aImageKeys,
573 PushDisplayItemFlagSet aFlags) {
574 // SWGL should always try to bypass shaders and composite directly.
575 bool preferCompositorSurface =
576 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
577 bool useExternalSurface =
578 aFlags.contains(PushDisplayItemFlag::SUPPORTS_EXTERNAL_BUFFER_TEXTURES);
579 if (GetFormat() != gfx::SurfaceFormat::YUV420) {
580 MOZ_ASSERT(aImageKeys.length() == 1);
581 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0],
582 !(mFlags & TextureFlags::NON_PREMULTIPLIED),
583 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
584 preferCompositorSurface, useExternalSurface);
585 } else {
586 MOZ_ASSERT(aImageKeys.length() == 3);
587 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
588 aBuilder.PushYCbCrPlanarImage(
589 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
590 wr::ToWrColorDepth(desc.colorDepth()),
591 wr::ToWrYuvColorSpace(desc.yUVColorSpace()),
592 wr::ToWrColorRange(desc.colorRange()), aFilter, preferCompositorSurface,
593 useExternalSurface);
597 void TextureHost::DeserializeReadLock(ReadLockDescriptor&& aDesc,
598 ISurfaceAllocator* aAllocator) {
599 if (mReadLock) {
600 return;
603 mReadLock = TextureReadLock::Deserialize(std::move(aDesc), aAllocator);
606 void TextureHost::SetReadLocked() {
607 if (!mReadLock) {
608 return;
610 // If mReadLocked is true it means we haven't read unlocked yet and the
611 // content side should not have been able to write into this texture and read
612 // lock again!
613 MOZ_ASSERT(!mReadLocked);
614 mReadLocked = true;
617 void TextureHost::ReadUnlock() {
618 if (mReadLock && mReadLocked) {
619 mReadLock->ReadUnlock();
620 mReadLocked = false;
624 bool TextureHost::NeedsYFlip() const {
625 return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT);
628 void BufferTextureHost::UnbindTextureSource() {
629 // This texture is not used by any layer anymore.
630 // If the texture has an intermediate buffer we don't care either because
631 // texture uploads are also performed synchronously for BufferTextureHost.
632 ReadUnlock();
635 gfx::SurfaceFormat BufferTextureHost::GetFormat() const { return mFormat; }
637 gfx::YUVColorSpace BufferTextureHost::GetYUVColorSpace() const {
638 if (mFormat == gfx::SurfaceFormat::YUV420) {
639 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
640 return desc.yUVColorSpace();
642 return gfx::YUVColorSpace::Identity;
645 gfx::ColorDepth BufferTextureHost::GetColorDepth() const {
646 if (mFormat == gfx::SurfaceFormat::YUV420) {
647 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
648 return desc.colorDepth();
650 return gfx::ColorDepth::COLOR_8;
653 gfx::ColorRange BufferTextureHost::GetColorRange() const {
654 if (mFormat == gfx::SurfaceFormat::YUV420) {
655 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
656 return desc.colorRange();
658 return TextureHost::GetColorRange();
661 gfx::ChromaSubsampling BufferTextureHost::GetChromaSubsampling() const {
662 if (mFormat == gfx::SurfaceFormat::YUV420) {
663 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
664 return desc.chromaSubsampling();
666 return gfx::ChromaSubsampling::FULL;
669 uint8_t* BufferTextureHost::GetYChannel() {
670 if (mFormat == gfx::SurfaceFormat::YUV420) {
671 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
672 return ImageDataSerializer::GetYChannel(GetBuffer(), desc);
674 return nullptr;
677 uint8_t* BufferTextureHost::GetCbChannel() {
678 if (mFormat == gfx::SurfaceFormat::YUV420) {
679 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
680 return ImageDataSerializer::GetCbChannel(GetBuffer(), desc);
682 return nullptr;
685 uint8_t* BufferTextureHost::GetCrChannel() {
686 if (mFormat == gfx::SurfaceFormat::YUV420) {
687 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
688 return ImageDataSerializer::GetCrChannel(GetBuffer(), desc);
690 return nullptr;
693 int32_t BufferTextureHost::GetYStride() const {
694 if (mFormat == gfx::SurfaceFormat::YUV420) {
695 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
696 return desc.yStride();
698 return 0;
701 int32_t BufferTextureHost::GetCbCrStride() const {
702 if (mFormat == gfx::SurfaceFormat::YUV420) {
703 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
704 return desc.cbCrStride();
706 return 0;
709 already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface(
710 gfx::DataSourceSurface* aSurface) {
711 RefPtr<gfx::DataSourceSurface> result;
712 if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
713 NS_WARNING("BufferTextureHost: unsupported format!");
714 return nullptr;
716 if (mFormat == gfx::SurfaceFormat::YUV420) {
717 result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
718 GetBuffer(), mDescriptor.get_YCbCrDescriptor(), aSurface);
719 if (NS_WARN_IF(!result)) {
720 return nullptr;
722 } else {
723 result = gfx::Factory::CreateWrappingDataSourceSurface(
724 GetBuffer(),
725 ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
726 mSize, mFormat);
728 return result.forget();
731 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
732 const BufferDescriptor& aDesc,
733 ISurfaceAllocator* aDeallocator,
734 TextureFlags aFlags)
735 : BufferTextureHost(aDesc, aFlags), mDeallocator(aDeallocator) {
736 if (aShmem.IsReadable()) {
737 mShmem = MakeUnique<ipc::Shmem>(aShmem);
738 } else {
739 // This can happen if we failed to map the shmem on this process, perhaps
740 // because it was big and we didn't have enough contiguous address space
741 // available, even though we did on the child process.
742 // As a result this texture will be in an invalid state and Lock will
743 // always fail.
745 gfxCriticalNote << "Failed to create a valid ShmemTextureHost";
748 MOZ_COUNT_CTOR(ShmemTextureHost);
751 ShmemTextureHost::~ShmemTextureHost() {
752 MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
753 "Leaking our buffer");
754 DeallocateDeviceData();
755 MOZ_COUNT_DTOR(ShmemTextureHost);
758 void ShmemTextureHost::DeallocateSharedData() {
759 if (mShmem) {
760 MOZ_ASSERT(mDeallocator,
761 "Shared memory would leak without a ISurfaceAllocator");
762 mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem);
763 mShmem = nullptr;
767 void ShmemTextureHost::ForgetSharedData() {
768 if (mShmem) {
769 mShmem = nullptr;
773 void ShmemTextureHost::OnShutdown() { mShmem = nullptr; }
775 uint8_t* ShmemTextureHost::GetBuffer() {
776 return mShmem ? mShmem->get<uint8_t>() : nullptr;
779 size_t ShmemTextureHost::GetBufferSize() {
780 return mShmem ? mShmem->Size<uint8_t>() : 0;
783 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
784 const BufferDescriptor& aDesc,
785 TextureFlags aFlags)
786 : BufferTextureHost(aDesc, aFlags), mBuffer(aBuffer) {
787 MOZ_COUNT_CTOR(MemoryTextureHost);
790 MemoryTextureHost::~MemoryTextureHost() {
791 MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
792 "Leaking our buffer");
793 DeallocateDeviceData();
794 MOZ_COUNT_DTOR(MemoryTextureHost);
797 void MemoryTextureHost::DeallocateSharedData() {
798 if (mBuffer) {
799 GfxMemoryImageReporter::WillFree(mBuffer);
801 delete[] mBuffer;
802 mBuffer = nullptr;
805 void MemoryTextureHost::ForgetSharedData() { mBuffer = nullptr; }
807 uint8_t* MemoryTextureHost::GetBuffer() { return mBuffer; }
809 size_t MemoryTextureHost::GetBufferSize() {
810 // MemoryTextureHost just trusts that the buffer size is large enough to read
811 // anything we need to. That's because MemoryTextureHost has to trust the
812 // buffer pointer anyway, so the security model here is just that
813 // MemoryTexture's are restricted to same-process clients.
814 return std::numeric_limits<size_t>::max();
817 TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator,
818 const dom::ContentParentId& aContentId,
819 uint64_t aSerial,
820 const wr::MaybeExternalImageId& aExternalImageId)
821 : mSurfaceAllocator(aSurfaceAllocator),
822 mContentId(aContentId),
823 mSerial(aSerial),
824 mExternalImageId(aExternalImageId) {
825 MOZ_COUNT_CTOR(TextureParent);
828 TextureParent::~TextureParent() { MOZ_COUNT_DTOR(TextureParent); }
830 void TextureParent::NotifyNotUsed(uint64_t aTransactionId) {
831 if (!mTextureHost) {
832 return;
834 mSurfaceAllocator->NotifyNotUsed(this, aTransactionId);
837 bool TextureParent::Init(const SurfaceDescriptor& aSharedData,
838 ReadLockDescriptor&& aReadLock,
839 const LayersBackend& aBackend,
840 const TextureFlags& aFlags) {
841 mTextureHost =
842 TextureHost::Create(aSharedData, std::move(aReadLock), mSurfaceAllocator,
843 aBackend, aFlags, mExternalImageId);
844 if (mTextureHost) {
845 mTextureHost->mActor = this;
848 return !!mTextureHost;
851 void TextureParent::Destroy() {
852 if (!mTextureHost) {
853 return;
856 if (mTextureHost->mReadLocked) {
857 // ReadUnlock here to make sure the ReadLock's shmem does not outlive the
858 // protocol that created it.
859 mTextureHost->ReadUnlock();
862 if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
863 mTextureHost->ForgetSharedData();
866 mTextureHost->mActor = nullptr;
867 mTextureHost = nullptr;
870 void TextureHost::ReceivedDestroy(PTextureParent* aActor) {
871 static_cast<TextureParent*>(aActor)->RecvDestroy();
874 mozilla::ipc::IPCResult TextureParent::RecvRecycleTexture(
875 const TextureFlags& aTextureFlags) {
876 if (!mTextureHost) {
877 return IPC_OK();
879 mTextureHost->RecycleTexture(aTextureFlags);
880 return IPC_OK();
883 ////////////////////////////////////////////////////////////////////////////////
885 } // namespace layers
886 } // namespace mozilla