ImageBridgeChild.cpp (30174B)
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 "ImageBridgeChild.h" 8 9 #include <vector> // for vector 10 11 #include "ImageBridgeParent.h" // for ImageBridgeParent 12 #include "ImageContainer.h" // for ImageContainer 13 #include "SynchronousTask.h" 14 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc 15 #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock 16 #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc 17 #include "mozilla/StaticMutex.h" 18 #include "mozilla/StaticPtr.h" // for StaticRefPtr 19 #include "mozilla/dom/ContentChild.h" 20 #include "mozilla/gfx/Point.h" // for IntSize 21 #include "mozilla/gfx/gfxVars.h" 22 #include "mozilla/ipc/Endpoint.h" 23 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc 24 #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc 25 #include "mozilla/layers/CompositorThread.h" 26 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator 27 #include "mozilla/layers/ImageClient.h" // for ImageClient 28 #include "mozilla/layers/LayersMessages.h" // for CompositableOperation 29 #include "mozilla/layers/TextureClient.h" // for TextureClient 30 #include "mozilla/layers/TextureClient.h" 31 #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager 32 #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild 33 #include "mozilla/mozalloc.h" // for operator new, etc 34 #include "transport/runnable_utils.h" 35 #include "nsContentUtils.h" 36 #include "nsGlobalWindowInner.h" 37 #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc 38 #include "nsTArray.h" // for AutoTArray, nsTArray, etc 39 #include "nsTArrayForwardDeclare.h" // for AutoTArray 40 #include "nsThreadUtils.h" // for NS_IsMainThread 41 #include "WindowRenderer.h" 42 43 #if defined(XP_WIN) 44 # include "mozilla/gfx/DeviceManagerDx.h" 45 #endif 46 47 namespace mozilla { 48 namespace ipc { 49 class Shmem; 50 } // namespace ipc 51 52 namespace layers { 53 54 using namespace mozilla::ipc; 55 using namespace mozilla::gfx; 56 using namespace mozilla::media; 57 58 typedef std::vector<CompositableOperation> OpVector; 59 typedef nsTArray<OpDestroy> OpDestroyVector; 60 61 struct CompositableTransaction { 62 CompositableTransaction() : mFinished(true) {} 63 ~CompositableTransaction() { End(); } 64 bool Finished() const { return mFinished; } 65 void Begin() { 66 MOZ_ASSERT(mFinished); 67 mFinished = false; 68 } 69 void End() { 70 mFinished = true; 71 mOperations.clear(); 72 mDestroyedActors.Clear(); 73 } 74 bool IsEmpty() const { 75 return mOperations.empty() && mDestroyedActors.IsEmpty(); 76 } 77 void AddNoSwapEdit(const CompositableOperation& op) { 78 MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); 79 mOperations.push_back(op); 80 } 81 82 OpVector mOperations; 83 OpDestroyVector mDestroyedActors; 84 85 bool mFinished; 86 }; 87 88 struct AutoEndTransaction final { 89 explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {} 90 ~AutoEndTransaction() { mTxn->End(); } 91 CompositableTransaction* mTxn; 92 }; 93 94 void ImageBridgeChild::UseTextures( 95 CompositableClient* aCompositable, 96 const nsTArray<TimedTextureClient>& aTextures) { 97 MOZ_ASSERT(aCompositable); 98 MOZ_ASSERT(aCompositable->GetIPCHandle()); 99 MOZ_ASSERT(aCompositable->IsConnected()); 100 101 AutoTArray<TimedTexture, 4> textures; 102 103 for (auto& t : aTextures) { 104 MOZ_ASSERT(t.mTextureClient); 105 MOZ_ASSERT(t.mTextureClient->GetIPDLActor()); 106 107 if (!t.mTextureClient->IsSharedWithCompositor()) { 108 return; 109 } 110 111 bool readLocked = t.mTextureClient->OnForwardedToHost(); 112 113 textures.AppendElement(TimedTexture( 114 WrapNotNull(t.mTextureClient->GetIPDLActor()), t.mTimeStamp, 115 t.mPictureRect, t.mFrameID, t.mProducerID, readLocked)); 116 117 // Wait end of usage on host side if TextureFlags::RECYCLE is set 118 HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient); 119 } 120 mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(), 121 OpUseTexture(textures))); 122 } 123 124 void ImageBridgeChild::UseRemoteTexture( 125 CompositableClient* aCompositable, const RemoteTextureId aTextureId, 126 const RemoteTextureOwnerId aOwnerId, const gfx::IntSize aSize, 127 const TextureFlags aFlags, const RefPtr<FwdTransactionTracker>& aTracker) { 128 MOZ_ASSERT(aCompositable); 129 MOZ_ASSERT(aCompositable->GetIPCHandle()); 130 MOZ_ASSERT(aCompositable->IsConnected()); 131 132 mTxn->AddNoSwapEdit(CompositableOperation( 133 aCompositable->GetIPCHandle(), 134 OpUseRemoteTexture(aTextureId, aOwnerId, aSize, aFlags))); 135 TrackFwdTransaction(aTracker); 136 } 137 138 void ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary( 139 TextureClient* aClient) { 140 if (!aClient) { 141 return; 142 } 143 144 // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE or 145 // TextureFlags::WAIT_HOST_USAGE_END is set on ImageBridge. 146 bool waitNotifyNotUsed = 147 aClient->GetFlags() & TextureFlags::RECYCLE || 148 aClient->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END; 149 if (!waitNotifyNotUsed) { 150 return; 151 } 152 153 aClient->SetLastFwdTransactionId(GetFwdTransactionId()); 154 mTexturesWaitingNotifyNotUsed.emplace(aClient->GetSerial(), aClient); 155 } 156 157 void ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, 158 uint64_t aFwdTransactionId) { 159 auto it = mTexturesWaitingNotifyNotUsed.find(aTextureId); 160 if (it != mTexturesWaitingNotifyNotUsed.end()) { 161 if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) { 162 // Released on host side, but client already requested newer use texture. 163 return; 164 } 165 mTexturesWaitingNotifyNotUsed.erase(it); 166 } 167 } 168 169 void ImageBridgeChild::CancelWaitForNotifyNotUsed(uint64_t aTextureId) { 170 MOZ_ASSERT(InImageBridgeChildThread()); 171 mTexturesWaitingNotifyNotUsed.erase(aTextureId); 172 } 173 174 // Singleton 175 static StaticMutex sImageBridgeSingletonLock MOZ_UNANNOTATED; 176 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton; 177 static StaticRefPtr<nsIThread> sImageBridgeChildThread; 178 179 // dispatched function 180 void ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask) { 181 AutoCompleteTask complete(aTask); 182 183 MOZ_ASSERT(InImageBridgeChildThread(), 184 "Should be in ImageBridgeChild thread."); 185 186 MediaSystemResourceManager::Shutdown(); 187 188 // Force all managed protocols to shut themselves down cleanly 189 nsTArray<PTextureChild*> textures; 190 ManagedPTextureChild(textures); 191 for (int i = textures.Length() - 1; i >= 0; --i) { 192 RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]); 193 if (client) { 194 client->Destroy(); 195 } 196 } 197 198 if (mCanSend) { 199 SendWillClose(); 200 } 201 MarkShutDown(); 202 203 // From now on, no message can be sent through the image bridge from the 204 // client side except the final Stop message. 205 } 206 207 // dispatched function 208 void ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask) { 209 AutoCompleteTask complete(aTask); 210 211 MOZ_ASSERT(InImageBridgeChildThread(), 212 "Should be in ImageBridgeChild thread."); 213 214 mSectionAllocator = nullptr; 215 216 if (!mDestroyed) { 217 Close(); 218 } 219 } 220 221 void ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { 222 mCanSend = false; 223 mDestroyed = true; 224 { 225 MutexAutoLock lock(mContainerMapLock); 226 mImageContainerListeners.clear(); 227 } 228 } 229 230 void ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask, 231 RefPtr<ImageClient>* result, 232 CompositableType aType, 233 ImageContainer* aImageContainer) { 234 AutoCompleteTask complete(aTask); 235 *result = CreateImageClientNow(aType, aImageContainer); 236 } 237 238 ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace) 239 : mNamespace(aNamespace), 240 mCanSend(false), 241 mDestroyed(false), 242 mFwdTransactionCounter(this), 243 mContainerMapLock("ImageBridgeChild.mContainerMapLock") { 244 MOZ_ASSERT(mNamespace); 245 MOZ_ASSERT(NS_IsMainThread()); 246 247 mTxn = new CompositableTransaction(); 248 } 249 250 ImageBridgeChild::~ImageBridgeChild() { delete mTxn; } 251 252 void ImageBridgeChild::MarkShutDown() { 253 mTexturesWaitingNotifyNotUsed.clear(); 254 255 mCanSend = false; 256 } 257 258 void ImageBridgeChild::Connect(CompositableClient* aCompositable, 259 ImageContainer* aImageContainer) { 260 MOZ_ASSERT(aCompositable); 261 MOZ_ASSERT(InImageBridgeChildThread()); 262 MOZ_ASSERT(CanSend()); 263 264 CompositableHandle handle = CompositableHandle::GetNext(); 265 266 // ImageClient of ImageContainer provides aImageContainer. 267 // But offscreen canvas does not provide it. 268 if (aImageContainer) { 269 MutexAutoLock lock(mContainerMapLock); 270 MOZ_ASSERT(mImageContainerListeners.find(uint64_t(handle)) == 271 mImageContainerListeners.end()); 272 mImageContainerListeners.emplace( 273 uint64_t(handle), aImageContainer->GetImageContainerListener()); 274 } 275 276 aCompositable->InitIPDL(handle); 277 SendNewCompositable(handle, aCompositable->GetTextureInfo()); 278 } 279 280 void ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle) { 281 MutexAutoLock lock(mContainerMapLock); 282 mImageContainerListeners.erase(aHandle.Value()); 283 } 284 285 /* static */ 286 RefPtr<ImageBridgeChild> ImageBridgeChild::GetSingleton() { 287 StaticMutexAutoLock lock(sImageBridgeSingletonLock); 288 return sImageBridgeChildSingleton; 289 } 290 291 void ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer) { 292 if (!aContainer) { 293 return; 294 } 295 296 if (!InImageBridgeChildThread()) { 297 RefPtr<Runnable> runnable = 298 WrapRunnable(RefPtr<ImageBridgeChild>(this), 299 &ImageBridgeChild::UpdateImageClient, aContainer); 300 GetThread()->Dispatch(runnable.forget()); 301 return; 302 } 303 304 if (!CanSend()) { 305 return; 306 } 307 308 RefPtr<ImageClient> client = aContainer->GetImageClient(); 309 if (NS_WARN_IF(!client)) { 310 return; 311 } 312 313 // If the client has become disconnected before this event was dispatched, 314 // early return now. 315 if (!client->IsConnected()) { 316 return; 317 } 318 319 BeginTransaction(); 320 client->UpdateImage(aContainer); 321 EndTransaction(); 322 } 323 324 void ImageBridgeChild::UpdateCompositable( 325 const RefPtr<ImageContainer> aContainer, const RemoteTextureId aTextureId, 326 const RemoteTextureOwnerId aOwnerId, const gfx::IntSize aSize, 327 const TextureFlags aFlags, const RefPtr<FwdTransactionTracker> aTracker) { 328 if (!aContainer) { 329 return; 330 } 331 332 if (!InImageBridgeChildThread()) { 333 RefPtr<Runnable> runnable = WrapRunnable( 334 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::UpdateCompositable, 335 aContainer, aTextureId, aOwnerId, aSize, aFlags, aTracker); 336 GetThread()->Dispatch(runnable.forget()); 337 return; 338 } 339 340 if (!CanSend()) { 341 return; 342 } 343 344 RefPtr<ImageClient> client = aContainer->GetImageClient(); 345 if (NS_WARN_IF(!client)) { 346 return; 347 } 348 349 // If the client has become disconnected before this event was dispatched, 350 // early return now. 351 if (!client->IsConnected()) { 352 return; 353 } 354 355 BeginTransaction(); 356 UseRemoteTexture(client, aTextureId, aOwnerId, aSize, aFlags, aTracker); 357 EndTransaction(); 358 } 359 360 void ImageBridgeChild::ClearImagesInHostSync(SynchronousTask* aTask, 361 ImageClient* aClient, 362 ImageContainer* aContainer, 363 ClearImagesType aType) { 364 AutoCompleteTask complete(aTask); 365 366 if (!CanSend()) { 367 return; 368 } 369 370 MOZ_ASSERT(aClient); 371 BeginTransaction(); 372 if (aContainer) { 373 aContainer->ClearImagesFromImageBridge(); 374 } 375 aClient->ClearImagesInHost(aType); 376 EndTransaction(); 377 } 378 379 void ImageBridgeChild::ClearImagesInHost(ImageClient* aClient, 380 ImageContainer* aContainer, 381 ClearImagesType aType) { 382 MOZ_ASSERT(aClient); 383 MOZ_ASSERT(!InImageBridgeChildThread()); 384 385 if (InImageBridgeChildThread()) { 386 NS_ERROR( 387 "ImageBridgeChild::ClearImagesInHost() is called on ImageBridge " 388 "thread."); 389 return; 390 } 391 392 SynchronousTask task("ClearImagesInHost Lock"); 393 394 // RefPtrs on arguments are not needed since this dispatches synchronously. 395 RefPtr<Runnable> runnable = WrapRunnable( 396 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ClearImagesInHostSync, 397 &task, aClient, aContainer, aType); 398 GetThread()->Dispatch(runnable.forget()); 399 400 task.Wait(); 401 } 402 403 void ImageBridgeChild::SyncWithCompositor(const Maybe<uint64_t>& aWindowID) { 404 if (NS_WARN_IF(InImageBridgeChildThread())) { 405 MOZ_ASSERT_UNREACHABLE("Cannot call on ImageBridge thread!"); 406 return; 407 } 408 409 if (!aWindowID) { 410 return; 411 } 412 413 const auto fnSyncWithWindow = [&]() { 414 if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(*aWindowID)) { 415 if (auto* widget = window->GetNearestWidget()) { 416 if (auto* renderer = widget->GetWindowRenderer()) { 417 if (auto* kc = renderer->AsKnowsCompositor()) { 418 kc->SyncWithCompositor(); 419 } 420 } 421 } 422 } 423 }; 424 425 if (NS_IsMainThread()) { 426 fnSyncWithWindow(); 427 return; 428 } 429 430 SynchronousTask task("SyncWithCompositor Lock"); 431 RefPtr<Runnable> runnable = 432 NS_NewRunnableFunction("ImageBridgeChild::SyncWithCompositor", [&]() { 433 AutoCompleteTask complete(&task); 434 fnSyncWithWindow(); 435 }); 436 NS_DispatchToMainThread(runnable.forget()); 437 task.Wait(); 438 } 439 440 void ImageBridgeChild::BeginTransaction() { 441 MOZ_ASSERT(CanSend()); 442 MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); 443 UpdateFwdTransactionId(); 444 mTxn->Begin(); 445 } 446 447 void ImageBridgeChild::EndTransaction() { 448 MOZ_ASSERT(CanSend()); 449 MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); 450 451 AutoEndTransaction _(mTxn); 452 453 if (mTxn->IsEmpty()) { 454 return; 455 } 456 457 AutoTArray<CompositableOperation, 10> cset; 458 cset.SetCapacity(mTxn->mOperations.size()); 459 if (!mTxn->mOperations.empty()) { 460 cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size()); 461 } 462 463 if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) { 464 NS_WARNING("could not send async texture transaction"); 465 return; 466 } 467 } 468 469 bool ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, 470 uint32_t aNamespace) { 471 MOZ_ASSERT(NS_IsMainThread()); 472 473 gfxPlatform::GetPlatform(); 474 475 if (!sImageBridgeChildThread) { 476 nsCOMPtr<nsIThread> thread; 477 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread)); 478 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), 479 "Failed to start ImageBridgeChild thread!"); 480 sImageBridgeChildThread = thread.forget(); 481 } 482 483 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); 484 485 child->GetThread()->Dispatch(NS_NewRunnableFunction( 486 "layers::ImageBridgeChild::Bind", 487 [child, endpoint = std::move(aEndpoint)]() mutable { 488 child->Bind(std::move(endpoint)); 489 })); 490 491 // Assign this after so other threads can't post messages before we connect to 492 // IPDL. 493 { 494 StaticMutexAutoLock lock(sImageBridgeSingletonLock); 495 sImageBridgeChildSingleton = child; 496 } 497 498 return true; 499 } 500 501 bool ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, 502 uint32_t aNamespace) { 503 MOZ_ASSERT(NS_IsMainThread()); 504 505 // Note that at this point, ActorDestroy may not have been called yet, 506 // meaning mCanSend is still true. In this case we will try to send a 507 // synchronous WillClose message to the parent, and will certainly get a 508 // false result and a MsgDropped processing error. This is okay. 509 ShutdownSingleton(); 510 511 return InitForContent(std::move(aEndpoint), aNamespace); 512 } 513 514 void ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint) { 515 if (!aEndpoint.Bind(this)) { 516 return; 517 } 518 519 mSectionAllocator = MakeUnique<FixedSizeSmallShmemSectionAllocator>(this); 520 mCanSend = true; 521 } 522 523 void ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent) { 524 Open(aParent, aParent->GetThread(), mozilla::ipc::ChildSide); 525 526 mSectionAllocator = MakeUnique<FixedSizeSmallShmemSectionAllocator>(this); 527 mCanSend = true; 528 } 529 530 /* static */ 531 void ImageBridgeChild::ShutDown() { 532 MOZ_ASSERT(NS_IsMainThread()); 533 534 ShutdownSingleton(); 535 536 if (sImageBridgeChildThread) { 537 sImageBridgeChildThread->Shutdown(); 538 sImageBridgeChildThread = nullptr; 539 } 540 } 541 542 /* static */ 543 void ImageBridgeChild::ShutdownSingleton() { 544 MOZ_ASSERT(NS_IsMainThread()); 545 546 if (RefPtr<ImageBridgeChild> child = GetSingleton()) { 547 child->WillShutdown(); 548 549 StaticMutexAutoLock lock(sImageBridgeSingletonLock); 550 sImageBridgeChildSingleton = nullptr; 551 } 552 } 553 554 void ImageBridgeChild::WillShutdown() { 555 { 556 SynchronousTask task("ImageBridge ShutdownStep1 lock"); 557 558 RefPtr<Runnable> runnable = 559 WrapRunnable(RefPtr<ImageBridgeChild>(this), 560 &ImageBridgeChild::ShutdownStep1, &task); 561 GetThread()->Dispatch(runnable.forget()); 562 563 task.Wait(); 564 } 565 566 { 567 SynchronousTask task("ImageBridge ShutdownStep2 lock"); 568 569 RefPtr<Runnable> runnable = 570 WrapRunnable(RefPtr<ImageBridgeChild>(this), 571 &ImageBridgeChild::ShutdownStep2, &task); 572 GetThread()->Dispatch(runnable.forget()); 573 574 task.Wait(); 575 } 576 } 577 578 void ImageBridgeChild::InitSameProcess(uint32_t aNamespace) { 579 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); 580 581 MOZ_ASSERT(!sImageBridgeChildSingleton); 582 MOZ_ASSERT(!sImageBridgeChildThread); 583 584 nsCOMPtr<nsIThread> thread; 585 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread)); 586 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), 587 "Failed to start ImageBridgeChild thread!"); 588 sImageBridgeChildThread = thread.forget(); 589 590 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); 591 RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess(); 592 593 RefPtr<Runnable> runnable = 594 WrapRunnable(child, &ImageBridgeChild::BindSameProcess, parent); 595 child->GetThread()->Dispatch(runnable.forget()); 596 597 // Assign this after so other threads can't post messages before we connect to 598 // IPDL. 599 { 600 StaticMutexAutoLock lock(sImageBridgeSingletonLock); 601 sImageBridgeChildSingleton = child; 602 } 603 } 604 605 /* static */ 606 void ImageBridgeChild::InitWithGPUProcess( 607 Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) { 608 MOZ_ASSERT(NS_IsMainThread()); 609 MOZ_ASSERT(!sImageBridgeChildSingleton); 610 MOZ_ASSERT(!sImageBridgeChildThread); 611 612 nsCOMPtr<nsIThread> thread; 613 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread)); 614 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), 615 "Failed to start ImageBridgeChild thread!"); 616 sImageBridgeChildThread = thread.forget(); 617 618 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace); 619 620 child->GetThread()->Dispatch(NS_NewRunnableFunction( 621 "layers::ImageBridgeChild::Bind", 622 [child, endpoint = std::move(aEndpoint)]() mutable { 623 child->Bind(std::move(endpoint)); 624 })); 625 626 // Assign this after so other threads can't post messages before we connect to 627 // IPDL. 628 { 629 StaticMutexAutoLock lock(sImageBridgeSingletonLock); 630 sImageBridgeChildSingleton = child; 631 } 632 } 633 634 bool InImageBridgeChildThread() { 635 return sImageBridgeChildThread && 636 sImageBridgeChildThread->IsOnCurrentThread(); 637 } 638 639 FixedSizeSmallShmemSectionAllocator* ImageBridgeChild::GetTileLockAllocator() { 640 return mSectionAllocator.get(); 641 } 642 643 nsISerialEventTarget* ImageBridgeChild::GetThread() const { 644 return sImageBridgeChildThread; 645 } 646 647 /* static */ 648 void ImageBridgeChild::IdentifyCompositorTextureHost( 649 const TextureFactoryIdentifier& aIdentifier) { 650 if (RefPtr<ImageBridgeChild> child = GetSingleton()) { 651 child->UpdateTextureFactoryIdentifier(aIdentifier); 652 } 653 } 654 655 void ImageBridgeChild::UpdateTextureFactoryIdentifier( 656 const TextureFactoryIdentifier& aIdentifier) { 657 IdentifyTextureHost(aIdentifier); 658 } 659 660 RefPtr<ImageClient> ImageBridgeChild::CreateImageClient( 661 CompositableType aType, ImageContainer* aImageContainer) { 662 if (InImageBridgeChildThread()) { 663 return CreateImageClientNow(aType, aImageContainer); 664 } 665 666 SynchronousTask task("CreateImageClient Lock"); 667 668 RefPtr<ImageClient> result = nullptr; 669 670 RefPtr<Runnable> runnable = WrapRunnable( 671 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::CreateImageClientSync, 672 &task, &result, aType, aImageContainer); 673 GetThread()->Dispatch(runnable.forget()); 674 675 task.Wait(); 676 677 return result; 678 } 679 680 RefPtr<ImageClient> ImageBridgeChild::CreateImageClientNow( 681 CompositableType aType, ImageContainer* aImageContainer) { 682 MOZ_ASSERT(InImageBridgeChildThread()); 683 if (!CanSend()) { 684 return nullptr; 685 } 686 687 RefPtr<ImageClient> client = ImageClient::CreateImageClient( 688 aType, aImageContainer->mUsageType, this, TextureFlags::NO_FLAGS); 689 MOZ_ASSERT(client, "failed to create ImageClient"); 690 if (client) { 691 client->Connect(aImageContainer); 692 } 693 return client; 694 } 695 696 bool ImageBridgeChild::AllocUnsafeShmem(size_t aSize, ipc::Shmem* aShmem) { 697 if (!InImageBridgeChildThread()) { 698 return DispatchAllocShmemInternal(aSize, aShmem, 699 true); // true: unsafe 700 } 701 702 if (!CanSend()) { 703 return false; 704 } 705 return PImageBridgeChild::AllocUnsafeShmem(aSize, aShmem); 706 } 707 708 bool ImageBridgeChild::AllocShmem(size_t aSize, ipc::Shmem* aShmem) { 709 if (!InImageBridgeChildThread()) { 710 return DispatchAllocShmemInternal(aSize, aShmem, 711 false); // false: unsafe 712 } 713 714 if (!CanSend()) { 715 return false; 716 } 717 return PImageBridgeChild::AllocShmem(aSize, aShmem); 718 } 719 720 void ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize, 721 ipc::Shmem* aShmem, bool aUnsafe, 722 bool* aSuccess) { 723 AutoCompleteTask complete(aTask); 724 725 if (!CanSend()) { 726 return; 727 } 728 729 bool ok = false; 730 if (aUnsafe) { 731 ok = AllocUnsafeShmem(aSize, aShmem); 732 } else { 733 ok = AllocShmem(aSize, aShmem); 734 } 735 *aSuccess = ok; 736 } 737 738 bool ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, 739 ipc::Shmem* aShmem, 740 bool aUnsafe) { 741 SynchronousTask task("AllocatorProxy alloc"); 742 743 bool success = false; 744 RefPtr<Runnable> runnable = WrapRunnable( 745 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ProxyAllocShmemNow, 746 &task, aSize, aShmem, aUnsafe, &success); 747 GetThread()->Dispatch(runnable.forget()); 748 749 task.Wait(); 750 751 return success; 752 } 753 754 void ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask, 755 ipc::Shmem* aShmem, bool* aResult) { 756 AutoCompleteTask complete(aTask); 757 758 if (!CanSend()) { 759 return; 760 } 761 *aResult = DeallocShmem(*aShmem); 762 } 763 764 bool ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) { 765 if (InImageBridgeChildThread()) { 766 if (!CanSend()) { 767 return false; 768 } 769 return PImageBridgeChild::DeallocShmem(aShmem); 770 } 771 772 // If we can't post a task, then we definitely cannot send, so there's 773 // no reason to queue up this send. 774 if (!CanPostTask()) { 775 return false; 776 } 777 778 SynchronousTask task("AllocatorProxy Dealloc"); 779 bool result = false; 780 781 RefPtr<Runnable> runnable = WrapRunnable( 782 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ProxyDeallocShmemNow, 783 &task, &aShmem, &result); 784 GetThread()->Dispatch(runnable.forget()); 785 786 task.Wait(); 787 return result; 788 } 789 790 PTextureChild* ImageBridgeChild::AllocPTextureChild( 791 const SurfaceDescriptor&, ReadLockDescriptor&, const LayersBackend&, 792 const TextureFlags&, const uint64_t& aSerial, 793 const wr::MaybeExternalImageId& aExternalImageId) { 794 MOZ_ASSERT(CanSend()); 795 return TextureClient::CreateIPDLActor(); 796 } 797 798 bool ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) { 799 return TextureClient::DestroyIPDLActor(actor); 800 } 801 802 PMediaSystemResourceManagerChild* 803 ImageBridgeChild::AllocPMediaSystemResourceManagerChild() { 804 MOZ_ASSERT(CanSend()); 805 return new mozilla::media::MediaSystemResourceManagerChild(); 806 } 807 808 bool ImageBridgeChild::DeallocPMediaSystemResourceManagerChild( 809 PMediaSystemResourceManagerChild* aActor) { 810 MOZ_ASSERT(aActor); 811 delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor); 812 return true; 813 } 814 815 mozilla::ipc::IPCResult ImageBridgeChild::RecvParentAsyncMessages( 816 nsTArray<AsyncParentMessageData>&& aMessages) { 817 for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) { 818 const AsyncParentMessageData& message = aMessages[i]; 819 820 switch (message.type()) { 821 case AsyncParentMessageData::TOpNotifyNotUsed: { 822 const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed(); 823 NotifyNotUsed(op.TextureId(), op.fwdTransactionId()); 824 break; 825 } 826 default: 827 NS_ERROR("unknown AsyncParentMessageData type"); 828 return IPC_FAIL_NO_REASON(this); 829 } 830 } 831 return IPC_OK(); 832 } 833 834 RefPtr<ImageContainerListener> ImageBridgeChild::FindListener( 835 const CompositableHandle& aHandle) { 836 RefPtr<ImageContainerListener> listener; 837 MutexAutoLock lock(mContainerMapLock); 838 auto it = mImageContainerListeners.find(aHandle.Value()); 839 if (it != mImageContainerListeners.end()) { 840 listener = it->second; 841 } 842 return listener; 843 } 844 845 mozilla::ipc::IPCResult ImageBridgeChild::RecvDidComposite( 846 nsTArray<ImageCompositeNotification>&& aNotifications) { 847 for (auto& n : aNotifications) { 848 RefPtr<ImageContainerListener> listener = FindListener(n.compositable()); 849 if (listener) { 850 listener->NotifyComposite(n); 851 } 852 } 853 return IPC_OK(); 854 } 855 856 mozilla::ipc::IPCResult ImageBridgeChild::RecvReportFramesDropped( 857 const CompositableHandle& aHandle, const uint32_t& aFrames) { 858 RefPtr<ImageContainerListener> listener = FindListener(aHandle); 859 if (listener) { 860 listener->NotifyDropped(aFrames); 861 } 862 863 return IPC_OK(); 864 } 865 866 PTextureChild* ImageBridgeChild::CreateTexture( 867 const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock, 868 LayersBackend aLayersBackend, TextureFlags aFlags, 869 const dom::ContentParentId& aContentId, uint64_t aSerial, 870 wr::MaybeExternalImageId& aExternalImageId) { 871 MOZ_ASSERT(CanSend()); 872 return SendPTextureConstructor(aSharedData, std::move(aReadLock), 873 aLayersBackend, aFlags, aSerial, 874 aExternalImageId); 875 } 876 877 static bool IBCAddOpDestroy(CompositableTransaction* aTxn, 878 const OpDestroy& op) { 879 if (aTxn->Finished()) { 880 return false; 881 } 882 883 aTxn->mDestroyedActors.AppendElement(op); 884 return true; 885 } 886 887 bool ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture) { 888 return IBCAddOpDestroy(mTxn, OpDestroy(WrapNotNull(aTexture))); 889 } 890 891 bool ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle) { 892 return IBCAddOpDestroy(mTxn, OpDestroy(aHandle)); 893 } 894 895 void ImageBridgeChild::RemoveTextureFromCompositable( 896 CompositableClient* aCompositable, TextureClient* aTexture) { 897 MOZ_ASSERT(CanSend()); 898 MOZ_ASSERT(aTexture); 899 MOZ_ASSERT(aTexture->IsSharedWithCompositor()); 900 MOZ_ASSERT(aCompositable->IsConnected()); 901 if (!aTexture || !aTexture->IsSharedWithCompositor() || 902 !aCompositable->IsConnected()) { 903 return; 904 } 905 906 mTxn->AddNoSwapEdit(CompositableOperation( 907 aCompositable->GetIPCHandle(), 908 OpRemoveTexture(WrapNotNull(aTexture->GetIPDLActor())))); 909 } 910 911 void ImageBridgeChild::ClearImagesFromCompositable( 912 CompositableClient* aCompositable, ClearImagesType aType) { 913 MOZ_ASSERT(CanSend()); 914 MOZ_ASSERT(aCompositable->IsConnected()); 915 if (!aCompositable->IsConnected()) { 916 return; 917 } 918 919 mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(), 920 OpClearImages(aType))); 921 } 922 923 bool ImageBridgeChild::IsSameProcess() const { 924 return OtherPid() == base::GetCurrentProcId(); 925 } 926 927 bool ImageBridgeChild::CanPostTask() const { 928 // During shutdown, the cycle collector may free objects that are holding a 929 // reference to ImageBridgeChild. Since this happens on the main thread, 930 // ImageBridgeChild will attempt to post a task to the ImageBridge thread. 931 // However the thread manager has already been shut down, so the task cannot 932 // post. 933 // 934 // It's okay if this races. We only care about the shutdown case where 935 // everything's happening on the main thread. Even if it races outside of 936 // shutdown, it's still harmless to post the task, since the task must 937 // check CanSend(). 938 return !mDestroyed; 939 } 940 941 void ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle) { 942 if (!InImageBridgeChildThread()) { 943 // If we can't post a task, then we definitely cannot send, so there's 944 // no reason to queue up this send. 945 if (!CanPostTask()) { 946 return; 947 } 948 949 RefPtr<Runnable> runnable = 950 WrapRunnable(RefPtr<ImageBridgeChild>(this), 951 &ImageBridgeChild::ReleaseCompositable, aHandle); 952 GetThread()->Dispatch(runnable.forget()); 953 return; 954 } 955 956 if (!CanSend()) { 957 return; 958 } 959 960 if (!DestroyInTransaction(aHandle)) { 961 SendReleaseCompositable(aHandle); 962 } 963 964 { 965 MutexAutoLock lock(mContainerMapLock); 966 mImageContainerListeners.erase(aHandle.Value()); 967 } 968 } 969 970 bool ImageBridgeChild::CanSend() const { 971 MOZ_ASSERT(InImageBridgeChildThread()); 972 return mCanSend; 973 } 974 975 void ImageBridgeChild::HandleFatalError(const char* aMsg) { 976 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID()); 977 } 978 979 wr::MaybeExternalImageId ImageBridgeChild::GetNextExternalImageId() { 980 static uint32_t sNextID = 1; 981 ++sNextID; 982 MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX); 983 984 uint64_t imageId = mNamespace; 985 imageId = imageId << 32 | sNextID; 986 return Some(wr::ToExternalImageId(imageId)); 987 } 988 989 } // namespace layers 990 } // namespace mozilla