gfx/layers/ipc/CompositorParent.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial