TextureHost.cpp (30087B)
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 "TextureHost.h" 8 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 <limits> 39 #include "../opengl/CompositorOGL.h" 40 41 #include "gfxUtils.h" 42 #include "IPDLActor.h" 43 44 #ifdef XP_MACOSX 45 # include "../opengl/MacIOSurfaceTextureHostOGL.h" 46 #endif 47 48 #ifdef XP_WIN 49 # include "../d3d11/CompositorD3D11.h" 50 # include "mozilla/layers/TextureD3D11.h" 51 # ifdef MOZ_WMF_MEDIA_ENGINE 52 # include "mozilla/layers/DcompSurfaceImage.h" 53 # endif 54 #endif 55 56 #if 0 57 # define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) 58 #else 59 # define RECYCLE_LOG(...) \ 60 do { \ 61 } while (0) 62 #endif 63 64 namespace mozilla { 65 namespace layers { 66 67 /** 68 * TextureParent is the host-side IPDL glue between TextureClient and 69 * TextureHost. It is an IPDL actor just like LayerParent, CompositableParent, 70 * etc. 71 */ 72 class TextureParent : public ParentActor<PTextureParent> { 73 public: 74 TextureParent(HostIPCAllocator* aAllocator, 75 const dom::ContentParentId& aContentId, uint64_t aSerial, 76 const wr::MaybeExternalImageId& aExternalImageId); 77 78 virtual ~TextureParent(); 79 80 bool Init(const SurfaceDescriptor& aSharedData, 81 ReadLockDescriptor&& aReadLock, const LayersBackend& aLayersBackend, 82 const TextureFlags& aFlags); 83 84 void NotifyNotUsed(uint64_t aTransactionId); 85 86 mozilla::ipc::IPCResult RecvRecycleTexture( 87 const TextureFlags& aTextureFlags) final; 88 89 TextureHost* GetTextureHost() { return mTextureHost; } 90 91 void Destroy() override; 92 93 const dom::ContentParentId& GetContentId() const { return mContentId; } 94 95 uint64_t GetSerial() const { return mSerial; } 96 97 HostIPCAllocator* mSurfaceAllocator; 98 RefPtr<TextureHost> mTextureHost; 99 dom::ContentParentId mContentId; 100 // mSerial is unique in TextureClient's process. 101 const uint64_t mSerial; 102 wr::MaybeExternalImageId mExternalImageId; 103 }; 104 105 static bool WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator, 106 LayersBackend aBackend, 107 TextureFlags aFlags) { 108 if (!aDeallocator) { 109 return false; 110 } 111 if ((aFlags & TextureFlags::SNAPSHOT) || 112 (!aDeallocator->UsesImageBridge() && 113 !aDeallocator->AsCompositorBridgeParentBase())) { 114 return false; 115 } 116 return true; 117 } 118 119 //////////////////////////////////////////////////////////////////////////////// 120 PTextureParent* TextureHost::CreateIPDLActor( 121 HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData, 122 ReadLockDescriptor&& aReadLock, LayersBackend aLayersBackend, 123 TextureFlags aFlags, const dom::ContentParentId& aContentId, 124 uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId) { 125 TextureParent* actor = 126 new TextureParent(aAllocator, aContentId, aSerial, aExternalImageId); 127 if (!actor->Init(aSharedData, std::move(aReadLock), aLayersBackend, aFlags)) { 128 actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor); 129 delete actor; 130 return nullptr; 131 } 132 return actor; 133 } 134 135 // static 136 bool TextureHost::DestroyIPDLActor(PTextureParent* actor) { 137 delete actor; 138 return true; 139 } 140 141 // static 142 bool TextureHost::SendDeleteIPDLActor(PTextureParent* actor) { 143 return PTextureParent::Send__delete__(actor); 144 } 145 146 // static 147 TextureHost* TextureHost::AsTextureHost(PTextureParent* actor) { 148 if (!actor) { 149 return nullptr; 150 } 151 return static_cast<TextureParent*>(actor)->mTextureHost; 152 } 153 154 // static 155 uint64_t TextureHost::GetTextureSerial(PTextureParent* actor) { 156 if (!actor) { 157 return UINT64_MAX; 158 } 159 return static_cast<TextureParent*>(actor)->mSerial; 160 } 161 162 // static 163 dom::ContentParentId TextureHost::GetTextureContentId(PTextureParent* actor) { 164 if (!actor) { 165 return dom::ContentParentId(); 166 } 167 return static_cast<TextureParent*>(actor)->mContentId; 168 } 169 170 PTextureParent* TextureHost::GetIPDLActor() { return mActor; } 171 172 void TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) { 173 MOZ_ASSERT(mFwdTransactionId <= aTransactionId); 174 mFwdTransactionId = aTransactionId; 175 } 176 177 already_AddRefed<TextureHost> CreateDummyBufferTextureHost( 178 mozilla::layers::LayersBackend aBackend, 179 mozilla::layers::TextureFlags aFlags) { 180 // Ensure that the host will delete the memory. 181 aFlags &= ~TextureFlags::DEALLOCATE_CLIENT; 182 aFlags |= TextureFlags::DUMMY_TEXTURE; 183 UniquePtr<TextureData> textureData(BufferTextureData::Create( 184 gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA, 185 aBackend, aFlags, TextureAllocationFlags::ALLOC_DEFAULT, nullptr)); 186 SurfaceDescriptor surfDesc; 187 textureData->Serialize(surfDesc); 188 const SurfaceDescriptorBuffer& bufferDesc = 189 surfDesc.get_SurfaceDescriptorBuffer(); 190 const MemoryOrShmem& data = bufferDesc.data(); 191 RefPtr<TextureHost> host = 192 new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()), 193 bufferDesc.desc(), aFlags); 194 return host.forget(); 195 } 196 197 already_AddRefed<TextureHost> TextureHost::Create( 198 const SurfaceDescriptor& aDesc, ReadLockDescriptor&& aReadLock, 199 HostIPCAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags, 200 wr::MaybeExternalImageId& aExternalImageId) { 201 RefPtr<TextureHost> result; 202 203 switch (aDesc.type()) { 204 case SurfaceDescriptor::TSurfaceDescriptorBuffer: 205 case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: 206 result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, 207 aBackend, aFlags); 208 break; 209 210 case SurfaceDescriptor::TEGLImageDescriptor: 211 case SurfaceDescriptor::TSurfaceTextureDescriptor: 212 case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer: 213 case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: 214 case SurfaceDescriptor::TSurfaceDescriptorDMABuf: 215 result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags); 216 break; 217 218 case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: 219 result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags); 220 break; 221 222 #ifdef XP_WIN 223 case SurfaceDescriptor::TSurfaceDescriptorD3D10: 224 case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: 225 result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags); 226 break; 227 # ifdef MOZ_WMF_MEDIA_ENGINE 228 case SurfaceDescriptor::TSurfaceDescriptorDcompSurface: 229 result = 230 CreateTextureHostDcompSurface(aDesc, aDeallocator, aBackend, aFlags); 231 break; 232 # endif 233 #endif 234 default: 235 MOZ_CRASH("GFX: Unsupported Surface type host"); 236 } 237 238 if (!result) { 239 gfxCriticalNote << "TextureHost creation failure type=" << aDesc.type(); 240 } 241 242 if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) { 243 MOZ_ASSERT(aExternalImageId.isSome()); 244 result = new WebRenderTextureHost(aFlags, result, aExternalImageId.ref()); 245 } 246 247 if (result) { 248 result->DeserializeReadLock(std::move(aReadLock), aDeallocator); 249 } 250 251 return result.forget(); 252 } 253 254 already_AddRefed<TextureHost> CreateBackendIndependentTextureHost( 255 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, 256 LayersBackend aBackend, TextureFlags aFlags) { 257 RefPtr<TextureHost> result; 258 switch (aDesc.type()) { 259 case SurfaceDescriptor::TSurfaceDescriptorBuffer: { 260 const SurfaceDescriptorBuffer& bufferDesc = 261 aDesc.get_SurfaceDescriptorBuffer(); 262 const MemoryOrShmem& data = bufferDesc.data(); 263 switch (data.type()) { 264 case MemoryOrShmem::TShmem: { 265 const ipc::Shmem& shmem = data.get_Shmem(); 266 const BufferDescriptor& desc = bufferDesc.desc(); 267 if (!shmem.IsReadable()) { 268 // We failed to map the shmem so we can't verify its size. This 269 // should not be a fatal error, so just create the texture with 270 // nothing backing it. 271 result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags); 272 break; 273 } 274 275 size_t bufSize = shmem.Size<char>(); 276 size_t reqSize = SIZE_MAX; 277 switch (desc.type()) { 278 case BufferDescriptor::TYCbCrDescriptor: { 279 const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor(); 280 reqSize = ImageDataSerializer::ComputeYCbCrBufferSize( 281 ycbcr.ySize(), ycbcr.yStride(), ycbcr.cbCrSize(), 282 ycbcr.cbCrStride(), ycbcr.yOffset(), ycbcr.cbOffset(), 283 ycbcr.crOffset()); 284 break; 285 } 286 case BufferDescriptor::TRGBDescriptor: { 287 const RGBDescriptor& rgb = desc.get_RGBDescriptor(); 288 reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(), 289 rgb.format()); 290 break; 291 } 292 default: 293 gfxCriticalError() 294 << "Bad buffer host descriptor " << (int)desc.type(); 295 MOZ_CRASH("GFX: Bad descriptor"); 296 } 297 298 if (reqSize == 0 || bufSize < reqSize) { 299 NS_ERROR( 300 "A client process gave a shmem too small to fit for its " 301 "descriptor!"); 302 return nullptr; 303 } 304 305 result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags); 306 break; 307 } 308 case MemoryOrShmem::Tuintptr_t: { 309 if (aDeallocator && !aDeallocator->IsSameProcess()) { 310 NS_ERROR( 311 "A client process is trying to peek at our address space using " 312 "a MemoryTexture!"); 313 return nullptr; 314 } 315 316 result = new MemoryTextureHost( 317 reinterpret_cast<uint8_t*>(data.get_uintptr_t()), 318 bufferDesc.desc(), aFlags); 319 break; 320 } 321 default: 322 gfxCriticalError() 323 << "Failed texture host for backend " << (int)data.type(); 324 MOZ_CRASH("GFX: No texture host for backend"); 325 } 326 break; 327 } 328 case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: { 329 MOZ_ASSERT(aDesc.get_SurfaceDescriptorGPUVideo().type() == 330 SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder); 331 result = GPUVideoTextureHost::CreateFromDescriptor( 332 aDeallocator->GetContentId(), aFlags, 333 aDesc.get_SurfaceDescriptorGPUVideo()); 334 break; 335 } 336 default: { 337 NS_WARNING("No backend independent TextureHost for this descriptor type"); 338 } 339 } 340 return result.forget(); 341 } 342 343 TextureHost::TextureHost(TextureHostType aType, TextureFlags aFlags) 344 : AtomicRefCountedWithFinalize("TextureHost"), 345 mTextureHostType(aType), 346 mActor(nullptr), 347 mFlags(aFlags), 348 mCompositableCount(0), 349 mFwdTransactionId(0), 350 mReadLocked(false) {} 351 352 TextureHost::~TextureHost() { 353 MOZ_ASSERT(mExternalImageId.isNothing()); 354 355 if (mReadLocked) { 356 // If we still have a ReadLock, unlock it. At this point we don't care about 357 // the texture client being written into on the other side since it should 358 // be destroyed by now. But we will hit assertions if we don't ReadUnlock 359 // before destroying the lock itself. 360 ReadUnlock(); 361 } 362 if (mDestroyedCallback) { 363 mDestroyedCallback(); 364 } 365 } 366 367 void TextureHost::Finalize() { 368 MaybeDestroyRenderTexture(); 369 370 if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) { 371 DeallocateSharedData(); 372 DeallocateDeviceData(); 373 } 374 } 375 376 void TextureHost::UnbindTextureSource() { 377 if (mReadLocked) { 378 ReadUnlock(); 379 } 380 } 381 382 void TextureHost::RecycleTexture(TextureFlags aFlags) { 383 MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE); 384 MOZ_ASSERT(aFlags & TextureFlags::RECYCLE); 385 mFlags = aFlags; 386 } 387 388 void TextureHost::PrepareForUse() {} 389 390 void TextureHost::NotifyNotUsed() { 391 if (!mActor) { 392 if ((mFlags & TextureFlags::REMOTE_TEXTURE) && AsSurfaceTextureHost()) { 393 MOZ_ASSERT(mExternalImageId.isSome()); 394 wr::RenderThread::Get()->NotifyNotUsed(*mExternalImageId); 395 } 396 return; 397 } 398 399 // Do not need to call NotifyNotUsed() if TextureHost does not have 400 // TextureFlags::RECYCLE flag nor TextureFlags::WAIT_HOST_USAGE_END flag. 401 if (!(GetFlags() & TextureFlags::RECYCLE) && 402 !(GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) { 403 return; 404 } 405 406 static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId); 407 } 408 409 void TextureHost::CallNotifyNotUsed() { 410 if (!mActor) { 411 return; 412 } 413 static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId); 414 } 415 416 void TextureHost::MaybeDestroyRenderTexture() { 417 if (mExternalImageId.isNothing()) { 418 // RenderTextureHost was not created 419 return; 420 } 421 // When TextureHost created RenderTextureHost, delete it here. 422 TextureHost::DestroyRenderTexture(mExternalImageId.ref()); 423 mExternalImageId = Nothing(); 424 } 425 426 void TextureHost::DestroyRenderTexture( 427 const wr::ExternalImageId& aExternalImageId) { 428 wr::RenderThread::Get()->UnregisterExternalImage(aExternalImageId); 429 } 430 431 void TextureHost::EnsureRenderTexture( 432 const wr::MaybeExternalImageId& aExternalImageId) { 433 if (aExternalImageId.isNothing()) { 434 // TextureHost is wrapped by GPUVideoTextureHost. 435 if (mExternalImageId.isSome()) { 436 // RenderTextureHost was already created. 437 return; 438 } 439 mExternalImageId = 440 Some(AsyncImagePipelineManager::GetNextExternalImageId()); 441 } else { 442 // TextureHost is wrapped by WebRenderTextureHost. 443 if (aExternalImageId == mExternalImageId) { 444 // The texture has already been created. 445 return; 446 } 447 MOZ_ASSERT(mExternalImageId.isNothing()); 448 mExternalImageId = aExternalImageId; 449 } 450 CreateRenderTexture(mExternalImageId.ref()); 451 } 452 453 TextureSource::TextureSource() : mCompositableCount(0) {} 454 455 TextureSource::~TextureSource() = default; 456 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc, 457 TextureFlags aFlags) 458 : TextureHost(TextureHostType::Buffer, aFlags), mLocked(false) { 459 mDescriptor = aDesc; 460 switch (mDescriptor.type()) { 461 case BufferDescriptor::TYCbCrDescriptor: { 462 const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor(); 463 mSize = ycbcr.display().Size(); 464 mFormat = gfx::SurfaceFormat::YUV420; 465 break; 466 } 467 case BufferDescriptor::TRGBDescriptor: { 468 const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor(); 469 mSize = rgb.size(); 470 mFormat = rgb.format(); 471 break; 472 } 473 default: 474 gfxCriticalError() << "Bad buffer host descriptor " 475 << (int)mDescriptor.type(); 476 MOZ_CRASH("GFX: Bad descriptor"); 477 } 478 479 #ifdef XP_MACOSX 480 const int kMinSize = 1024; 481 const int kMaxSize = 4096; 482 mUseExternalTextures = 483 kMaxSize >= mSize.width && mSize.width >= kMinSize && 484 kMaxSize >= mSize.height && mSize.height >= kMinSize && 485 StaticPrefs::gfx_webrender_enable_client_storage_AtStartup(); 486 #else 487 mUseExternalTextures = false; 488 #endif 489 } 490 491 BufferTextureHost::~BufferTextureHost() = default; 492 493 void BufferTextureHost::DeallocateDeviceData() {} 494 495 void BufferTextureHost::CreateRenderTexture( 496 const wr::ExternalImageId& aExternalImageId) { 497 MOZ_ASSERT(mExternalImageId.isSome()); 498 499 RefPtr<wr::RenderTextureHost> texture; 500 501 if (UseExternalTextures()) { 502 texture = 503 new wr::RenderExternalTextureHost(GetBuffer(), GetBufferDescriptor()); 504 } else { 505 texture = 506 new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor()); 507 } 508 509 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 510 texture.forget()); 511 } 512 513 uint32_t BufferTextureHost::NumSubTextures() { 514 if (GetFormat() == gfx::SurfaceFormat::YUV420) { 515 return 3; 516 } 517 518 return 1; 519 } 520 521 void BufferTextureHost::PushResourceUpdates( 522 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 523 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 524 auto method = aOp == TextureHost::ADD_IMAGE 525 ? &wr::TransactionBuilder::AddExternalImage 526 : &wr::TransactionBuilder::UpdateExternalImage; 527 528 // Use native textures if our backend requires it, or if our backend doesn't 529 // forbid it and we want to use them. 530 NativeTexturePolicy policy = 531 BackendNativeTexturePolicy(aResources.GetBackendType(), GetSize()); 532 bool useNativeTexture = 533 (policy == REQUIRE) || (policy != FORBID && UseExternalTextures()); 534 auto imageType = useNativeTexture ? wr::ExternalImageType::TextureHandle( 535 wr::ImageBufferKind::TextureRect) 536 : wr::ExternalImageType::Buffer(); 537 538 if (GetFormat() != gfx::SurfaceFormat::YUV420) { 539 MOZ_ASSERT(aImageKeys.length() == 1); 540 541 wr::ImageDescriptor descriptor( 542 GetSize(), 543 ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width), 544 GetFormat()); 545 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0, 546 /* aNormalizedUvs */ false); 547 } else { 548 MOZ_ASSERT(aImageKeys.length() == 3); 549 550 const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 551 gfx::IntSize ySize = desc.display().Size(); 552 gfx::IntSize cbcrSize = ImageDataSerializer::GetCroppedCbCrSize(desc); 553 wr::ImageDescriptor yDescriptor( 554 ySize, desc.yStride(), SurfaceFormatForColorDepth(desc.colorDepth())); 555 wr::ImageDescriptor cbcrDescriptor( 556 cbcrSize, desc.cbCrStride(), 557 SurfaceFormatForColorDepth(desc.colorDepth())); 558 (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0, 559 /* aNormalizedUvs */ false); 560 (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1, 561 /* aNormalizedUvs */ false); 562 (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2, 563 /* aNormalizedUvs */ false); 564 } 565 } 566 567 void BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder, 568 const wr::LayoutRect& aBounds, 569 const wr::LayoutRect& aClip, 570 wr::ImageRendering aFilter, 571 const Range<wr::ImageKey>& aImageKeys, 572 PushDisplayItemFlagSet aFlags) { 573 // SWGL should always try to bypass shaders and composite directly. 574 bool preferCompositorSurface = 575 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); 576 bool useExternalSurface = 577 aFlags.contains(PushDisplayItemFlag::SUPPORTS_EXTERNAL_BUFFER_TEXTURES); 578 if (GetFormat() != gfx::SurfaceFormat::YUV420) { 579 MOZ_ASSERT(aImageKeys.length() == 1); 580 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 581 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 582 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 583 preferCompositorSurface, useExternalSurface); 584 } else { 585 MOZ_ASSERT(aImageKeys.length() == 3); 586 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 587 aBuilder.PushYCbCrPlanarImage( 588 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2], 589 wr::ToWrColorDepth(desc.colorDepth()), 590 wr::ToWrYuvColorSpace(desc.yUVColorSpace()), 591 wr::ToWrColorRange(desc.colorRange()), aFilter, preferCompositorSurface, 592 useExternalSurface); 593 } 594 } 595 596 void TextureHost::DeserializeReadLock(ReadLockDescriptor&& aDesc, 597 ISurfaceAllocator* aAllocator) { 598 if (mReadLock) { 599 return; 600 } 601 602 mReadLock = TextureReadLock::Deserialize(std::move(aDesc), aAllocator); 603 } 604 605 void TextureHost::SetReadLocked() { 606 if (!mReadLock) { 607 return; 608 } 609 // If mReadLocked is true it means we haven't read unlocked yet and the 610 // content side should not have been able to write into this texture and read 611 // lock again! 612 MOZ_ASSERT(!mReadLocked); 613 mReadLocked = true; 614 } 615 616 void TextureHost::ReadUnlock() { 617 if (mReadLock && mReadLocked) { 618 mReadLock->ReadUnlock(); 619 mReadLocked = false; 620 } 621 } 622 623 bool TextureHost::NeedsYFlip() const { 624 return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT); 625 } 626 627 void BufferTextureHost::UnbindTextureSource() { 628 // This texture is not used by any layer anymore. 629 // If the texture has an intermediate buffer we don't care either because 630 // texture uploads are also performed synchronously for BufferTextureHost. 631 ReadUnlock(); 632 } 633 634 gfx::SurfaceFormat BufferTextureHost::GetFormat() const { return mFormat; } 635 636 gfx::YUVColorSpace BufferTextureHost::GetYUVColorSpace() const { 637 if (mFormat == gfx::SurfaceFormat::YUV420) { 638 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 639 return desc.yUVColorSpace(); 640 } 641 return gfx::YUVColorSpace::Identity; 642 } 643 644 gfx::ColorDepth BufferTextureHost::GetColorDepth() const { 645 if (mFormat == gfx::SurfaceFormat::YUV420) { 646 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 647 return desc.colorDepth(); 648 } 649 return gfx::ColorDepth::COLOR_8; 650 } 651 652 gfx::ColorRange BufferTextureHost::GetColorRange() const { 653 if (mFormat == gfx::SurfaceFormat::YUV420) { 654 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 655 return desc.colorRange(); 656 } 657 return TextureHost::GetColorRange(); 658 } 659 660 gfx::ChromaSubsampling BufferTextureHost::GetChromaSubsampling() const { 661 if (mFormat == gfx::SurfaceFormat::YUV420) { 662 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 663 return desc.chromaSubsampling(); 664 } 665 return gfx::ChromaSubsampling::FULL; 666 } 667 668 uint8_t* BufferTextureHost::GetYChannel() { 669 if (mFormat == gfx::SurfaceFormat::YUV420) { 670 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 671 return ImageDataSerializer::GetYChannel(GetBuffer(), desc); 672 } 673 return nullptr; 674 } 675 676 uint8_t* BufferTextureHost::GetCbChannel() { 677 if (mFormat == gfx::SurfaceFormat::YUV420) { 678 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 679 return ImageDataSerializer::GetCbChannel(GetBuffer(), desc); 680 } 681 return nullptr; 682 } 683 684 uint8_t* BufferTextureHost::GetCrChannel() { 685 if (mFormat == gfx::SurfaceFormat::YUV420) { 686 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 687 return ImageDataSerializer::GetCrChannel(GetBuffer(), desc); 688 } 689 return nullptr; 690 } 691 692 int32_t BufferTextureHost::GetYStride() const { 693 if (mFormat == gfx::SurfaceFormat::YUV420) { 694 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 695 return desc.yStride(); 696 } 697 return 0; 698 } 699 700 int32_t BufferTextureHost::GetCbCrStride() const { 701 if (mFormat == gfx::SurfaceFormat::YUV420) { 702 const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); 703 return desc.cbCrStride(); 704 } 705 return 0; 706 } 707 708 already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface( 709 gfx::DataSourceSurface* aSurface) { 710 RefPtr<gfx::DataSourceSurface> result; 711 if (mFormat == gfx::SurfaceFormat::UNKNOWN) { 712 NS_WARNING("BufferTextureHost: unsupported format!"); 713 return nullptr; 714 } 715 if (mFormat == gfx::SurfaceFormat::YUV420) { 716 result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor( 717 GetBuffer(), mDescriptor.get_YCbCrDescriptor(), aSurface); 718 if (NS_WARN_IF(!result)) { 719 return nullptr; 720 } 721 } else { 722 result = gfx::Factory::CreateWrappingDataSourceSurface( 723 GetBuffer(), 724 ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()), 725 mSize, mFormat); 726 } 727 return result.forget(); 728 } 729 730 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem, 731 const BufferDescriptor& aDesc, 732 ISurfaceAllocator* aDeallocator, 733 TextureFlags aFlags) 734 : BufferTextureHost(aDesc, aFlags), mDeallocator(aDeallocator) { 735 if (aShmem.IsReadable()) { 736 mShmem = MakeUnique<ipc::Shmem>(aShmem); 737 } else { 738 // This can happen if we failed to map the shmem on this process, perhaps 739 // because it was big and we didn't have enough contiguous address space 740 // available, even though we did on the child process. 741 // As a result this texture will be in an invalid state and Lock will 742 // always fail. 743 744 gfxCriticalNote << "Failed to create a valid ShmemTextureHost"; 745 } 746 747 MOZ_COUNT_CTOR(ShmemTextureHost); 748 } 749 750 ShmemTextureHost::~ShmemTextureHost() { 751 MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT), 752 "Leaking our buffer"); 753 DeallocateDeviceData(); 754 MOZ_COUNT_DTOR(ShmemTextureHost); 755 } 756 757 void ShmemTextureHost::DeallocateSharedData() { 758 if (mShmem) { 759 MOZ_ASSERT(mDeallocator, 760 "Shared memory would leak without a ISurfaceAllocator"); 761 mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem); 762 mShmem = nullptr; 763 } 764 } 765 766 void ShmemTextureHost::ForgetSharedData() { 767 if (mShmem) { 768 mShmem = nullptr; 769 } 770 } 771 772 void ShmemTextureHost::OnShutdown() { mShmem = nullptr; } 773 774 uint8_t* ShmemTextureHost::GetBuffer() const { 775 return mShmem ? mShmem->get<uint8_t>() : nullptr; 776 } 777 778 size_t ShmemTextureHost::GetBufferSize() const { 779 return mShmem ? mShmem->Size<uint8_t>() : 0; 780 } 781 782 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer, 783 const BufferDescriptor& aDesc, 784 TextureFlags aFlags) 785 : BufferTextureHost(aDesc, aFlags), mBuffer(aBuffer) { 786 MOZ_COUNT_CTOR(MemoryTextureHost); 787 } 788 789 MemoryTextureHost::~MemoryTextureHost() { 790 MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT), 791 "Leaking our buffer"); 792 DeallocateDeviceData(); 793 MOZ_COUNT_DTOR(MemoryTextureHost); 794 } 795 796 void MemoryTextureHost::DeallocateSharedData() { 797 if (mBuffer) { 798 GfxMemoryImageReporter::WillFree(mBuffer); 799 } 800 delete[] mBuffer; 801 mBuffer = nullptr; 802 } 803 804 void MemoryTextureHost::ForgetSharedData() { mBuffer = nullptr; } 805 806 uint8_t* MemoryTextureHost::GetBuffer() const { return mBuffer; } 807 808 size_t MemoryTextureHost::GetBufferSize() const { 809 // MemoryTextureHost just trusts that the buffer size is large enough to read 810 // anything we need to. That's because MemoryTextureHost has to trust the 811 // buffer pointer anyway, so the security model here is just that 812 // MemoryTexture's are restricted to same-process clients. 813 return std::numeric_limits<size_t>::max(); 814 } 815 816 TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator, 817 const dom::ContentParentId& aContentId, 818 uint64_t aSerial, 819 const wr::MaybeExternalImageId& aExternalImageId) 820 : mSurfaceAllocator(aSurfaceAllocator), 821 mContentId(aContentId), 822 mSerial(aSerial), 823 mExternalImageId(aExternalImageId) { 824 MOZ_COUNT_CTOR(TextureParent); 825 } 826 827 TextureParent::~TextureParent() { MOZ_COUNT_DTOR(TextureParent); } 828 829 void TextureParent::NotifyNotUsed(uint64_t aTransactionId) { 830 if (!mTextureHost) { 831 return; 832 } 833 mSurfaceAllocator->NotifyNotUsed(this, aTransactionId); 834 } 835 836 bool TextureParent::Init(const SurfaceDescriptor& aSharedData, 837 ReadLockDescriptor&& aReadLock, 838 const LayersBackend& aBackend, 839 const TextureFlags& aFlags) { 840 mTextureHost = 841 TextureHost::Create(aSharedData, std::move(aReadLock), mSurfaceAllocator, 842 aBackend, aFlags, mExternalImageId); 843 if (mTextureHost) { 844 mTextureHost->mActor = this; 845 } 846 847 return !!mTextureHost; 848 } 849 850 void TextureParent::Destroy() { 851 if (!mTextureHost) { 852 return; 853 } 854 855 if (mTextureHost->mReadLocked) { 856 // ReadUnlock here to make sure the ReadLock's shmem does not outlive the 857 // protocol that created it. 858 mTextureHost->ReadUnlock(); 859 } 860 861 if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) { 862 mTextureHost->ForgetSharedData(); 863 } 864 865 mTextureHost->mActor = nullptr; 866 mTextureHost = nullptr; 867 } 868 869 void TextureHost::ReceivedDestroy(PTextureParent* aActor) { 870 static_cast<TextureParent*>(aActor)->RecvDestroy(); 871 } 872 873 mozilla::ipc::IPCResult TextureParent::RecvRecycleTexture( 874 const TextureFlags& aTextureFlags) { 875 if (!mTextureHost) { 876 return IPC_OK(); 877 } 878 mTextureHost->RecycleTexture(aTextureFlags); 879 return IPC_OK(); 880 } 881 882 //////////////////////////////////////////////////////////////////////////////// 883 884 } // namespace layers 885 } // namespace mozilla