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