1 /* vim: set ts=2 sw=2 et tw=80: */
2 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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 "ImageBridgeParent.h"
8 #include <stdint.h>                     // for uint64_t, uint32_t
9 #include "CompositableHost.h"           // for CompositableParent, Create
10 #include "base/message_loop.h"          // for MessageLoop
11 #include "base/process.h"               // for ProcessId
12 #include "base/task.h"                  // for CancelableTask, DeleteTask, etc
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/gfx/Point.h"                   // for IntSize
15 #include "mozilla/Hal.h"                // for hal::SetCurrentThreadPriority()
16 #include "mozilla/HalTypes.h"           // for hal::THREAD_PRIORITY_COMPOSITOR
17 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
18 #include "mozilla/ipc/ProtocolUtils.h"
19 #include "mozilla/ipc/Transport.h"      // for Transport
20 #include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
21 #include "mozilla/layers/CompositableTransactionParent.h"
22 #include "mozilla/layers/LayerManagerComposite.h"
23 #include "mozilla/layers/LayersMessages.h"  // for EditReply
24 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
25 #include "mozilla/layers/PCompositableParent.h"
26 #include "mozilla/layers/PImageBridgeParent.h"
27 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
28 #include "mozilla/layers/Compositor.h"
29 #include "mozilla/Monitor.h"
30 #include "mozilla/mozalloc.h"           // for operator new, etc
31 #include "mozilla/Unused.h"
32 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
33 #include "nsISupportsImpl.h"            // for ImageBridgeParent::Release, etc
34 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
35 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
36 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
37 #include "mozilla/layers/TextureHost.h"
38 #include "nsThreadUtils.h"
39 
40 namespace mozilla {
41 namespace layers {
42 
43 using namespace mozilla::ipc;
44 using namespace mozilla::gfx;
45 using namespace mozilla::media;
46 
47 std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
48 
49 StaticAutoPtr<mozilla::Monitor> sImageBridgesLock;
50 
51 // defined in CompositorBridgeParent.cpp
52 CompositorThreadHolder* GetCompositorThreadHolder();
53 
54 /* static */ void
Setup()55 ImageBridgeParent::Setup()
56 {
57   MOZ_ASSERT(NS_IsMainThread());
58   if (!sImageBridgesLock) {
59     sImageBridgesLock = new Monitor("ImageBridges");
60     mozilla::ClearOnShutdown(&sImageBridgesLock);
61   }
62 }
63 
ImageBridgeParent(MessageLoop * aLoop,ProcessId aChildProcessId)64 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
65                                      ProcessId aChildProcessId)
66   : mMessageLoop(aLoop)
67   , mSetChildThreadPriority(false)
68   , mClosed(false)
69 {
70   MOZ_ASSERT(NS_IsMainThread());
71 
72   // creates the map only if it has not been created already, so it is safe
73   // with several bridges
74   CompositableMap::Create();
75   {
76     MonitorAutoLock lock(*sImageBridgesLock);
77     sImageBridges[aChildProcessId] = this;
78   }
79   SetOtherProcessId(aChildProcessId);
80 }
81 
~ImageBridgeParent()82 ImageBridgeParent::~ImageBridgeParent()
83 {
84   nsTArray<PImageContainerParent*> parents;
85   ManagedPImageContainerParent(parents);
86   for (PImageContainerParent* p : parents) {
87     delete p;
88   }
89 }
90 
91 static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
92 
ReleaseImageBridgeParentSingleton()93 void ReleaseImageBridgeParentSingleton() {
94   sImageBridgeParentSingleton = nullptr;
95 }
96 
97 /* static */ ImageBridgeParent*
CreateSameProcess()98 ImageBridgeParent::CreateSameProcess()
99 {
100   RefPtr<ImageBridgeParent> parent =
101     new ImageBridgeParent(CompositorThreadHolder::Loop(), base::GetCurrentProcId());
102   parent->mSelfRef = parent;
103 
104   sImageBridgeParentSingleton = parent;
105   return parent;
106 }
107 
108 /* static */ bool
CreateForGPUProcess(Endpoint<PImageBridgeParent> && aEndpoint)109 ImageBridgeParent::CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint)
110 {
111   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
112 
113   MessageLoop* loop = CompositorThreadHolder::Loop();
114   RefPtr<ImageBridgeParent> parent = new ImageBridgeParent(loop, aEndpoint.OtherPid());
115 
116   loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
117     parent, &ImageBridgeParent::Bind, Move(aEndpoint)));
118 
119   sImageBridgeParentSingleton = parent;
120   return true;
121 }
122 
123 void
ActorDestroy(ActorDestroyReason aWhy)124 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
125 {
126   // Can't alloc/dealloc shmems from now on.
127   mClosed = true;
128   {
129     MonitorAutoLock lock(*sImageBridgesLock);
130     sImageBridges.erase(OtherPid());
131   }
132   MessageLoop::current()->PostTask(NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
133 
134   // It is very important that this method gets called at shutdown (be it a clean
135   // or an abnormal shutdown), because DeferredDestroy is what clears mSelfRef.
136   // If mSelfRef is not null and ActorDestroy is not called, the ImageBridgeParent
137   // is leaked which causes the CompositorThreadHolder to be leaked and
138   // CompsoitorParent's shutdown ends up spinning the event loop forever, waiting
139   // for the compositor thread to terminate.
140 }
141 
142 bool
RecvImageBridgeThreadId(const PlatformThreadId & aThreadId)143 ImageBridgeParent::RecvImageBridgeThreadId(const PlatformThreadId& aThreadId)
144 {
145   MOZ_ASSERT(!mSetChildThreadPriority);
146   if (mSetChildThreadPriority) {
147     return false;
148   }
149   mSetChildThreadPriority = true;
150   return true;
151 }
152 
153 class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
154 {
155 public:
AutoImageBridgeParentAsyncMessageSender(ImageBridgeParent * aImageBridge,InfallibleTArray<OpDestroy> * aToDestroy=nullptr)156   explicit AutoImageBridgeParentAsyncMessageSender(ImageBridgeParent* aImageBridge,
157                                                    InfallibleTArray<OpDestroy>* aToDestroy = nullptr)
158     : mImageBridge(aImageBridge)
159     , mToDestroy(aToDestroy)
160   {
161     mImageBridge->SetAboutToSendAsyncMessages();
162   }
163 
~AutoImageBridgeParentAsyncMessageSender()164   ~AutoImageBridgeParentAsyncMessageSender()
165   {
166     mImageBridge->SendPendingAsyncMessages();
167     if (mToDestroy) {
168       for (const auto& op : *mToDestroy) {
169         mImageBridge->DestroyActor(op);
170       }
171     }
172   }
173 private:
174   ImageBridgeParent* mImageBridge;
175   InfallibleTArray<OpDestroy>* mToDestroy;
176 };
177 
178 bool
RecvUpdate(EditArray && aEdits,OpDestroyArray && aToDestroy,const uint64_t & aFwdTransactionId,EditReplyArray * aReply)179 ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
180                               const uint64_t& aFwdTransactionId,
181                               EditReplyArray* aReply)
182 {
183   // This ensures that destroy operations are always processed. It is not safe
184   // to early-return from RecvUpdate without doing so.
185   AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
186   UpdateFwdTransactionId(aFwdTransactionId);
187 
188   EditReplyVector replyv;
189   for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
190     if (!ReceiveCompositableUpdate(aEdits[i], replyv)) {
191       return false;
192     }
193   }
194 
195   aReply->SetCapacity(replyv.size());
196   if (replyv.size() > 0) {
197     aReply->AppendElements(&replyv.front(), replyv.size());
198   }
199 
200   if (!IsSameProcess()) {
201     // Ensure that any pending operations involving back and front
202     // buffers have completed, so that neither process stomps on the
203     // other's buffer contents.
204     LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
205   }
206 
207   return true;
208 }
209 
210 bool
RecvUpdateNoSwap(EditArray && aEdits,OpDestroyArray && aToDestroy,const uint64_t & aFwdTransactionId)211 ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
212                                     const uint64_t& aFwdTransactionId)
213 {
214   InfallibleTArray<EditReply> noReplies;
215   bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), aFwdTransactionId, &noReplies);
216   MOZ_ASSERT(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits");
217   return success;
218 }
219 
220 /* static */ bool
CreateForContent(Endpoint<PImageBridgeParent> && aEndpoint)221 ImageBridgeParent::CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint)
222 {
223   MessageLoop* loop = CompositorThreadHolder::Loop();
224 
225   RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aEndpoint.OtherPid());
226   loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
227     bridge, &ImageBridgeParent::Bind, Move(aEndpoint)));
228 
229   return true;
230 }
231 
232 void
Bind(Endpoint<PImageBridgeParent> && aEndpoint)233 ImageBridgeParent::Bind(Endpoint<PImageBridgeParent>&& aEndpoint)
234 {
235   if (!aEndpoint.Bind(this))
236     return;
237   mSelfRef = this;
238 }
239 
RecvWillClose()240 bool ImageBridgeParent::RecvWillClose()
241 {
242   // If there is any texture still alive we have to force it to deallocate the
243   // device data (GL textures, etc.) now because shortly after SenStop() returns
244   // on the child side the widget will be destroyed along with it's associated
245   // GL context.
246   InfallibleTArray<PTextureParent*> textures;
247   ManagedPTextureParent(textures);
248   for (unsigned int i = 0; i < textures.Length(); ++i) {
249     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
250     tex->DeallocateDeviceData();
251   }
252   return true;
253 }
254 
GenImageContainerID()255 static  uint64_t GenImageContainerID() {
256   static uint64_t sNextImageID = 1;
257 
258   ++sNextImageID;
259   return sNextImageID;
260 }
261 
262 PCompositableParent*
AllocPCompositableParent(const TextureInfo & aInfo,PImageContainerParent * aImageContainer,uint64_t * aID)263 ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo,
264                                             PImageContainerParent* aImageContainer,
265                                             uint64_t* aID)
266 {
267   uint64_t id = GenImageContainerID();
268   *aID = id;
269   return CompositableHost::CreateIPDLActor(this, aInfo, id, aImageContainer);
270 }
271 
DeallocPCompositableParent(PCompositableParent * aActor)272 bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
273 {
274   return CompositableHost::DestroyIPDLActor(aActor);
275 }
276 
277 PTextureParent*
AllocPTextureParent(const SurfaceDescriptor & aSharedData,const LayersBackend & aLayersBackend,const TextureFlags & aFlags,const uint64_t & aSerial)278 ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
279                                        const LayersBackend& aLayersBackend,
280                                        const TextureFlags& aFlags,
281                                        const uint64_t& aSerial)
282 {
283   return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
284 }
285 
286 bool
DeallocPTextureParent(PTextureParent * actor)287 ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
288 {
289   return TextureHost::DestroyIPDLActor(actor);
290 }
291 
292 PMediaSystemResourceManagerParent*
AllocPMediaSystemResourceManagerParent()293 ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
294 {
295   return new mozilla::media::MediaSystemResourceManagerParent();
296 }
297 
298 bool
DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent * aActor)299 ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
300 {
301   MOZ_ASSERT(aActor);
302   delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
303   return true;
304 }
305 
306 PImageContainerParent*
AllocPImageContainerParent()307 ImageBridgeParent::AllocPImageContainerParent()
308 {
309   return new ImageContainerParent();
310 }
311 
312 bool
DeallocPImageContainerParent(PImageContainerParent * actor)313 ImageBridgeParent::DeallocPImageContainerParent(PImageContainerParent* actor)
314 {
315   delete actor;
316   return true;
317 }
318 
319 void
SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData> & aMessage)320 ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
321 {
322   mozilla::Unused << SendParentAsyncMessages(aMessage);
323 }
324 
325 class ProcessIdComparator
326 {
327 public:
Equals(const ImageCompositeNotification & aA,const ImageCompositeNotification & aB) const328   bool Equals(const ImageCompositeNotification& aA,
329               const ImageCompositeNotification& aB) const
330   {
331     return aA.imageContainerParent()->OtherPid() == aB.imageContainerParent()->OtherPid();
332   }
LessThan(const ImageCompositeNotification & aA,const ImageCompositeNotification & aB) const333   bool LessThan(const ImageCompositeNotification& aA,
334                 const ImageCompositeNotification& aB) const
335   {
336     return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid();
337   }
338 };
339 
340 /* static */ bool
NotifyImageComposites(nsTArray<ImageCompositeNotification> & aNotifications)341 ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications)
342 {
343   // Group the notifications by destination process ID and then send the
344   // notifications in one message per group.
345   aNotifications.Sort(ProcessIdComparator());
346   uint32_t i = 0;
347   bool ok = true;
348   while (i < aNotifications.Length()) {
349     AutoTArray<ImageCompositeNotification,1> notifications;
350     notifications.AppendElement(aNotifications[i]);
351     uint32_t end = i + 1;
352     MOZ_ASSERT(aNotifications[i].imageContainerParent());
353     ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
354     while (end < aNotifications.Length() &&
355            aNotifications[end].imageContainerParent()->OtherPid() == pid) {
356       notifications.AppendElement(aNotifications[end]);
357       ++end;
358     }
359     GetInstance(pid)->SendPendingAsyncMessages();
360     if (!GetInstance(pid)->SendDidComposite(notifications)) {
361       ok = false;
362     }
363     i = end;
364   }
365   return ok;
366 }
367 
368 void
DeferredDestroy()369 ImageBridgeParent::DeferredDestroy()
370 {
371   mCompositorThreadHolder = nullptr;
372   mSelfRef = nullptr; // "this" ImageBridge may get deleted here.
373 }
374 
375 RefPtr<ImageBridgeParent>
GetInstance(ProcessId aId)376 ImageBridgeParent::GetInstance(ProcessId aId)
377 {
378   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
379   MonitorAutoLock lock(*sImageBridgesLock);
380   NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
381   return sImageBridges[aId];
382 }
383 
384 void
OnChannelConnected(int32_t aPid)385 ImageBridgeParent::OnChannelConnected(int32_t aPid)
386 {
387   mCompositorThreadHolder = GetCompositorThreadHolder();
388 }
389 
390 
391 bool
AllocShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)392 ImageBridgeParent::AllocShmem(size_t aSize,
393                       ipc::SharedMemory::SharedMemoryType aType,
394                       ipc::Shmem* aShmem)
395 {
396   if (mClosed) {
397     return false;
398   }
399   return PImageBridgeParent::AllocShmem(aSize, aType, aShmem);
400 }
401 
402 bool
AllocUnsafeShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)403 ImageBridgeParent::AllocUnsafeShmem(size_t aSize,
404                       ipc::SharedMemory::SharedMemoryType aType,
405                       ipc::Shmem* aShmem)
406 {
407   if (mClosed) {
408     return false;
409   }
410   return PImageBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
411 }
412 
413 void
DeallocShmem(ipc::Shmem & aShmem)414 ImageBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
415 {
416   if (mClosed) {
417     return;
418   }
419   PImageBridgeParent::DeallocShmem(aShmem);
420 }
421 
IsSameProcess() const422 bool ImageBridgeParent::IsSameProcess() const
423 {
424   return OtherPid() == base::GetCurrentProcId();
425 }
426 
427 void
NotifyNotUsed(PTextureParent * aTexture,uint64_t aTransactionId)428 ImageBridgeParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
429 {
430   RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
431   if (!texture) {
432     return;
433   }
434 
435   if (!(texture->GetFlags() & TextureFlags::RECYCLE)) {
436     return;
437   }
438 
439   uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
440   mPendingAsyncMessage.push_back(
441     OpNotifyNotUsed(textureId, aTransactionId));
442 
443   if (!IsAboutToSendAsyncMessages()) {
444     SendPendingAsyncMessages();
445   }
446 }
447 
448 } // namespace layers
449 } // namespace mozilla
450