gfx/layers/ipc/CompositorParent.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:6c38456ef7ae
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et 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 "CompositorParent.h"
8 #include <stdio.h> // for fprintf, stdout
9 #include <stdint.h> // for uint64_t
10 #include <map> // for _Rb_tree_iterator, etc
11 #include <utility> // for pair
12 #include "LayerTransactionParent.h" // for LayerTransactionParent
13 #include "RenderTrace.h" // for RenderTraceLayers
14 #include "base/message_loop.h" // for MessageLoop
15 #include "base/process.h" // for ProcessHandle
16 #include "base/process_util.h" // for OpenProcessHandle
17 #include "base/task.h" // for CancelableTask, etc
18 #include "base/thread.h" // for Thread
19 #include "base/tracked.h" // for FROM_HERE
20 #include "gfxContext.h" // for gfxContext
21 #include "gfxPlatform.h" // for gfxPlatform
22 #include "gfxPrefs.h" // for gfxPrefs
23 #include "ipc/ShadowLayersManager.h" // for ShadowLayersManager
24 #include "mozilla/AutoRestore.h" // for AutoRestore
25 #include "mozilla/DebugOnly.h" // for DebugOnly
26 #include "mozilla/gfx/2D.h" // for DrawTarget
27 #include "mozilla/gfx/Point.h" // for IntSize
28 #include "mozilla/ipc/Transport.h" // for Transport
29 #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
30 #include "mozilla/layers/AsyncCompositionManager.h"
31 #include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
32 #include "mozilla/layers/Compositor.h" // for Compositor
33 #include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
34 #include "mozilla/layers/CompositorTypes.h"
35 #include "mozilla/layers/LayerManagerComposite.h"
36 #include "mozilla/layers/LayersTypes.h"
37 #include "mozilla/layers/PLayerTransactionParent.h"
38 #include "mozilla/mozalloc.h" // for operator new, etc
39 #include "nsCOMPtr.h" // for already_AddRefed
40 #include "nsDebug.h" // for NS_ABORT_IF_FALSE, etc
41 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
42 #include "nsIWidget.h" // for nsIWidget
43 #include "nsRect.h" // for nsIntRect
44 #include "nsTArray.h" // for nsTArray
45 #include "nsThreadUtils.h" // for NS_IsMainThread
46 #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
47 #ifdef XP_WIN
48 #include "mozilla/layers/CompositorD3D11.h"
49 #include "mozilla/layers/CompositorD3D9.h"
50 #endif
51 #include "GeckoProfiler.h"
52 #include "mozilla/ipc/ProtocolTypes.h"
53 #include "mozilla/unused.h"
54
55 using namespace base;
56 using namespace mozilla;
57 using namespace mozilla::ipc;
58 using namespace mozilla::gfx;
59 using namespace std;
60
61 namespace mozilla {
62 namespace layers {
63
64 CompositorParent::LayerTreeState::LayerTreeState()
65 : mParent(nullptr)
66 , mLayerManager(nullptr)
67 , mCrossProcessParent(nullptr)
68 {
69 }
70
71 typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
72 static LayerTreeMap sIndirectLayerTrees;
73
74 // FIXME/bug 774386: we're assuming that there's only one
75 // CompositorParent, but that's not always true. This assumption only
76 // affects CrossProcessCompositorParent below.
77 static Thread* sCompositorThread = nullptr;
78 // manual reference count of the compositor thread.
79 static int sCompositorThreadRefCount = 0;
80 static MessageLoop* sMainLoop = nullptr;
81 // When ContentParent::StartUp() is called, we use the Thread global.
82 // When StartUpWithExistingThread() is used, we have to use the two
83 // duplicated globals, because there's no API to make a Thread from an
84 // existing thread.
85 static PlatformThreadId sCompositorThreadID = 0;
86 static MessageLoop* sCompositorLoop = nullptr;
87
88 // See ImageBridgeChild.cpp
89 void ReleaseImageBridgeParentSingleton();
90
91 static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie)
92 {
93 aNowReadyToDie->Release();
94 }
95
96 static void DeleteCompositorThread()
97 {
98 if (NS_IsMainThread()){
99 ReleaseImageBridgeParentSingleton();
100 delete sCompositorThread;
101 sCompositorThread = nullptr;
102 sCompositorLoop = nullptr;
103 sCompositorThreadID = 0;
104 } else {
105 sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread));
106 }
107 }
108
109 static void ReleaseCompositorThread()
110 {
111 if(--sCompositorThreadRefCount == 0) {
112 DeleteCompositorThread();
113 }
114 }
115
116 void
117 CompositorParent::StartUpWithExistingThread(MessageLoop* aMsgLoop,
118 PlatformThreadId aThreadID)
119 {
120 MOZ_ASSERT(!sCompositorThread);
121 CreateCompositorMap();
122 sCompositorLoop = aMsgLoop;
123 sCompositorThreadID = aThreadID;
124 sMainLoop = MessageLoop::current();
125 sCompositorThreadRefCount = 1;
126 }
127
128 void CompositorParent::StartUp()
129 {
130 // Check if compositor started already with StartUpWithExistingThread
131 if (sCompositorThreadID) {
132 return;
133 }
134 MOZ_ASSERT(!sCompositorLoop);
135 CreateCompositorMap();
136 CreateThread();
137 sMainLoop = MessageLoop::current();
138 }
139
140 void CompositorParent::ShutDown()
141 {
142 DestroyThread();
143 DestroyCompositorMap();
144 }
145
146 bool CompositorParent::CreateThread()
147 {
148 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
149 if (sCompositorThread || sCompositorLoop) {
150 return true;
151 }
152 sCompositorThreadRefCount = 1;
153 sCompositorThread = new Thread("Compositor");
154
155 Thread::Options options;
156 /* Timeout values are powers-of-two to enable us get better data.
157 128ms is chosen for transient hangs because 8Hz should be the minimally
158 acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
159 options.transient_hang_timeout = 128; // milliseconds
160 /* 8192ms is chosen for permanent hangs because it's several seconds longer
161 than the default hang timeout on major platforms (about 5 seconds). */
162 options.permanent_hang_timeout = 8192; // milliseconds
163
164 if (!sCompositorThread->StartWithOptions(options)) {
165 delete sCompositorThread;
166 sCompositorThread = nullptr;
167 return false;
168 }
169 return true;
170 }
171
172 void CompositorParent::DestroyThread()
173 {
174 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
175 ReleaseCompositorThread();
176 }
177
178 MessageLoop* CompositorParent::CompositorLoop()
179 {
180 return sCompositorThread ? sCompositorThread->message_loop() : sCompositorLoop;
181 }
182
183 CompositorParent::CompositorParent(nsIWidget* aWidget,
184 bool aUseExternalSurfaceSize,
185 int aSurfaceWidth, int aSurfaceHeight)
186 : mWidget(aWidget)
187 , mCurrentCompositeTask(nullptr)
188 , mIsTesting(false)
189 , mPaused(false)
190 , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
191 , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight)
192 , mPauseCompositionMonitor("PauseCompositionMonitor")
193 , mResumeCompositionMonitor("ResumeCompositionMonitor")
194 , mOverrideComposeReadiness(false)
195 , mForceCompositionTask(nullptr)
196 , mWantDidCompositeEvent(false)
197 {
198 NS_ABORT_IF_FALSE(sCompositorThread != nullptr || sCompositorThreadID,
199 "The compositor thread must be Initialized before instanciating a COmpositorParent.");
200 MOZ_COUNT_CTOR(CompositorParent);
201 mCompositorID = 0;
202 // FIXME: This holds on the the fact that right now the only thing that
203 // can destroy this instance is initialized on the compositor thread after
204 // this task has been processed.
205 CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor,
206 this, &mCompositorID));
207
208 mRootLayerTreeID = AllocateLayerTreeId();
209 sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
210
211 mApzcTreeManager = new APZCTreeManager();
212 ++sCompositorThreadRefCount;
213 }
214
215 PlatformThreadId
216 CompositorParent::CompositorThreadID()
217 {
218 return sCompositorThread ? sCompositorThread->thread_id() : sCompositorThreadID;
219 }
220
221 bool
222 CompositorParent::IsInCompositorThread()
223 {
224 return CompositorThreadID() == PlatformThread::CurrentId();
225 }
226
227 uint64_t
228 CompositorParent::RootLayerTreeId()
229 {
230 return mRootLayerTreeID;
231 }
232
233 CompositorParent::~CompositorParent()
234 {
235 MOZ_COUNT_DTOR(CompositorParent);
236
237 ReleaseCompositorThread();
238 }
239
240 void
241 CompositorParent::Destroy()
242 {
243 NS_ABORT_IF_FALSE(ManagedPLayerTransactionParent().Length() == 0,
244 "CompositorParent destroyed before managed PLayerTransactionParent");
245
246 // Ensure that the layer manager is destructed on the compositor thread.
247 mLayerManager = nullptr;
248 mCompositor = nullptr;
249 mCompositionManager = nullptr;
250 mApzcTreeManager->ClearTree();
251 mApzcTreeManager = nullptr;
252 sIndirectLayerTrees.erase(mRootLayerTreeID);
253 }
254
255 void
256 CompositorParent::ForceIsFirstPaint()
257 {
258 mCompositionManager->ForceIsFirstPaint();
259 }
260
261 bool
262 CompositorParent::RecvWillStop()
263 {
264 mPaused = true;
265 RemoveCompositor(mCompositorID);
266
267 // Ensure that the layer manager is destroyed before CompositorChild.
268 if (mLayerManager) {
269 for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
270 it != sIndirectLayerTrees.end(); it++)
271 {
272 LayerTreeState* lts = &it->second;
273 if (lts->mParent == this) {
274 mLayerManager->ClearCachedResources(lts->mRoot);
275 lts->mLayerManager = nullptr;
276 }
277 }
278 mLayerManager->Destroy();
279 mLayerManager = nullptr;
280 mCompositor = nullptr;
281 mCompositionManager = nullptr;
282 }
283
284 return true;
285 }
286
287 bool
288 CompositorParent::RecvStop()
289 {
290 Destroy();
291 // There are chances that the ref count reaches zero on the main thread shortly
292 // after this function returns while some ipdl code still needs to run on
293 // this thread.
294 // We must keep the compositor parent alive untill the code handling message
295 // reception is finished on this thread.
296 this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release
297 CompositorLoop()->PostTask(FROM_HERE,
298 NewRunnableFunction(&DeferredDeleteCompositorParent,
299 this));
300 return true;
301 }
302
303 bool
304 CompositorParent::RecvPause()
305 {
306 PauseComposition();
307 return true;
308 }
309
310 bool
311 CompositorParent::RecvResume()
312 {
313 ResumeComposition();
314 return true;
315 }
316
317 bool
318 CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
319 SurfaceDescriptor* aOutSnapshot)
320 {
321 RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
322 ForceComposeToTarget(target);
323 *aOutSnapshot = aInSnapshot;
324 return true;
325 }
326
327 bool
328 CompositorParent::RecvFlushRendering()
329 {
330 // If we're waiting to do a composite, then cancel it
331 // and do it immediately instead.
332 if (mCurrentCompositeTask) {
333 CancelCurrentCompositeTask();
334 ForceComposeToTarget(nullptr);
335 }
336 return true;
337 }
338
339 bool
340 CompositorParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
341 {
342 if (mLayerManager) {
343 mLayerManager->AddInvalidRegion(aRegion);
344 }
345 return true;
346 }
347
348 bool
349 CompositorParent::RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex)
350 {
351 if (mLayerManager) {
352 *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize);
353 } else {
354 *aOutStartIndex = 0;
355 }
356 return true;
357 }
358
359 bool
360 CompositorParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex,
361 InfallibleTArray<float>* intervals)
362 {
363 if (mLayerManager) {
364 mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals);
365 }
366 return true;
367 }
368
369 void
370 CompositorParent::ActorDestroy(ActorDestroyReason why)
371 {
372 CancelCurrentCompositeTask();
373 if (mForceCompositionTask) {
374 mForceCompositionTask->Cancel();
375 mForceCompositionTask = nullptr;
376 }
377 mPaused = true;
378 RemoveCompositor(mCompositorID);
379
380 if (mLayerManager) {
381 mLayerManager->Destroy();
382 mLayerManager = nullptr;
383 sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr;
384 mCompositionManager = nullptr;
385 mCompositor = nullptr;
386 }
387 }
388
389
390 void
391 CompositorParent::ScheduleRenderOnCompositorThread()
392 {
393 CancelableTask *renderTask = NewRunnableMethod(this, &CompositorParent::ScheduleComposition);
394 CompositorLoop()->PostTask(FROM_HERE, renderTask);
395 }
396
397 void
398 CompositorParent::PauseComposition()
399 {
400 NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(),
401 "PauseComposition() can only be called on the compositor thread");
402
403 MonitorAutoLock lock(mPauseCompositionMonitor);
404
405 if (!mPaused) {
406 mPaused = true;
407
408 mCompositor->Pause();
409 }
410
411 // if anyone's waiting to make sure that composition really got paused, tell them
412 lock.NotifyAll();
413 }
414
415 void
416 CompositorParent::ResumeComposition()
417 {
418 NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(),
419 "ResumeComposition() can only be called on the compositor thread");
420
421 MonitorAutoLock lock(mResumeCompositionMonitor);
422
423 if (!mCompositor->Resume()) {
424 #ifdef MOZ_WIDGET_ANDROID
425 // We can't get a surface. This could be because the activity changed between
426 // the time resume was scheduled and now.
427 __android_log_print(ANDROID_LOG_INFO, "CompositorParent", "Unable to renew compositor surface; remaining in paused state");
428 #endif
429 lock.NotifyAll();
430 return;
431 }
432
433 mPaused = false;
434
435 Composite();
436
437 // if anyone's waiting to make sure that composition really got resumed, tell them
438 lock.NotifyAll();
439 }
440
441 void
442 CompositorParent::ForceComposition()
443 {
444 // Cancel the orientation changed state to force composition
445 mForceCompositionTask = nullptr;
446 ScheduleRenderOnCompositorThread();
447 }
448
449 void
450 CompositorParent::CancelCurrentCompositeTask()
451 {
452 if (mCurrentCompositeTask) {
453 mCurrentCompositeTask->Cancel();
454 mCurrentCompositeTask = nullptr;
455 }
456 }
457
458 void
459 CompositorParent::SetEGLSurfaceSize(int width, int height)
460 {
461 NS_ASSERTION(mUseExternalSurfaceSize, "Compositor created without UseExternalSurfaceSize provided");
462 mEGLSurfaceSize.SizeTo(width, height);
463 if (mCompositor) {
464 mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height));
465 }
466 }
467
468 void
469 CompositorParent::ResumeCompositionAndResize(int width, int height)
470 {
471 SetEGLSurfaceSize(width, height);
472 ResumeComposition();
473 }
474
475 /*
476 * This will execute a pause synchronously, waiting to make sure that the compositor
477 * really is paused.
478 */
479 void
480 CompositorParent::SchedulePauseOnCompositorThread()
481 {
482 MonitorAutoLock lock(mPauseCompositionMonitor);
483
484 CancelableTask *pauseTask = NewRunnableMethod(this,
485 &CompositorParent::PauseComposition);
486 CompositorLoop()->PostTask(FROM_HERE, pauseTask);
487
488 // Wait until the pause has actually been processed by the compositor thread
489 lock.Wait();
490 }
491
492 bool
493 CompositorParent::ScheduleResumeOnCompositorThread(int width, int height)
494 {
495 MonitorAutoLock lock(mResumeCompositionMonitor);
496
497 CancelableTask *resumeTask =
498 NewRunnableMethod(this, &CompositorParent::ResumeCompositionAndResize, width, height);
499 CompositorLoop()->PostTask(FROM_HERE, resumeTask);
500
501 // Wait until the resume has actually been processed by the compositor thread
502 lock.Wait();
503
504 return !mPaused;
505 }
506
507 void
508 CompositorParent::ScheduleTask(CancelableTask* task, int time)
509 {
510 if (time == 0) {
511 MessageLoop::current()->PostTask(FROM_HERE, task);
512 } else {
513 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, time);
514 }
515 }
516
517 void
518 CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite)
519 {
520 if (mApzcTreeManager &&
521 mLayerManager &&
522 mLayerManager->GetRoot()) {
523 AutoResolveRefLayers resolve(mCompositionManager);
524 mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId);
525
526 mLayerManager->NotifyShadowTreeTransaction();
527 }
528 if (aScheduleComposite) {
529 ScheduleComposition();
530 }
531
532 mWantDidCompositeEvent = true;
533 }
534
535 // Used when layout.frame_rate is -1. Needs to be kept in sync with
536 // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
537 static const int32_t kDefaultFrameRate = 60;
538
539 static int32_t
540 CalculateCompositionFrameRate()
541 {
542 int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate();
543 if (compositionFrameRatePref < 0) {
544 // Use the same frame rate for composition as for layout.
545 int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate();
546 if (layoutFrameRatePref < 0) {
547 // TODO: The main thread frame scheduling code consults the actual
548 // monitor refresh rate in this case. We should do the same.
549 return kDefaultFrameRate;
550 }
551 return layoutFrameRatePref;
552 }
553 return compositionFrameRatePref;
554 }
555
556 void
557 CompositorParent::ScheduleComposition()
558 {
559 if (mCurrentCompositeTask || mPaused) {
560 return;
561 }
562
563 bool initialComposition = mLastCompose.IsNull();
564 TimeDuration delta;
565 if (!initialComposition)
566 delta = TimeStamp::Now() - mLastCompose;
567
568 int32_t rate = CalculateCompositionFrameRate();
569
570 // If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.
571 TimeDuration minFrameDelta = TimeDuration::FromMilliseconds(
572 rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
573
574
575 mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::Composite);
576
577 if (!initialComposition && delta < minFrameDelta) {
578 TimeDuration delay = minFrameDelta - delta;
579 #ifdef COMPOSITOR_PERFORMANCE_WARNING
580 mExpectedComposeStartTime = TimeStamp::Now() + delay;
581 #endif
582 ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds());
583 } else {
584 #ifdef COMPOSITOR_PERFORMANCE_WARNING
585 mExpectedComposeStartTime = TimeStamp::Now();
586 #endif
587 ScheduleTask(mCurrentCompositeTask, 0);
588 }
589 }
590
591 void
592 CompositorParent::Composite()
593 {
594 CompositeToTarget(nullptr);
595 }
596
597 void
598 CompositorParent::CompositeToTarget(DrawTarget* aTarget)
599 {
600 profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
601 PROFILER_LABEL("CompositorParent", "Composite");
602 NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(),
603 "Composite can only be called on the compositor thread");
604
605 #ifdef COMPOSITOR_PERFORMANCE_WARNING
606 TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime;
607 if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
608 scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
609 printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
610 scheduleDelta.ToMilliseconds());
611 }
612 #endif
613
614 if (mCurrentCompositeTask) {
615 mCurrentCompositeTask->Cancel();
616 mCurrentCompositeTask = nullptr;
617 }
618
619 mLastCompose = TimeStamp::Now();
620
621 if (!CanComposite()) {
622 return;
623 }
624
625 AutoResolveRefLayers resolve(mCompositionManager);
626
627 if (aTarget) {
628 mLayerManager->BeginTransactionWithDrawTarget(aTarget);
629 } else {
630 mLayerManager->BeginTransaction();
631 }
632
633 if (mForceCompositionTask && !mOverrideComposeReadiness) {
634 if (mCompositionManager->ReadyForCompose()) {
635 mForceCompositionTask->Cancel();
636 mForceCompositionTask = nullptr;
637 } else {
638 return;
639 }
640 }
641
642 TimeStamp time = mIsTesting ? mTestTime : mLastCompose;
643 bool requestNextFrame = mCompositionManager->TransformShadowTree(time);
644 if (requestNextFrame) {
645 ScheduleComposition();
646 }
647
648 RenderTraceLayers(mLayerManager->GetRoot(), "0000");
649
650 mCompositionManager->ComputeRotation();
651
652 #ifdef MOZ_DUMP_PAINTING
653 static bool gDumpCompositorTree = false;
654 if (gDumpCompositorTree) {
655 printf_stderr("Painting --- compositing layer tree:\n");
656 mLayerManager->Dump();
657 }
658 #endif
659 mLayerManager->SetDebugOverlayWantsNextFrame(false);
660 mLayerManager->EndEmptyTransaction();
661
662 if (!aTarget && mWantDidCompositeEvent) {
663 DidComposite();
664 mWantDidCompositeEvent = false;
665 }
666
667 if (mLayerManager->DebugOverlayWantsNextFrame()) {
668 ScheduleComposition();
669 }
670
671 #ifdef COMPOSITOR_PERFORMANCE_WARNING
672 TimeDuration executionTime = TimeStamp::Now() - mLastCompose;
673 TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
674 int32_t frameRate = CalculateCompositionFrameRate();
675 if (frameRate > 0) {
676 frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
677 }
678 if (executionTime > frameBudget) {
679 printf_stderr("Compositor: Composite execution took %4.1f ms\n",
680 executionTime.ToMilliseconds());
681 }
682 #endif
683
684 // 0 -> Full-tilt composite
685 if (gfxPrefs::LayersCompositionFrameRate() == 0
686 || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DIAGNOSTIC_FLASH_BORDERS) {
687 // Special full-tilt composite mode for performance testing
688 ScheduleComposition();
689 }
690
691 profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
692 }
693
694 void
695 CompositorParent::DidComposite()
696 {
697 unused << SendDidComposite(0);
698
699 for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
700 it != sIndirectLayerTrees.end(); it++) {
701 LayerTreeState* lts = &it->second;
702 if (lts->mParent == this && lts->mCrossProcessParent) {
703 unused << lts->mCrossProcessParent->SendDidComposite(it->first);
704 }
705 }
706 }
707
708 void
709 CompositorParent::ForceComposeToTarget(DrawTarget* aTarget)
710 {
711 PROFILER_LABEL("CompositorParent", "ForceComposeToTarget");
712 AutoRestore<bool> override(mOverrideComposeReadiness);
713 mOverrideComposeReadiness = true;
714
715 CompositeToTarget(aTarget);
716 }
717
718 bool
719 CompositorParent::CanComposite()
720 {
721 return !(mPaused || !mLayerManager || !mLayerManager->GetRoot());
722 }
723
724 // Go down the composite layer tree, setting properties to match their
725 // content-side counterparts.
726 static void
727 SetShadowProperties(Layer* aLayer)
728 {
729 // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate.
730 LayerComposite* layerComposite = aLayer->AsLayerComposite();
731 // Set the layerComposite's base transform to the layer's base transform.
732 layerComposite->SetShadowTransform(aLayer->GetBaseTransform());
733 layerComposite->SetShadowTransformSetByAnimation(false);
734 layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
735 layerComposite->SetShadowClipRect(aLayer->GetClipRect());
736 layerComposite->SetShadowOpacity(aLayer->GetOpacity());
737
738 for (Layer* child = aLayer->GetFirstChild();
739 child; child = child->GetNextSibling()) {
740 SetShadowProperties(child);
741 }
742 }
743
744 void
745 CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
746 const TargetConfig& aTargetConfig,
747 bool aIsFirstPaint,
748 bool aScheduleComposite)
749 {
750 if (!aIsFirstPaint &&
751 !mCompositionManager->IsFirstPaint() &&
752 mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
753 if (mForceCompositionTask != nullptr) {
754 mForceCompositionTask->Cancel();
755 }
756 mForceCompositionTask = NewRunnableMethod(this, &CompositorParent::ForceComposition);
757 ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis());
758 }
759
760 // Instruct the LayerManager to update its render bounds now. Since all the orientation
761 // change, dimension change would be done at the stage, update the size here is free of
762 // race condition.
763 mLayerManager->UpdateRenderBounds(aTargetConfig.clientBounds());
764 mLayerManager->SetRegionToClear(aTargetConfig.clearRegion());
765
766 mCompositionManager->Updated(aIsFirstPaint, aTargetConfig);
767 Layer* root = aLayerTree->GetRoot();
768 mLayerManager->SetRoot(root);
769
770 if (mApzcTreeManager) {
771 AutoResolveRefLayers resolve(mCompositionManager);
772 mApzcTreeManager->UpdatePanZoomControllerTree(this, root, aIsFirstPaint, mRootLayerTreeID);
773 }
774
775 if (root) {
776 SetShadowProperties(root);
777 }
778 if (aScheduleComposite) {
779 ScheduleComposition();
780 // When testing we synchronously update the shadow tree with the animated
781 // values to avoid race conditions when calling GetAnimationTransform etc.
782 // (since the above SetShadowProperties will remove animation effects).
783 // However, we only do this update when a composite operation is already
784 // scheduled in order to better match the behavior under regular sampling
785 // conditions.
786 if (mIsTesting && root && mCurrentCompositeTask) {
787 AutoResolveRefLayers resolve(mCompositionManager);
788 bool requestNextFrame =
789 mCompositionManager->TransformShadowTree(mTestTime);
790 if (!requestNextFrame) {
791 CancelCurrentCompositeTask();
792 }
793 }
794 }
795 mLayerManager->NotifyShadowTreeTransaction();
796 mWantDidCompositeEvent = true;
797 }
798
799 void
800 CompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
801 {
802 ScheduleComposition();
803 }
804
805 bool
806 CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
807 const TimeStamp& aTime)
808 {
809 if (aTime.IsNull()) {
810 return false;
811 }
812
813 mIsTesting = true;
814 mTestTime = aTime;
815
816 // Update but only if we were already scheduled to animate
817 if (mCompositionManager && mCurrentCompositeTask) {
818 AutoResolveRefLayers resolve(mCompositionManager);
819 bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime);
820 if (!requestNextFrame) {
821 CancelCurrentCompositeTask();
822 }
823 }
824
825 return true;
826 }
827
828 void
829 CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
830 {
831 mIsTesting = false;
832 }
833
834 void
835 CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
836 {
837 NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
838 NS_ASSERTION(!mCompositor, "Already initialised mCompositor");
839
840 for (size_t i = 0; i < aBackendHints.Length(); ++i) {
841 RefPtr<Compositor> compositor;
842 if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
843 compositor = new CompositorOGL(mWidget,
844 mEGLSurfaceSize.width,
845 mEGLSurfaceSize.height,
846 mUseExternalSurfaceSize);
847 } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) {
848 compositor = new BasicCompositor(mWidget);
849 #ifdef XP_WIN
850 } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
851 compositor = new CompositorD3D11(mWidget);
852 } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9) {
853 compositor = new CompositorD3D9(this, mWidget);
854 #endif
855 }
856
857 if (!compositor) {
858 // We passed a backend hint for which we can't create a compositor.
859 // For example, we sometime pass LayersBackend::LAYERS_NONE as filler in aBackendHints.
860 continue;
861 }
862
863 compositor->SetCompositorID(mCompositorID);
864 RefPtr<LayerManagerComposite> layerManager = new LayerManagerComposite(compositor);
865
866 if (layerManager->Initialize()) {
867 mLayerManager = layerManager;
868 MOZ_ASSERT(compositor);
869 mCompositor = compositor;
870 sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = layerManager;
871 return;
872 }
873 }
874 }
875
876 PLayerTransactionParent*
877 CompositorParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
878 const uint64_t& aId,
879 TextureFactoryIdentifier* aTextureFactoryIdentifier,
880 bool *aSuccess)
881 {
882 MOZ_ASSERT(aId == 0);
883
884 // mWidget doesn't belong to the compositor thread, so it should be set to
885 // nullptr before returning from this method, to avoid accessing it elsewhere.
886 nsIntRect rect;
887 mWidget->GetClientBounds(rect);
888 InitializeLayerManager(aBackendHints);
889 mWidget = nullptr;
890
891 if (!mLayerManager) {
892 NS_WARNING("Failed to initialise Compositor");
893 *aSuccess = false;
894 LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, 0);
895 p->AddIPDLReference();
896 return p;
897 }
898
899 mCompositionManager = new AsyncCompositionManager(mLayerManager);
900 *aSuccess = true;
901
902 *aTextureFactoryIdentifier = mCompositor->GetTextureFactoryIdentifier();
903 LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, 0);
904 p->AddIPDLReference();
905 return p;
906 }
907
908 bool
909 CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor)
910 {
911 static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();
912 return true;
913 }
914
915
916 typedef map<uint64_t,CompositorParent*> CompositorMap;
917 static CompositorMap* sCompositorMap;
918
919 void CompositorParent::CreateCompositorMap()
920 {
921 if (sCompositorMap == nullptr) {
922 sCompositorMap = new CompositorMap;
923 }
924 }
925
926 void CompositorParent::DestroyCompositorMap()
927 {
928 if (sCompositorMap != nullptr) {
929 NS_ASSERTION(sCompositorMap->empty(),
930 "The Compositor map should be empty when destroyed>");
931 delete sCompositorMap;
932 sCompositorMap = nullptr;
933 }
934 }
935
936 CompositorParent* CompositorParent::GetCompositor(uint64_t id)
937 {
938 CompositorMap::iterator it = sCompositorMap->find(id);
939 return it != sCompositorMap->end() ? it->second : nullptr;
940 }
941
942 void CompositorParent::AddCompositor(CompositorParent* compositor, uint64_t* outID)
943 {
944 static uint64_t sNextID = 1;
945
946 ++sNextID;
947 (*sCompositorMap)[sNextID] = compositor;
948 *outID = sNextID;
949 }
950
951 CompositorParent* CompositorParent::RemoveCompositor(uint64_t id)
952 {
953 CompositorMap::iterator it = sCompositorMap->find(id);
954 if (it == sCompositorMap->end()) {
955 return nullptr;
956 }
957 CompositorParent *retval = it->second;
958 sCompositorMap->erase(it);
959 return retval;
960 }
961
962 bool
963 CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
964 {
965 NotifyChildCreated(child);
966 return true;
967 }
968
969 void
970 CompositorParent::NotifyChildCreated(uint64_t aChild)
971 {
972 sIndirectLayerTrees[aChild].mParent = this;
973 sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
974 }
975
976 /*static*/ uint64_t
977 CompositorParent::AllocateLayerTreeId()
978 {
979 MOZ_ASSERT(CompositorLoop());
980 MOZ_ASSERT(NS_IsMainThread());
981 static uint64_t ids = 0;
982 return ++ids;
983 }
984
985 static void
986 EraseLayerState(uint64_t aId)
987 {
988 sIndirectLayerTrees.erase(aId);
989 }
990
991 /*static*/ void
992 CompositorParent::DeallocateLayerTreeId(uint64_t aId)
993 {
994 MOZ_ASSERT(NS_IsMainThread());
995 CompositorLoop()->PostTask(FROM_HERE,
996 NewRunnableFunction(&EraseLayerState, aId));
997 }
998
999 static void
1000 UpdateControllerForLayersId(uint64_t aLayersId,
1001 GeckoContentController* aController)
1002 {
1003 // Adopt ref given to us by SetControllerForLayerTree()
1004 sIndirectLayerTrees[aLayersId].mController =
1005 already_AddRefed<GeckoContentController>(aController);
1006 }
1007
1008 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(uint64_t aLayersId,
1009 Layer* aRoot,
1010 GeckoContentController* aController)
1011 : mLayersId(aLayersId)
1012 {
1013 sIndirectLayerTrees[aLayersId].mRoot = aRoot;
1014 sIndirectLayerTrees[aLayersId].mController = aController;
1015 }
1016
1017 ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration()
1018 {
1019 sIndirectLayerTrees.erase(mLayersId);
1020 }
1021
1022 /*static*/ void
1023 CompositorParent::SetControllerForLayerTree(uint64_t aLayersId,
1024 GeckoContentController* aController)
1025 {
1026 // This ref is adopted by UpdateControllerForLayersId().
1027 aController->AddRef();
1028 CompositorLoop()->PostTask(FROM_HERE,
1029 NewRunnableFunction(&UpdateControllerForLayersId,
1030 aLayersId,
1031 aController));
1032 }
1033
1034 /*static*/ APZCTreeManager*
1035 CompositorParent::GetAPZCTreeManager(uint64_t aLayersId)
1036 {
1037 const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
1038 if (state && state->mParent) {
1039 return state->mParent->mApzcTreeManager;
1040 }
1041 return nullptr;
1042 }
1043
1044 float
1045 CompositorParent::ComputeRenderIntegrity()
1046 {
1047 if (mLayerManager) {
1048 return mLayerManager->ComputeRenderIntegrity();
1049 }
1050
1051 return 1.0f;
1052 }
1053
1054
1055 /**
1056 * This class handles layer updates pushed directly from child
1057 * processes to the compositor thread. It's associated with a
1058 * CompositorParent on the compositor thread. While it uses the
1059 * PCompositor protocol to manage these updates, it doesn't actually
1060 * drive compositing itself. For that it hands off work to the
1061 * CompositorParent it's associated with.
1062 */
1063 class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent,
1064 public ShadowLayersManager
1065 {
1066 friend class CompositorParent;
1067
1068 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent)
1069 public:
1070 CrossProcessCompositorParent(Transport* aTransport)
1071 : mTransport(aTransport)
1072 {}
1073
1074 // IToplevelProtocol::CloneToplevel()
1075 virtual IToplevelProtocol*
1076 CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
1077 base::ProcessHandle aPeerProcess,
1078 mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
1079
1080 virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
1081
1082 // FIXME/bug 774388: work out what shutdown protocol we need.
1083 virtual bool RecvWillStop() MOZ_OVERRIDE { return true; }
1084 virtual bool RecvStop() MOZ_OVERRIDE { return true; }
1085 virtual bool RecvPause() MOZ_OVERRIDE { return true; }
1086 virtual bool RecvResume() MOZ_OVERRIDE { return true; }
1087 virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE;
1088 virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
1089 SurfaceDescriptor* aOutSnapshot)
1090 { return true; }
1091 virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
1092 virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) { return true; }
1093 virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) MOZ_OVERRIDE { return true; }
1094 virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) MOZ_OVERRIDE { return true; }
1095
1096 virtual PLayerTransactionParent*
1097 AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
1098 const uint64_t& aId,
1099 TextureFactoryIdentifier* aTextureFactoryIdentifier,
1100 bool *aSuccess) MOZ_OVERRIDE;
1101
1102 virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
1103
1104 virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
1105 const TargetConfig& aTargetConfig,
1106 bool aIsFirstPaint,
1107 bool aScheduleComposite) MOZ_OVERRIDE;
1108 virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
1109 virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
1110 const TimeStamp& aTime) MOZ_OVERRIDE;
1111 virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
1112
1113 virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) MOZ_OVERRIDE;
1114
1115 private:
1116 // Private destructor, to discourage deletion outside of Release():
1117 virtual ~CrossProcessCompositorParent();
1118
1119 void DeferredDestroy();
1120
1121 // There can be many CPCPs, and IPDL-generated code doesn't hold a
1122 // reference to top-level actors. So we hold a reference to
1123 // ourself. This is released (deferred) in ActorDestroy().
1124 nsRefPtr<CrossProcessCompositorParent> mSelfRef;
1125 Transport* mTransport;
1126 };
1127
1128 static void
1129 OpenCompositor(CrossProcessCompositorParent* aCompositor,
1130 Transport* aTransport, ProcessHandle aHandle,
1131 MessageLoop* aIOLoop)
1132 {
1133 DebugOnly<bool> ok = aCompositor->Open(aTransport, aHandle, aIOLoop);
1134 MOZ_ASSERT(ok);
1135 }
1136
1137 /*static*/ PCompositorParent*
1138 CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess)
1139 {
1140 nsRefPtr<CrossProcessCompositorParent> cpcp =
1141 new CrossProcessCompositorParent(aTransport);
1142 ProcessHandle handle;
1143 if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
1144 // XXX need to kill |aOtherProcess|, it's boned
1145 return nullptr;
1146 }
1147 cpcp->mSelfRef = cpcp;
1148 CompositorLoop()->PostTask(
1149 FROM_HERE,
1150 NewRunnableFunction(OpenCompositor, cpcp.get(),
1151 aTransport, handle, XRE_GetIOMessageLoop()));
1152 // The return value is just compared to null for success checking,
1153 // we're not sharing a ref.
1154 return cpcp.get();
1155 }
1156
1157 IToplevelProtocol*
1158 CompositorParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
1159 base::ProcessHandle aPeerProcess,
1160 mozilla::ipc::ProtocolCloneContext* aCtx)
1161 {
1162 for (unsigned int i = 0; i < aFds.Length(); i++) {
1163 if (aFds[i].protocolId() == (unsigned)GetProtocolId()) {
1164 Transport* transport = OpenDescriptor(aFds[i].fd(),
1165 Transport::MODE_SERVER);
1166 PCompositorParent* compositor = Create(transport, base::GetProcId(aPeerProcess));
1167 compositor->CloneManagees(this, aCtx);
1168 compositor->IToplevelProtocol::SetTransport(transport);
1169 return compositor;
1170 }
1171 }
1172 return nullptr;
1173 }
1174
1175 static void
1176 UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig)
1177 {
1178 sIndirectLayerTrees[aId].mRoot = aRoot;
1179 sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
1180 }
1181
1182 /* static */ const CompositorParent::LayerTreeState*
1183 CompositorParent::GetIndirectShadowTree(uint64_t aId)
1184 {
1185 LayerTreeMap::const_iterator cit = sIndirectLayerTrees.find(aId);
1186 if (sIndirectLayerTrees.end() == cit) {
1187 return nullptr;
1188 }
1189 return &cit->second;
1190 }
1191
1192 static void
1193 RemoveIndirectTree(uint64_t aId)
1194 {
1195 sIndirectLayerTrees.erase(aId);
1196 }
1197
1198 void
1199 CrossProcessCompositorParent::ActorDestroy(ActorDestroyReason aWhy)
1200 {
1201 MessageLoop::current()->PostTask(
1202 FROM_HERE,
1203 NewRunnableMethod(this, &CrossProcessCompositorParent::DeferredDestroy));
1204 }
1205
1206 PLayerTransactionParent*
1207 CrossProcessCompositorParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>&,
1208 const uint64_t& aId,
1209 TextureFactoryIdentifier* aTextureFactoryIdentifier,
1210 bool *aSuccess)
1211 {
1212 MOZ_ASSERT(aId != 0);
1213
1214 if (sIndirectLayerTrees[aId].mLayerManager) {
1215 sIndirectLayerTrees[aId].mCrossProcessParent = this;
1216 LayerManagerComposite* lm = sIndirectLayerTrees[aId].mLayerManager;
1217 *aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier();
1218 *aSuccess = true;
1219 LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId);
1220 p->AddIPDLReference();
1221 return p;
1222 }
1223
1224 NS_WARNING("Created child without a matching parent?");
1225 // XXX: should be false, but that causes us to fail some tests on Mac w/ OMTC.
1226 // Bug 900745. change *aSuccess to false to see test failures.
1227 *aSuccess = true;
1228 LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId);
1229 p->AddIPDLReference();
1230 return p;
1231 }
1232
1233 bool
1234 CrossProcessCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
1235 {
1236 LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers);
1237 RemoveIndirectTree(slp->GetId());
1238 static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference();
1239 return true;
1240 }
1241
1242 bool
1243 CrossProcessCompositorParent::RecvNotifyChildCreated(const uint64_t& child)
1244 {
1245 sIndirectLayerTrees[child].mParent->NotifyChildCreated(child);
1246 return true;
1247 }
1248
1249 void
1250 CrossProcessCompositorParent::ShadowLayersUpdated(
1251 LayerTransactionParent* aLayerTree,
1252 const TargetConfig& aTargetConfig,
1253 bool aIsFirstPaint,
1254 bool aScheduleComposite)
1255 {
1256 uint64_t id = aLayerTree->GetId();
1257 MOZ_ASSERT(id != 0);
1258 Layer* shadowRoot = aLayerTree->GetRoot();
1259 if (shadowRoot) {
1260 SetShadowProperties(shadowRoot);
1261 }
1262 UpdateIndirectTree(id, shadowRoot, aTargetConfig);
1263
1264 sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite);
1265 }
1266
1267 void
1268 CrossProcessCompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
1269 {
1270 uint64_t id = aLayerTree->GetId();
1271 MOZ_ASSERT(id != 0);
1272 sIndirectLayerTrees[id].mParent->ForceComposite(aLayerTree);
1273 }
1274
1275 bool
1276 CrossProcessCompositorParent::SetTestSampleTime(
1277 LayerTransactionParent* aLayerTree, const TimeStamp& aTime)
1278 {
1279 uint64_t id = aLayerTree->GetId();
1280 MOZ_ASSERT(id != 0);
1281 return sIndirectLayerTrees[id].mParent->SetTestSampleTime(aLayerTree, aTime);
1282 }
1283
1284 void
1285 CrossProcessCompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
1286 {
1287 uint64_t id = aLayerTree->GetId();
1288 MOZ_ASSERT(id != 0);
1289 sIndirectLayerTrees[id].mParent->LeaveTestMode(aLayerTree);
1290 }
1291
1292 AsyncCompositionManager*
1293 CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLayerTree)
1294 {
1295 uint64_t id = aLayerTree->GetId();
1296 return sIndirectLayerTrees[id].mParent->GetCompositionManager(aLayerTree);
1297 }
1298
1299 void
1300 CrossProcessCompositorParent::DeferredDestroy()
1301 {
1302 CrossProcessCompositorParent* self;
1303 mSelfRef.forget(&self);
1304
1305 nsCOMPtr<nsIRunnable> runnable =
1306 NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release);
1307 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
1308 }
1309
1310 CrossProcessCompositorParent::~CrossProcessCompositorParent()
1311 {
1312 XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
1313 new DeleteTask<Transport>(mTransport));
1314 }
1315
1316 IToplevelProtocol*
1317 CrossProcessCompositorParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
1318 base::ProcessHandle aPeerProcess,
1319 mozilla::ipc::ProtocolCloneContext* aCtx)
1320 {
1321 for (unsigned int i = 0; i < aFds.Length(); i++) {
1322 if (aFds[i].protocolId() == (unsigned)GetProtocolId()) {
1323 Transport* transport = OpenDescriptor(aFds[i].fd(),
1324 Transport::MODE_SERVER);
1325 PCompositorParent* compositor =
1326 CompositorParent::Create(transport, base::GetProcId(aPeerProcess));
1327 compositor->CloneManagees(this, aCtx);
1328 compositor->IToplevelProtocol::SetTransport(transport);
1329 return compositor;
1330 }
1331 }
1332 return nullptr;
1333 }
1334
1335 } // namespace layers
1336 } // namespace mozilla

mercurial