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