Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "ImageBridgeChild.h"
7 : #include <vector> // for vector
8 : #include "ImageBridgeParent.h" // for ImageBridgeParent
9 : #include "ImageContainer.h" // for ImageContainer
10 : #include "Layers.h" // for Layer, etc
11 : #include "ShadowLayers.h" // for ShadowLayerForwarder
12 : #include "base/message_loop.h" // for MessageLoop
13 : #include "base/platform_thread.h" // for PlatformThread
14 : #include "base/process.h" // for ProcessId
15 : #include "base/task.h" // for NewRunnableFunction, etc
16 : #include "base/thread.h" // for Thread
17 : #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
18 : #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
19 : #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
20 : #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
21 : #include "mozilla/ipc/Transport.h" // for Transport
22 : #include "mozilla/gfx/Point.h" // for IntSize
23 : #include "mozilla/layers/AsyncCanvasRenderer.h"
24 : #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
25 : #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
26 : #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
27 : #include "mozilla/layers/CompositorThread.h"
28 : #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
29 : #include "mozilla/layers/ImageClient.h" // for ImageClient
30 : #include "mozilla/layers/LayersMessages.h" // for CompositableOperation
31 : #include "mozilla/layers/TextureClient.h" // for TextureClient
32 : #include "mozilla/dom/ContentChild.h"
33 : #include "mozilla/mozalloc.h" // for operator new, etc
34 : #include "mtransport/runnable_utils.h"
35 : #include "nsContentUtils.h"
36 : #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc
37 : #include "nsTArray.h" // for AutoTArray, nsTArray, etc
38 : #include "nsTArrayForwardDeclare.h" // for AutoTArray
39 : #include "nsThreadUtils.h" // for NS_IsMainThread
40 : #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
41 : #include "mozilla/StaticMutex.h"
42 : #include "mozilla/StaticPtr.h" // for StaticRefPtr
43 : #include "mozilla/layers/TextureClient.h"
44 : #include "SynchronousTask.h"
45 :
46 : namespace mozilla {
47 : namespace ipc {
48 : class Shmem;
49 : } // namespace ipc
50 :
51 : namespace layers {
52 :
53 : using base::Thread;
54 : using base::ProcessId;
55 : using namespace mozilla::ipc;
56 : using namespace mozilla::gfx;
57 : using namespace mozilla::media;
58 :
59 : typedef std::vector<CompositableOperation> OpVector;
60 : typedef nsTArray<OpDestroy> OpDestroyVector;
61 : typedef nsTArray<ReadLockInit> ReadLockVector;
62 :
63 : struct CompositableTransaction
64 : {
65 3 : CompositableTransaction()
66 3 : : mReadLockSequenceNumber(0)
67 3 : , mFinished(true)
68 3 : {}
69 0 : ~CompositableTransaction()
70 0 : {
71 0 : End();
72 0 : }
73 0 : bool Finished() const
74 : {
75 0 : return mFinished;
76 : }
77 0 : void Begin()
78 : {
79 0 : MOZ_ASSERT(mFinished);
80 0 : mFinished = false;
81 0 : mReadLockSequenceNumber = 0;
82 0 : mReadLocks.AppendElement();
83 0 : }
84 0 : void End()
85 : {
86 0 : mFinished = true;
87 0 : mOperations.clear();
88 0 : mDestroyedActors.Clear();
89 0 : mReadLocks.Clear();
90 0 : }
91 0 : bool IsEmpty() const
92 : {
93 0 : return mOperations.empty() && mDestroyedActors.IsEmpty();
94 : }
95 0 : void AddNoSwapEdit(const CompositableOperation& op)
96 : {
97 0 : MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
98 0 : mOperations.push_back(op);
99 0 : }
100 :
101 0 : ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock)
102 : {
103 0 : ReadLockHandle handle(++mReadLockSequenceNumber);
104 0 : if (mReadLocks.LastElement().Length() >= CompositableForwarder::GetMaxFileDescriptorsPerMessage()) {
105 0 : mReadLocks.AppendElement();
106 : }
107 0 : mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle));
108 0 : return handle;
109 : }
110 :
111 : OpVector mOperations;
112 : OpDestroyVector mDestroyedActors;
113 : nsTArray<ReadLockVector> mReadLocks;
114 : uint64_t mReadLockSequenceNumber;
115 :
116 : bool mFinished;
117 : };
118 :
119 : struct AutoEndTransaction {
120 0 : explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
121 0 : ~AutoEndTransaction() { mTxn->End(); }
122 : CompositableTransaction* mTxn;
123 : };
124 :
125 : void
126 0 : ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
127 : const nsTArray<TimedTextureClient>& aTextures)
128 : {
129 0 : MOZ_ASSERT(aCompositable);
130 0 : MOZ_ASSERT(aCompositable->GetIPCHandle());
131 0 : MOZ_ASSERT(aCompositable->IsConnected());
132 :
133 0 : AutoTArray<TimedTexture,4> textures;
134 :
135 0 : for (auto& t : aTextures) {
136 0 : MOZ_ASSERT(t.mTextureClient);
137 0 : MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
138 :
139 0 : if (!t.mTextureClient->IsSharedWithCompositor()) {
140 0 : return;
141 : }
142 :
143 0 : ReadLockDescriptor readLock;
144 0 : ReadLockHandle readLockHandle;
145 0 : if (t.mTextureClient->SerializeReadLock(readLock)) {
146 0 : readLockHandle = mTxn->AddReadLock(readLock);
147 : }
148 :
149 0 : textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
150 : readLockHandle,
151 : t.mTimeStamp, t.mPictureRect,
152 0 : t.mFrameID, t.mProducerID));
153 :
154 : // Wait end of usage on host side if TextureFlags::RECYCLE is set
155 0 : HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
156 : }
157 0 : mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
158 0 : OpUseTexture(textures)));
159 : }
160 :
161 : void
162 0 : ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
163 : TextureClient* aTextureOnBlack,
164 : TextureClient* aTextureOnWhite)
165 : {
166 0 : MOZ_CRASH("should not be called");
167 : }
168 :
169 : void
170 0 : ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
171 : {
172 : // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge.
173 0 : if (!aClient ||
174 0 : !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
175 0 : return;
176 : }
177 0 : aClient->SetLastFwdTransactionId(GetFwdTransactionId());
178 0 : mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
179 : }
180 :
181 : void
182 0 : ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
183 : {
184 0 : if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
185 0 : if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
186 : // Released on host side, but client already requested newer use texture.
187 0 : return;
188 : }
189 0 : entry.Remove();
190 : }
191 : }
192 :
193 : void
194 0 : ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
195 : {
196 0 : MOZ_ASSERT(InImageBridgeChildThread());
197 0 : mTexturesWaitingRecycled.Remove(aTextureId);
198 0 : }
199 :
200 : // Singleton
201 3 : static StaticMutex sImageBridgeSingletonLock;
202 3 : static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
203 : static Thread *sImageBridgeChildThread = nullptr;
204 :
205 : // dispatched function
206 : void
207 0 : ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask)
208 : {
209 0 : AutoCompleteTask complete(aTask);
210 :
211 0 : MOZ_ASSERT(InImageBridgeChildThread(),
212 : "Should be in ImageBridgeChild thread.");
213 :
214 0 : MediaSystemResourceManager::Shutdown();
215 :
216 : // Force all managed protocols to shut themselves down cleanly
217 0 : InfallibleTArray<PTextureChild*> textures;
218 0 : ManagedPTextureChild(textures);
219 0 : for (int i = textures.Length() - 1; i >= 0; --i) {
220 0 : RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
221 0 : if (client) {
222 0 : client->Destroy();
223 : }
224 : }
225 :
226 0 : if (mCanSend) {
227 0 : SendWillClose();
228 : }
229 0 : MarkShutDown();
230 :
231 : // From now on, no message can be sent through the image bridge from the
232 : // client side except the final Stop message.
233 0 : }
234 :
235 : // dispatched function
236 : void
237 0 : ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
238 : {
239 0 : AutoCompleteTask complete(aTask);
240 :
241 0 : MOZ_ASSERT(InImageBridgeChildThread(),
242 : "Should be in ImageBridgeChild thread.");
243 0 : Close();
244 0 : }
245 :
246 : void
247 0 : ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
248 : {
249 0 : mCanSend = false;
250 : {
251 0 : MutexAutoLock lock(mContainerMapLock);
252 0 : mImageContainers.Clear();
253 : }
254 0 : }
255 :
256 : void
257 0 : ImageBridgeChild::DeallocPImageBridgeChild()
258 : {
259 0 : this->Release();
260 0 : }
261 :
262 : void
263 0 : ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
264 : RefPtr<ImageClient>* result,
265 : CompositableType aType,
266 : ImageContainer* aImageContainer)
267 : {
268 0 : AutoCompleteTask complete(aTask);
269 0 : *result = CreateImageClientNow(aType, aImageContainer);
270 0 : }
271 :
272 : // dispatched function
273 : void
274 0 : ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask,
275 : CanvasClient::CanvasClientType aType,
276 : TextureFlags aFlags,
277 : RefPtr<CanvasClient>* const outResult)
278 : {
279 0 : AutoCompleteTask complete(aTask);
280 0 : *outResult = CreateCanvasClientNow(aType, aFlags);
281 0 : }
282 :
283 3 : ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
284 : : mNamespace(aNamespace)
285 : , mCanSend(false)
286 : , mDestroyed(false)
287 : , mFwdTransactionId(0)
288 3 : , mContainerMapLock("ImageBridgeChild.mContainerMapLock")
289 : {
290 3 : MOZ_ASSERT(mNamespace);
291 3 : MOZ_ASSERT(NS_IsMainThread());
292 :
293 3 : mTxn = new CompositableTransaction();
294 3 : }
295 :
296 0 : ImageBridgeChild::~ImageBridgeChild()
297 : {
298 0 : delete mTxn;
299 0 : }
300 :
301 : void
302 0 : ImageBridgeChild::MarkShutDown()
303 : {
304 0 : mTexturesWaitingRecycled.Clear();
305 :
306 0 : mCanSend = false;
307 0 : }
308 :
309 : void
310 0 : ImageBridgeChild::Connect(CompositableClient* aCompositable,
311 : ImageContainer* aImageContainer)
312 : {
313 0 : MOZ_ASSERT(aCompositable);
314 0 : MOZ_ASSERT(InImageBridgeChildThread());
315 0 : MOZ_ASSERT(CanSend());
316 :
317 : // Note: this is static, rather than per-IBC, so IDs are not re-used across
318 : // ImageBridgeChild instances. This is relevant for the GPU process, where
319 : // we don't want old IDs to potentially leak into a recreated ImageBridge.
320 : static uint64_t sNextID = 1;
321 0 : uint64_t id = sNextID++;
322 :
323 : {
324 0 : MutexAutoLock lock(mContainerMapLock);
325 0 : MOZ_ASSERT(!mImageContainers.Contains(id));
326 0 : mImageContainers.Put(id, aImageContainer);
327 : }
328 :
329 0 : CompositableHandle handle(id);
330 0 : aCompositable->InitIPDL(handle);
331 0 : SendNewCompositable(handle, aCompositable->GetTextureInfo());
332 0 : }
333 :
334 : void
335 0 : ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
336 : {
337 0 : MutexAutoLock lock(mContainerMapLock);
338 0 : mImageContainers.Remove(aHandle.Value());
339 0 : }
340 :
341 0 : Thread* ImageBridgeChild::GetThread() const
342 : {
343 0 : return sImageBridgeChildThread;
344 : }
345 :
346 : /* static */ RefPtr<ImageBridgeChild>
347 5 : ImageBridgeChild::GetSingleton()
348 : {
349 10 : StaticMutexAutoLock lock(sImageBridgeSingletonLock);
350 10 : return sImageBridgeChildSingleton;
351 : }
352 :
353 : void
354 0 : ImageBridgeChild::ReleaseTextureClientNow(TextureClient* aClient)
355 : {
356 0 : MOZ_ASSERT(InImageBridgeChildThread());
357 0 : RELEASE_MANUALLY(aClient);
358 0 : }
359 :
360 : /* static */ void
361 0 : ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
362 : {
363 0 : if (!aClient) {
364 0 : return;
365 : }
366 :
367 0 : RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
368 0 : if (!imageBridge) {
369 : // TextureClient::Release should normally happen in the ImageBridgeChild
370 : // thread because it usually generate some IPDL messages.
371 : // However, if we take this branch it means that the ImageBridgeChild
372 : // has already shut down, along with the TextureChild, which means no
373 : // message will be sent and it is safe to run this code from any thread.
374 0 : RELEASE_MANUALLY(aClient);
375 0 : return;
376 : }
377 :
378 0 : RefPtr<Runnable> runnable = WrapRunnable(
379 : imageBridge,
380 : &ImageBridgeChild::ReleaseTextureClientNow,
381 0 : aClient);
382 0 : imageBridge->GetMessageLoop()->PostTask(runnable.forget());
383 : }
384 :
385 : void
386 0 : ImageBridgeChild::UpdateImageClient(RefPtr<ImageClient> aClient, RefPtr<ImageContainer> aContainer)
387 : {
388 0 : if (!aClient || !aContainer) {
389 0 : return;
390 : }
391 :
392 0 : if (!InImageBridgeChildThread()) {
393 0 : RefPtr<Runnable> runnable = WrapRunnable(
394 0 : RefPtr<ImageBridgeChild>(this),
395 : &ImageBridgeChild::UpdateImageClient,
396 : aClient,
397 0 : aContainer);
398 0 : GetMessageLoop()->PostTask(runnable.forget());
399 0 : return;
400 : }
401 :
402 0 : if (!CanSend()) {
403 0 : return;
404 : }
405 :
406 : // If the client has become disconnected before this event was dispatched,
407 : // early return now.
408 0 : if (!aClient->IsConnected()) {
409 0 : return;
410 : }
411 :
412 0 : BeginTransaction();
413 0 : aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
414 0 : EndTransaction();
415 : }
416 :
417 : void
418 0 : ImageBridgeChild::UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper)
419 : {
420 0 : AutoCompleteTask complete(aTask);
421 :
422 0 : UpdateAsyncCanvasRendererNow(aWrapper);
423 0 : }
424 :
425 : void
426 0 : ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
427 : {
428 0 : aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
429 :
430 0 : if (InImageBridgeChildThread()) {
431 0 : UpdateAsyncCanvasRendererNow(aWrapper);
432 0 : return;
433 : }
434 :
435 0 : SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
436 :
437 0 : RefPtr<Runnable> runnable = WrapRunnable(
438 0 : RefPtr<ImageBridgeChild>(this),
439 : &ImageBridgeChild::UpdateAsyncCanvasRendererSync,
440 : &task,
441 0 : aWrapper);
442 0 : GetMessageLoop()->PostTask(runnable.forget());
443 :
444 0 : task.Wait();
445 : }
446 :
447 : void
448 0 : ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
449 : {
450 0 : MOZ_ASSERT(aWrapper);
451 :
452 0 : if (!CanSend()) {
453 0 : return;
454 : }
455 :
456 0 : BeginTransaction();
457 0 : aWrapper->GetCanvasClient()->Updated();
458 0 : EndTransaction();
459 : }
460 :
461 : void
462 0 : ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
463 : ImageClient* aClient,
464 : ImageContainer* aContainer)
465 : {
466 0 : AutoCompleteTask complete(aTask);
467 :
468 0 : if (!CanSend()) {
469 0 : return;
470 : }
471 :
472 0 : MOZ_ASSERT(aClient);
473 0 : BeginTransaction();
474 0 : if (aContainer) {
475 0 : aContainer->ClearImagesFromImageBridge();
476 : }
477 0 : aClient->FlushAllImages();
478 0 : EndTransaction();
479 : }
480 :
481 : void
482 0 : ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer)
483 : {
484 0 : MOZ_ASSERT(aClient);
485 0 : MOZ_ASSERT(!InImageBridgeChildThread());
486 :
487 0 : if (InImageBridgeChildThread()) {
488 0 : NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
489 0 : return;
490 : }
491 :
492 0 : SynchronousTask task("FlushAllImages Lock");
493 :
494 : // RefPtrs on arguments are not needed since this dispatches synchronously.
495 0 : RefPtr<Runnable> runnable = WrapRunnable(
496 0 : RefPtr<ImageBridgeChild>(this),
497 : &ImageBridgeChild::FlushAllImagesSync,
498 : &task,
499 : aClient,
500 0 : aContainer);
501 0 : GetMessageLoop()->PostTask(runnable.forget());
502 :
503 0 : task.Wait();
504 : }
505 :
506 : void
507 0 : ImageBridgeChild::BeginTransaction()
508 : {
509 0 : MOZ_ASSERT(CanSend());
510 0 : MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
511 0 : UpdateFwdTransactionId();
512 0 : mTxn->Begin();
513 0 : }
514 :
515 : void
516 0 : ImageBridgeChild::EndTransaction()
517 : {
518 0 : MOZ_ASSERT(CanSend());
519 0 : MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
520 :
521 0 : AutoEndTransaction _(mTxn);
522 :
523 0 : if (mTxn->IsEmpty()) {
524 0 : return;
525 : }
526 :
527 0 : AutoTArray<CompositableOperation, 10> cset;
528 0 : cset.SetCapacity(mTxn->mOperations.size());
529 0 : if (!mTxn->mOperations.empty()) {
530 0 : cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
531 : }
532 :
533 0 : if (!IsSameProcess()) {
534 0 : ShadowLayerForwarder::PlatformSyncBeforeUpdate();
535 : }
536 :
537 0 : for (ReadLockVector& locks : mTxn->mReadLocks) {
538 0 : if (locks.Length()) {
539 0 : if (!SendInitReadLocks(locks)) {
540 0 : NS_WARNING("[LayersForwarder] WARNING: sending read locks failed!");
541 0 : return;
542 : }
543 : }
544 : }
545 :
546 0 : if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
547 0 : NS_WARNING("could not send async texture transaction");
548 0 : return;
549 : }
550 : }
551 :
552 : void
553 3 : ImageBridgeChild::SendImageBridgeThreadId()
554 : {
555 3 : }
556 :
557 : bool
558 2 : ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
559 : {
560 2 : MOZ_ASSERT(NS_IsMainThread());
561 :
562 2 : gfxPlatform::GetPlatform();
563 :
564 2 : if (!sImageBridgeChildThread) {
565 2 : sImageBridgeChildThread = new Thread("ImageBridgeChild");
566 2 : if (!sImageBridgeChildThread->Start()) {
567 0 : return false;
568 : }
569 : }
570 :
571 4 : RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
572 :
573 4 : RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
574 : "layers::ImageBridgeChild::Bind",
575 : child,
576 : &ImageBridgeChild::Bind,
577 6 : Move(aEndpoint));
578 2 : child->GetMessageLoop()->PostTask(runnable.forget());
579 :
580 : // Assign this after so other threads can't post messages before we connect to IPDL.
581 : {
582 4 : StaticMutexAutoLock lock(sImageBridgeSingletonLock);
583 2 : sImageBridgeChildSingleton = child;
584 : }
585 :
586 2 : return true;
587 : }
588 :
589 : bool
590 0 : ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
591 : {
592 0 : MOZ_ASSERT(NS_IsMainThread());
593 :
594 : // Note that at this point, ActorDestroy may not have been called yet,
595 : // meaning mCanSend is still true. In this case we will try to send a
596 : // synchronous WillClose message to the parent, and will certainly get a
597 : // false result and a MsgDropped processing error. This is okay.
598 0 : ShutdownSingleton();
599 :
600 0 : return InitForContent(Move(aEndpoint), aNamespace);
601 : }
602 :
603 : void
604 2 : ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint)
605 : {
606 2 : if (!aEndpoint.Bind(this)) {
607 0 : return;
608 : }
609 :
610 : // This reference is dropped in DeallocPImageBridgeChild.
611 2 : this->AddRef();
612 :
613 2 : mCanSend = true;
614 2 : SendImageBridgeThreadId();
615 : }
616 :
617 : void
618 1 : ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent)
619 : {
620 1 : MessageLoop *parentMsgLoop = aParent->GetMessageLoop();
621 1 : ipc::MessageChannel *parentChannel = aParent->GetIPCChannel();
622 1 : Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
623 :
624 : // This reference is dropped in DeallocPImageBridgeChild.
625 1 : this->AddRef();
626 :
627 1 : mCanSend = true;
628 1 : SendImageBridgeThreadId();
629 1 : }
630 :
631 : /* static */ void
632 0 : ImageBridgeChild::ShutDown()
633 : {
634 0 : MOZ_ASSERT(NS_IsMainThread());
635 :
636 0 : ShutdownSingleton();
637 :
638 0 : delete sImageBridgeChildThread;
639 0 : sImageBridgeChildThread = nullptr;
640 0 : }
641 :
642 : /* static */ void
643 0 : ImageBridgeChild::ShutdownSingleton()
644 : {
645 0 : MOZ_ASSERT(NS_IsMainThread());
646 :
647 0 : if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
648 0 : child->WillShutdown();
649 :
650 0 : StaticMutexAutoLock lock(sImageBridgeSingletonLock);
651 0 : sImageBridgeChildSingleton = nullptr;
652 : }
653 0 : }
654 :
655 : void
656 0 : ImageBridgeChild::WillShutdown()
657 : {
658 : {
659 0 : SynchronousTask task("ImageBridge ShutdownStep1 lock");
660 :
661 0 : RefPtr<Runnable> runnable = WrapRunnable(
662 0 : RefPtr<ImageBridgeChild>(this),
663 : &ImageBridgeChild::ShutdownStep1,
664 0 : &task);
665 0 : GetMessageLoop()->PostTask(runnable.forget());
666 :
667 0 : task.Wait();
668 : }
669 :
670 : {
671 0 : SynchronousTask task("ImageBridge ShutdownStep2 lock");
672 :
673 0 : RefPtr<Runnable> runnable = WrapRunnable(
674 0 : RefPtr<ImageBridgeChild>(this),
675 : &ImageBridgeChild::ShutdownStep2,
676 0 : &task);
677 0 : GetMessageLoop()->PostTask(runnable.forget());
678 :
679 0 : task.Wait();
680 : }
681 :
682 0 : mDestroyed = true;
683 0 : }
684 :
685 : void
686 1 : ImageBridgeChild::InitSameProcess(uint32_t aNamespace)
687 : {
688 1 : NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
689 :
690 1 : MOZ_ASSERT(!sImageBridgeChildSingleton);
691 1 : MOZ_ASSERT(!sImageBridgeChildThread);
692 :
693 1 : sImageBridgeChildThread = new Thread("ImageBridgeChild");
694 1 : if (!sImageBridgeChildThread->IsRunning()) {
695 1 : sImageBridgeChildThread->Start();
696 : }
697 :
698 2 : RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
699 2 : RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
700 :
701 4 : RefPtr<Runnable> runnable = WrapRunnable(
702 : child,
703 : &ImageBridgeChild::BindSameProcess,
704 4 : parent);
705 1 : child->GetMessageLoop()->PostTask(runnable.forget());
706 :
707 : // Assign this after so other threads can't post messages before we connect to IPDL.
708 : {
709 2 : StaticMutexAutoLock lock(sImageBridgeSingletonLock);
710 1 : sImageBridgeChildSingleton = child;
711 : }
712 1 : }
713 :
714 : /* static */ void
715 0 : ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
716 : {
717 0 : MOZ_ASSERT(NS_IsMainThread());
718 0 : MOZ_ASSERT(!sImageBridgeChildSingleton);
719 0 : MOZ_ASSERT(!sImageBridgeChildThread);
720 :
721 0 : sImageBridgeChildThread = new Thread("ImageBridgeChild");
722 0 : if (!sImageBridgeChildThread->IsRunning()) {
723 0 : sImageBridgeChildThread->Start();
724 : }
725 :
726 0 : RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
727 :
728 0 : MessageLoop* loop = child->GetMessageLoop();
729 0 : loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
730 : "layers::ImageBridgeChild::Bind",
731 : child,
732 : &ImageBridgeChild::Bind,
733 0 : Move(aEndpoint)));
734 :
735 : // Assign this after so other threads can't post messages before we connect to IPDL.
736 : {
737 0 : StaticMutexAutoLock lock(sImageBridgeSingletonLock);
738 0 : sImageBridgeChildSingleton = child;
739 : }
740 0 : }
741 :
742 0 : bool InImageBridgeChildThread()
743 : {
744 0 : return sImageBridgeChildThread &&
745 0 : sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
746 : }
747 :
748 3 : MessageLoop * ImageBridgeChild::GetMessageLoop() const
749 : {
750 3 : return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
751 : }
752 :
753 : /* static */ void
754 2 : ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier)
755 : {
756 4 : if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
757 2 : child->IdentifyTextureHost(aIdentifier);
758 : }
759 2 : }
760 :
761 : RefPtr<ImageClient>
762 0 : ImageBridgeChild::CreateImageClient(CompositableType aType,
763 : ImageContainer* aImageContainer)
764 : {
765 0 : if (InImageBridgeChildThread()) {
766 0 : return CreateImageClientNow(aType, aImageContainer);
767 : }
768 :
769 0 : SynchronousTask task("CreateImageClient Lock");
770 :
771 0 : RefPtr<ImageClient> result = nullptr;
772 :
773 0 : RefPtr<Runnable> runnable = WrapRunnable(
774 0 : RefPtr<ImageBridgeChild>(this),
775 : &ImageBridgeChild::CreateImageClientSync,
776 : &task,
777 : &result,
778 : aType,
779 0 : aImageContainer);
780 0 : GetMessageLoop()->PostTask(runnable.forget());
781 :
782 0 : task.Wait();
783 :
784 0 : return result;
785 : }
786 :
787 : RefPtr<ImageClient>
788 0 : ImageBridgeChild::CreateImageClientNow(CompositableType aType,
789 : ImageContainer* aImageContainer)
790 : {
791 0 : MOZ_ASSERT(InImageBridgeChildThread());
792 0 : if (!CanSend()) {
793 0 : return nullptr;
794 : }
795 :
796 0 : RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
797 0 : MOZ_ASSERT(client, "failed to create ImageClient");
798 0 : if (client) {
799 0 : client->Connect(aImageContainer);
800 : }
801 0 : return client;
802 : }
803 :
804 : already_AddRefed<CanvasClient>
805 0 : ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
806 : TextureFlags aFlag)
807 : {
808 0 : if (InImageBridgeChildThread()) {
809 0 : return CreateCanvasClientNow(aType, aFlag);
810 : }
811 :
812 0 : SynchronousTask task("CreateCanvasClient Lock");
813 :
814 : // RefPtrs on arguments are not needed since this dispatches synchronously.
815 0 : RefPtr<CanvasClient> result = nullptr;
816 0 : RefPtr<Runnable> runnable = WrapRunnable(
817 0 : RefPtr<ImageBridgeChild>(this),
818 : &ImageBridgeChild::CreateCanvasClientSync,
819 : &task,
820 : aType,
821 : aFlag,
822 0 : &result);
823 0 : GetMessageLoop()->PostTask(runnable.forget());
824 :
825 0 : task.Wait();
826 :
827 0 : return result.forget();
828 : }
829 :
830 : already_AddRefed<CanvasClient>
831 0 : ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
832 : TextureFlags aFlag)
833 : {
834 : RefPtr<CanvasClient> client
835 0 : = CanvasClient::CreateCanvasClient(aType, this, aFlag);
836 0 : MOZ_ASSERT(client, "failed to create CanvasClient");
837 0 : if (client) {
838 0 : client->Connect();
839 : }
840 0 : return client.forget();
841 : }
842 :
843 : bool
844 0 : ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
845 : ipc::SharedMemory::SharedMemoryType aType,
846 : ipc::Shmem* aShmem)
847 : {
848 0 : if (!InImageBridgeChildThread()) {
849 0 : return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
850 : }
851 :
852 0 : if (!CanSend()) {
853 0 : return false;
854 : }
855 0 : return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
856 : }
857 :
858 : bool
859 0 : ImageBridgeChild::AllocShmem(size_t aSize,
860 : ipc::SharedMemory::SharedMemoryType aType,
861 : ipc::Shmem* aShmem)
862 : {
863 0 : if (!InImageBridgeChildThread()) {
864 0 : return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
865 : }
866 :
867 0 : if (!CanSend()) {
868 0 : return false;
869 : }
870 0 : return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
871 : }
872 :
873 : // NewRunnableFunction accepts a limited number of parameters so we need a
874 : // struct here
875 : struct AllocShmemParams {
876 : size_t mSize;
877 : ipc::SharedMemory::SharedMemoryType mType;
878 : ipc::Shmem* mShmem;
879 : bool mUnsafe;
880 : bool mSuccess;
881 : };
882 :
883 : void
884 0 : ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams)
885 : {
886 0 : AutoCompleteTask complete(aTask);
887 :
888 0 : if (!CanSend()) {
889 0 : return;
890 : }
891 :
892 0 : bool ok = false;
893 0 : if (aParams->mUnsafe) {
894 0 : ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem);
895 : } else {
896 0 : ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem);
897 : }
898 0 : aParams->mSuccess = ok;
899 : }
900 :
901 : bool
902 0 : ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize,
903 : SharedMemory::SharedMemoryType aType,
904 : ipc::Shmem* aShmem,
905 : bool aUnsafe)
906 : {
907 0 : SynchronousTask task("AllocatorProxy alloc");
908 :
909 : AllocShmemParams params = {
910 : aSize, aType, aShmem, aUnsafe, false
911 0 : };
912 :
913 0 : RefPtr<Runnable> runnable = WrapRunnable(
914 0 : RefPtr<ImageBridgeChild>(this),
915 : &ImageBridgeChild::ProxyAllocShmemNow,
916 : &task,
917 0 : ¶ms);
918 0 : GetMessageLoop()->PostTask(runnable.forget());
919 :
920 0 : task.Wait();
921 :
922 0 : return params.mSuccess;
923 : }
924 :
925 : void
926 0 : ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
927 : ipc::Shmem* aShmem,
928 : bool* aResult)
929 : {
930 0 : AutoCompleteTask complete(aTask);
931 :
932 0 : if (!CanSend()) {
933 0 : return;
934 : }
935 0 : *aResult = DeallocShmem(*aShmem);
936 : }
937 :
938 : bool
939 0 : ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
940 : {
941 0 : if (InImageBridgeChildThread()) {
942 0 : if (!CanSend()) {
943 0 : return false;
944 : }
945 0 : return PImageBridgeChild::DeallocShmem(aShmem);
946 : }
947 :
948 : // If we can't post a task, then we definitely cannot send, so there's
949 : // no reason to queue up this send.
950 0 : if (!CanPostTask()) {
951 0 : return false;
952 : }
953 :
954 0 : SynchronousTask task("AllocatorProxy Dealloc");
955 0 : bool result = false;
956 :
957 0 : RefPtr<Runnable> runnable = WrapRunnable(
958 0 : RefPtr<ImageBridgeChild>(this),
959 : &ImageBridgeChild::ProxyDeallocShmemNow,
960 : &task,
961 : &aShmem,
962 0 : &result);
963 0 : GetMessageLoop()->PostTask(runnable.forget());
964 :
965 0 : task.Wait();
966 0 : return result;
967 : }
968 :
969 : PTextureChild*
970 0 : ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
971 : const LayersBackend&,
972 : const TextureFlags&,
973 : const uint64_t& aSerial,
974 : const wr::MaybeExternalImageId& aExternalImageId)
975 : {
976 0 : MOZ_ASSERT(CanSend());
977 0 : return TextureClient::CreateIPDLActor();
978 : }
979 :
980 : bool
981 0 : ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
982 : {
983 0 : return TextureClient::DestroyIPDLActor(actor);
984 : }
985 :
986 : PMediaSystemResourceManagerChild*
987 0 : ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
988 : {
989 0 : MOZ_ASSERT(CanSend());
990 0 : return new mozilla::media::MediaSystemResourceManagerChild();
991 : }
992 :
993 : bool
994 0 : ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
995 : {
996 0 : MOZ_ASSERT(aActor);
997 0 : delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
998 0 : return true;
999 : }
1000 :
1001 : mozilla::ipc::IPCResult
1002 0 : ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
1003 : {
1004 0 : for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
1005 0 : const AsyncParentMessageData& message = aMessages[i];
1006 :
1007 0 : switch (message.type()) {
1008 : case AsyncParentMessageData::TOpNotifyNotUsed: {
1009 0 : const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
1010 0 : NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
1011 0 : break;
1012 : }
1013 : default:
1014 0 : NS_ERROR("unknown AsyncParentMessageData type");
1015 0 : return IPC_FAIL_NO_REASON(this);
1016 : }
1017 : }
1018 0 : return IPC_OK();
1019 : }
1020 :
1021 : mozilla::ipc::IPCResult
1022 0 : ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
1023 : {
1024 0 : for (auto& n : aNotifications) {
1025 0 : RefPtr<ImageContainerListener> listener;
1026 : {
1027 0 : MutexAutoLock lock(mContainerMapLock);
1028 : ImageContainer* imageContainer;
1029 0 : imageContainer = mImageContainers.Get(n.compositable().Value());
1030 0 : if (imageContainer) {
1031 0 : listener = imageContainer->GetImageContainerListener();
1032 : }
1033 : }
1034 0 : if (listener) {
1035 0 : listener->NotifyComposite(n);
1036 : }
1037 : }
1038 0 : return IPC_OK();
1039 : }
1040 :
1041 : PTextureChild*
1042 0 : ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
1043 : LayersBackend aLayersBackend,
1044 : TextureFlags aFlags,
1045 : uint64_t aSerial,
1046 : wr::MaybeExternalImageId& aExternalImageId,
1047 : nsIEventTarget* aTarget)
1048 : {
1049 0 : MOZ_ASSERT(CanSend());
1050 0 : return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
1051 : }
1052 :
1053 : static bool
1054 0 : IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op)
1055 : {
1056 0 : if (aTxn->Finished()) {
1057 0 : return false;
1058 : }
1059 :
1060 0 : aTxn->mDestroyedActors.AppendElement(op);
1061 0 : return true;
1062 : }
1063 :
1064 : bool
1065 0 : ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture)
1066 : {
1067 0 : return IBCAddOpDestroy(mTxn, OpDestroy(aTexture));
1068 : }
1069 :
1070 : bool
1071 0 : ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
1072 : {
1073 0 : return IBCAddOpDestroy(mTxn, OpDestroy(aHandle));
1074 : }
1075 :
1076 : void
1077 0 : ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
1078 : TextureClient* aTexture)
1079 : {
1080 0 : MOZ_ASSERT(CanSend());
1081 0 : MOZ_ASSERT(aTexture);
1082 0 : MOZ_ASSERT(aTexture->IsSharedWithCompositor());
1083 0 : MOZ_ASSERT(aCompositable->IsConnected());
1084 0 : if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
1085 0 : return;
1086 : }
1087 :
1088 0 : mTxn->AddNoSwapEdit(CompositableOperation(
1089 0 : aCompositable->GetIPCHandle(),
1090 0 : OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
1091 : }
1092 :
1093 0 : bool ImageBridgeChild::IsSameProcess() const
1094 : {
1095 0 : return OtherPid() == base::GetCurrentProcId();
1096 : }
1097 :
1098 : bool
1099 0 : ImageBridgeChild::CanPostTask() const
1100 : {
1101 : // During shutdown, the cycle collector may free objects that are holding a
1102 : // reference to ImageBridgeChild. Since this happens on the main thread,
1103 : // ImageBridgeChild will attempt to post a task to the ImageBridge thread.
1104 : // However the thread manager has already been shut down, so the task cannot
1105 : // post.
1106 : //
1107 : // It's okay if this races. We only care about the shutdown case where
1108 : // everything's happening on the main thread. Even if it races outside of
1109 : // shutdown, it's still harmless to post the task, since the task must
1110 : // check CanSend().
1111 0 : return !mDestroyed;
1112 : }
1113 :
1114 : void
1115 0 : ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
1116 : {
1117 0 : if (!InImageBridgeChildThread()) {
1118 : // If we can't post a task, then we definitely cannot send, so there's
1119 : // no reason to queue up this send.
1120 0 : if (!CanPostTask()) {
1121 0 : return;
1122 : }
1123 :
1124 0 : RefPtr<Runnable> runnable = WrapRunnable(
1125 0 : RefPtr<ImageBridgeChild>(this),
1126 : &ImageBridgeChild::ReleaseCompositable,
1127 0 : aHandle);
1128 0 : GetMessageLoop()->PostTask(runnable.forget());
1129 0 : return;
1130 : }
1131 :
1132 0 : if (!CanSend()) {
1133 0 : return;
1134 : }
1135 :
1136 0 : if (!DestroyInTransaction(aHandle)) {
1137 0 : SendReleaseCompositable(aHandle);
1138 : }
1139 :
1140 : {
1141 0 : MutexAutoLock lock(mContainerMapLock);
1142 0 : mImageContainers.Remove(aHandle.Value());
1143 : }
1144 : }
1145 :
1146 : bool
1147 0 : ImageBridgeChild::CanSend() const
1148 : {
1149 0 : MOZ_ASSERT(InImageBridgeChildThread());
1150 0 : return mCanSend;
1151 : }
1152 :
1153 : void
1154 0 : ImageBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
1155 : {
1156 0 : dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
1157 0 : }
1158 :
1159 : wr::MaybeExternalImageId
1160 0 : ImageBridgeChild::GetNextExternalImageId()
1161 : {
1162 : static uint32_t sNextID = 1;
1163 0 : ++sNextID;
1164 0 : MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
1165 :
1166 0 : uint64_t imageId = mNamespace;
1167 0 : imageId = imageId << 32 | sNextID;
1168 0 : return Some(wr::ToExternalImageId(imageId));
1169 : }
1170 :
1171 : } // namespace layers
1172 : } // namespace mozilla
|