1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/ipc/CompositorParent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1336 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=2 et tw=80 : */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "CompositorParent.h" 1.11 +#include <stdio.h> // for fprintf, stdout 1.12 +#include <stdint.h> // for uint64_t 1.13 +#include <map> // for _Rb_tree_iterator, etc 1.14 +#include <utility> // for pair 1.15 +#include "LayerTransactionParent.h" // for LayerTransactionParent 1.16 +#include "RenderTrace.h" // for RenderTraceLayers 1.17 +#include "base/message_loop.h" // for MessageLoop 1.18 +#include "base/process.h" // for ProcessHandle 1.19 +#include "base/process_util.h" // for OpenProcessHandle 1.20 +#include "base/task.h" // for CancelableTask, etc 1.21 +#include "base/thread.h" // for Thread 1.22 +#include "base/tracked.h" // for FROM_HERE 1.23 +#include "gfxContext.h" // for gfxContext 1.24 +#include "gfxPlatform.h" // for gfxPlatform 1.25 +#include "gfxPrefs.h" // for gfxPrefs 1.26 +#include "ipc/ShadowLayersManager.h" // for ShadowLayersManager 1.27 +#include "mozilla/AutoRestore.h" // for AutoRestore 1.28 +#include "mozilla/DebugOnly.h" // for DebugOnly 1.29 +#include "mozilla/gfx/2D.h" // for DrawTarget 1.30 +#include "mozilla/gfx/Point.h" // for IntSize 1.31 +#include "mozilla/ipc/Transport.h" // for Transport 1.32 +#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager 1.33 +#include "mozilla/layers/AsyncCompositionManager.h" 1.34 +#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor 1.35 +#include "mozilla/layers/Compositor.h" // for Compositor 1.36 +#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL 1.37 +#include "mozilla/layers/CompositorTypes.h" 1.38 +#include "mozilla/layers/LayerManagerComposite.h" 1.39 +#include "mozilla/layers/LayersTypes.h" 1.40 +#include "mozilla/layers/PLayerTransactionParent.h" 1.41 +#include "mozilla/mozalloc.h" // for operator new, etc 1.42 +#include "nsCOMPtr.h" // for already_AddRefed 1.43 +#include "nsDebug.h" // for NS_ABORT_IF_FALSE, etc 1.44 +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc 1.45 +#include "nsIWidget.h" // for nsIWidget 1.46 +#include "nsRect.h" // for nsIntRect 1.47 +#include "nsTArray.h" // for nsTArray 1.48 +#include "nsThreadUtils.h" // for NS_IsMainThread 1.49 +#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop 1.50 +#ifdef XP_WIN 1.51 +#include "mozilla/layers/CompositorD3D11.h" 1.52 +#include "mozilla/layers/CompositorD3D9.h" 1.53 +#endif 1.54 +#include "GeckoProfiler.h" 1.55 +#include "mozilla/ipc/ProtocolTypes.h" 1.56 +#include "mozilla/unused.h" 1.57 + 1.58 +using namespace base; 1.59 +using namespace mozilla; 1.60 +using namespace mozilla::ipc; 1.61 +using namespace mozilla::gfx; 1.62 +using namespace std; 1.63 + 1.64 +namespace mozilla { 1.65 +namespace layers { 1.66 + 1.67 +CompositorParent::LayerTreeState::LayerTreeState() 1.68 + : mParent(nullptr) 1.69 + , mLayerManager(nullptr) 1.70 + , mCrossProcessParent(nullptr) 1.71 +{ 1.72 +} 1.73 + 1.74 +typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap; 1.75 +static LayerTreeMap sIndirectLayerTrees; 1.76 + 1.77 +// FIXME/bug 774386: we're assuming that there's only one 1.78 +// CompositorParent, but that's not always true. This assumption only 1.79 +// affects CrossProcessCompositorParent below. 1.80 +static Thread* sCompositorThread = nullptr; 1.81 +// manual reference count of the compositor thread. 1.82 +static int sCompositorThreadRefCount = 0; 1.83 +static MessageLoop* sMainLoop = nullptr; 1.84 +// When ContentParent::StartUp() is called, we use the Thread global. 1.85 +// When StartUpWithExistingThread() is used, we have to use the two 1.86 +// duplicated globals, because there's no API to make a Thread from an 1.87 +// existing thread. 1.88 +static PlatformThreadId sCompositorThreadID = 0; 1.89 +static MessageLoop* sCompositorLoop = nullptr; 1.90 + 1.91 +// See ImageBridgeChild.cpp 1.92 +void ReleaseImageBridgeParentSingleton(); 1.93 + 1.94 +static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) 1.95 +{ 1.96 + aNowReadyToDie->Release(); 1.97 +} 1.98 + 1.99 +static void DeleteCompositorThread() 1.100 +{ 1.101 + if (NS_IsMainThread()){ 1.102 + ReleaseImageBridgeParentSingleton(); 1.103 + delete sCompositorThread; 1.104 + sCompositorThread = nullptr; 1.105 + sCompositorLoop = nullptr; 1.106 + sCompositorThreadID = 0; 1.107 + } else { 1.108 + sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread)); 1.109 + } 1.110 +} 1.111 + 1.112 +static void ReleaseCompositorThread() 1.113 +{ 1.114 + if(--sCompositorThreadRefCount == 0) { 1.115 + DeleteCompositorThread(); 1.116 + } 1.117 +} 1.118 + 1.119 +void 1.120 +CompositorParent::StartUpWithExistingThread(MessageLoop* aMsgLoop, 1.121 + PlatformThreadId aThreadID) 1.122 +{ 1.123 + MOZ_ASSERT(!sCompositorThread); 1.124 + CreateCompositorMap(); 1.125 + sCompositorLoop = aMsgLoop; 1.126 + sCompositorThreadID = aThreadID; 1.127 + sMainLoop = MessageLoop::current(); 1.128 + sCompositorThreadRefCount = 1; 1.129 +} 1.130 + 1.131 +void CompositorParent::StartUp() 1.132 +{ 1.133 + // Check if compositor started already with StartUpWithExistingThread 1.134 + if (sCompositorThreadID) { 1.135 + return; 1.136 + } 1.137 + MOZ_ASSERT(!sCompositorLoop); 1.138 + CreateCompositorMap(); 1.139 + CreateThread(); 1.140 + sMainLoop = MessageLoop::current(); 1.141 +} 1.142 + 1.143 +void CompositorParent::ShutDown() 1.144 +{ 1.145 + DestroyThread(); 1.146 + DestroyCompositorMap(); 1.147 +} 1.148 + 1.149 +bool CompositorParent::CreateThread() 1.150 +{ 1.151 + NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); 1.152 + if (sCompositorThread || sCompositorLoop) { 1.153 + return true; 1.154 + } 1.155 + sCompositorThreadRefCount = 1; 1.156 + sCompositorThread = new Thread("Compositor"); 1.157 + 1.158 + Thread::Options options; 1.159 + /* Timeout values are powers-of-two to enable us get better data. 1.160 + 128ms is chosen for transient hangs because 8Hz should be the minimally 1.161 + acceptable goal for Compositor responsiveness (normal goal is 60Hz). */ 1.162 + options.transient_hang_timeout = 128; // milliseconds 1.163 + /* 8192ms is chosen for permanent hangs because it's several seconds longer 1.164 + than the default hang timeout on major platforms (about 5 seconds). */ 1.165 + options.permanent_hang_timeout = 8192; // milliseconds 1.166 + 1.167 + if (!sCompositorThread->StartWithOptions(options)) { 1.168 + delete sCompositorThread; 1.169 + sCompositorThread = nullptr; 1.170 + return false; 1.171 + } 1.172 + return true; 1.173 +} 1.174 + 1.175 +void CompositorParent::DestroyThread() 1.176 +{ 1.177 + NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); 1.178 + ReleaseCompositorThread(); 1.179 +} 1.180 + 1.181 +MessageLoop* CompositorParent::CompositorLoop() 1.182 +{ 1.183 + return sCompositorThread ? sCompositorThread->message_loop() : sCompositorLoop; 1.184 +} 1.185 + 1.186 +CompositorParent::CompositorParent(nsIWidget* aWidget, 1.187 + bool aUseExternalSurfaceSize, 1.188 + int aSurfaceWidth, int aSurfaceHeight) 1.189 + : mWidget(aWidget) 1.190 + , mCurrentCompositeTask(nullptr) 1.191 + , mIsTesting(false) 1.192 + , mPaused(false) 1.193 + , mUseExternalSurfaceSize(aUseExternalSurfaceSize) 1.194 + , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight) 1.195 + , mPauseCompositionMonitor("PauseCompositionMonitor") 1.196 + , mResumeCompositionMonitor("ResumeCompositionMonitor") 1.197 + , mOverrideComposeReadiness(false) 1.198 + , mForceCompositionTask(nullptr) 1.199 + , mWantDidCompositeEvent(false) 1.200 +{ 1.201 + NS_ABORT_IF_FALSE(sCompositorThread != nullptr || sCompositorThreadID, 1.202 + "The compositor thread must be Initialized before instanciating a COmpositorParent."); 1.203 + MOZ_COUNT_CTOR(CompositorParent); 1.204 + mCompositorID = 0; 1.205 + // FIXME: This holds on the the fact that right now the only thing that 1.206 + // can destroy this instance is initialized on the compositor thread after 1.207 + // this task has been processed. 1.208 + CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor, 1.209 + this, &mCompositorID)); 1.210 + 1.211 + mRootLayerTreeID = AllocateLayerTreeId(); 1.212 + sIndirectLayerTrees[mRootLayerTreeID].mParent = this; 1.213 + 1.214 + mApzcTreeManager = new APZCTreeManager(); 1.215 + ++sCompositorThreadRefCount; 1.216 +} 1.217 + 1.218 +PlatformThreadId 1.219 +CompositorParent::CompositorThreadID() 1.220 +{ 1.221 + return sCompositorThread ? sCompositorThread->thread_id() : sCompositorThreadID; 1.222 +} 1.223 + 1.224 +bool 1.225 +CompositorParent::IsInCompositorThread() 1.226 +{ 1.227 + return CompositorThreadID() == PlatformThread::CurrentId(); 1.228 +} 1.229 + 1.230 +uint64_t 1.231 +CompositorParent::RootLayerTreeId() 1.232 +{ 1.233 + return mRootLayerTreeID; 1.234 +} 1.235 + 1.236 +CompositorParent::~CompositorParent() 1.237 +{ 1.238 + MOZ_COUNT_DTOR(CompositorParent); 1.239 + 1.240 + ReleaseCompositorThread(); 1.241 +} 1.242 + 1.243 +void 1.244 +CompositorParent::Destroy() 1.245 +{ 1.246 + NS_ABORT_IF_FALSE(ManagedPLayerTransactionParent().Length() == 0, 1.247 + "CompositorParent destroyed before managed PLayerTransactionParent"); 1.248 + 1.249 + // Ensure that the layer manager is destructed on the compositor thread. 1.250 + mLayerManager = nullptr; 1.251 + mCompositor = nullptr; 1.252 + mCompositionManager = nullptr; 1.253 + mApzcTreeManager->ClearTree(); 1.254 + mApzcTreeManager = nullptr; 1.255 + sIndirectLayerTrees.erase(mRootLayerTreeID); 1.256 +} 1.257 + 1.258 +void 1.259 +CompositorParent::ForceIsFirstPaint() 1.260 +{ 1.261 + mCompositionManager->ForceIsFirstPaint(); 1.262 +} 1.263 + 1.264 +bool 1.265 +CompositorParent::RecvWillStop() 1.266 +{ 1.267 + mPaused = true; 1.268 + RemoveCompositor(mCompositorID); 1.269 + 1.270 + // Ensure that the layer manager is destroyed before CompositorChild. 1.271 + if (mLayerManager) { 1.272 + for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin(); 1.273 + it != sIndirectLayerTrees.end(); it++) 1.274 + { 1.275 + LayerTreeState* lts = &it->second; 1.276 + if (lts->mParent == this) { 1.277 + mLayerManager->ClearCachedResources(lts->mRoot); 1.278 + lts->mLayerManager = nullptr; 1.279 + } 1.280 + } 1.281 + mLayerManager->Destroy(); 1.282 + mLayerManager = nullptr; 1.283 + mCompositor = nullptr; 1.284 + mCompositionManager = nullptr; 1.285 + } 1.286 + 1.287 + return true; 1.288 +} 1.289 + 1.290 +bool 1.291 +CompositorParent::RecvStop() 1.292 +{ 1.293 + Destroy(); 1.294 + // There are chances that the ref count reaches zero on the main thread shortly 1.295 + // after this function returns while some ipdl code still needs to run on 1.296 + // this thread. 1.297 + // We must keep the compositor parent alive untill the code handling message 1.298 + // reception is finished on this thread. 1.299 + this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release 1.300 + CompositorLoop()->PostTask(FROM_HERE, 1.301 + NewRunnableFunction(&DeferredDeleteCompositorParent, 1.302 + this)); 1.303 + return true; 1.304 +} 1.305 + 1.306 +bool 1.307 +CompositorParent::RecvPause() 1.308 +{ 1.309 + PauseComposition(); 1.310 + return true; 1.311 +} 1.312 + 1.313 +bool 1.314 +CompositorParent::RecvResume() 1.315 +{ 1.316 + ResumeComposition(); 1.317 + return true; 1.318 +} 1.319 + 1.320 +bool 1.321 +CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot, 1.322 + SurfaceDescriptor* aOutSnapshot) 1.323 +{ 1.324 + RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO); 1.325 + ForceComposeToTarget(target); 1.326 + *aOutSnapshot = aInSnapshot; 1.327 + return true; 1.328 +} 1.329 + 1.330 +bool 1.331 +CompositorParent::RecvFlushRendering() 1.332 +{ 1.333 + // If we're waiting to do a composite, then cancel it 1.334 + // and do it immediately instead. 1.335 + if (mCurrentCompositeTask) { 1.336 + CancelCurrentCompositeTask(); 1.337 + ForceComposeToTarget(nullptr); 1.338 + } 1.339 + return true; 1.340 +} 1.341 + 1.342 +bool 1.343 +CompositorParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) 1.344 +{ 1.345 + if (mLayerManager) { 1.346 + mLayerManager->AddInvalidRegion(aRegion); 1.347 + } 1.348 + return true; 1.349 +} 1.350 + 1.351 +bool 1.352 +CompositorParent::RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) 1.353 +{ 1.354 + if (mLayerManager) { 1.355 + *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize); 1.356 + } else { 1.357 + *aOutStartIndex = 0; 1.358 + } 1.359 + return true; 1.360 +} 1.361 + 1.362 +bool 1.363 +CompositorParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex, 1.364 + InfallibleTArray<float>* intervals) 1.365 +{ 1.366 + if (mLayerManager) { 1.367 + mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals); 1.368 + } 1.369 + return true; 1.370 +} 1.371 + 1.372 +void 1.373 +CompositorParent::ActorDestroy(ActorDestroyReason why) 1.374 +{ 1.375 + CancelCurrentCompositeTask(); 1.376 + if (mForceCompositionTask) { 1.377 + mForceCompositionTask->Cancel(); 1.378 + mForceCompositionTask = nullptr; 1.379 + } 1.380 + mPaused = true; 1.381 + RemoveCompositor(mCompositorID); 1.382 + 1.383 + if (mLayerManager) { 1.384 + mLayerManager->Destroy(); 1.385 + mLayerManager = nullptr; 1.386 + sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr; 1.387 + mCompositionManager = nullptr; 1.388 + mCompositor = nullptr; 1.389 + } 1.390 +} 1.391 + 1.392 + 1.393 +void 1.394 +CompositorParent::ScheduleRenderOnCompositorThread() 1.395 +{ 1.396 + CancelableTask *renderTask = NewRunnableMethod(this, &CompositorParent::ScheduleComposition); 1.397 + CompositorLoop()->PostTask(FROM_HERE, renderTask); 1.398 +} 1.399 + 1.400 +void 1.401 +CompositorParent::PauseComposition() 1.402 +{ 1.403 + NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(), 1.404 + "PauseComposition() can only be called on the compositor thread"); 1.405 + 1.406 + MonitorAutoLock lock(mPauseCompositionMonitor); 1.407 + 1.408 + if (!mPaused) { 1.409 + mPaused = true; 1.410 + 1.411 + mCompositor->Pause(); 1.412 + } 1.413 + 1.414 + // if anyone's waiting to make sure that composition really got paused, tell them 1.415 + lock.NotifyAll(); 1.416 +} 1.417 + 1.418 +void 1.419 +CompositorParent::ResumeComposition() 1.420 +{ 1.421 + NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(), 1.422 + "ResumeComposition() can only be called on the compositor thread"); 1.423 + 1.424 + MonitorAutoLock lock(mResumeCompositionMonitor); 1.425 + 1.426 + if (!mCompositor->Resume()) { 1.427 +#ifdef MOZ_WIDGET_ANDROID 1.428 + // We can't get a surface. This could be because the activity changed between 1.429 + // the time resume was scheduled and now. 1.430 + __android_log_print(ANDROID_LOG_INFO, "CompositorParent", "Unable to renew compositor surface; remaining in paused state"); 1.431 +#endif 1.432 + lock.NotifyAll(); 1.433 + return; 1.434 + } 1.435 + 1.436 + mPaused = false; 1.437 + 1.438 + Composite(); 1.439 + 1.440 + // if anyone's waiting to make sure that composition really got resumed, tell them 1.441 + lock.NotifyAll(); 1.442 +} 1.443 + 1.444 +void 1.445 +CompositorParent::ForceComposition() 1.446 +{ 1.447 + // Cancel the orientation changed state to force composition 1.448 + mForceCompositionTask = nullptr; 1.449 + ScheduleRenderOnCompositorThread(); 1.450 +} 1.451 + 1.452 +void 1.453 +CompositorParent::CancelCurrentCompositeTask() 1.454 +{ 1.455 + if (mCurrentCompositeTask) { 1.456 + mCurrentCompositeTask->Cancel(); 1.457 + mCurrentCompositeTask = nullptr; 1.458 + } 1.459 +} 1.460 + 1.461 +void 1.462 +CompositorParent::SetEGLSurfaceSize(int width, int height) 1.463 +{ 1.464 + NS_ASSERTION(mUseExternalSurfaceSize, "Compositor created without UseExternalSurfaceSize provided"); 1.465 + mEGLSurfaceSize.SizeTo(width, height); 1.466 + if (mCompositor) { 1.467 + mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height)); 1.468 + } 1.469 +} 1.470 + 1.471 +void 1.472 +CompositorParent::ResumeCompositionAndResize(int width, int height) 1.473 +{ 1.474 + SetEGLSurfaceSize(width, height); 1.475 + ResumeComposition(); 1.476 +} 1.477 + 1.478 +/* 1.479 + * This will execute a pause synchronously, waiting to make sure that the compositor 1.480 + * really is paused. 1.481 + */ 1.482 +void 1.483 +CompositorParent::SchedulePauseOnCompositorThread() 1.484 +{ 1.485 + MonitorAutoLock lock(mPauseCompositionMonitor); 1.486 + 1.487 + CancelableTask *pauseTask = NewRunnableMethod(this, 1.488 + &CompositorParent::PauseComposition); 1.489 + CompositorLoop()->PostTask(FROM_HERE, pauseTask); 1.490 + 1.491 + // Wait until the pause has actually been processed by the compositor thread 1.492 + lock.Wait(); 1.493 +} 1.494 + 1.495 +bool 1.496 +CompositorParent::ScheduleResumeOnCompositorThread(int width, int height) 1.497 +{ 1.498 + MonitorAutoLock lock(mResumeCompositionMonitor); 1.499 + 1.500 + CancelableTask *resumeTask = 1.501 + NewRunnableMethod(this, &CompositorParent::ResumeCompositionAndResize, width, height); 1.502 + CompositorLoop()->PostTask(FROM_HERE, resumeTask); 1.503 + 1.504 + // Wait until the resume has actually been processed by the compositor thread 1.505 + lock.Wait(); 1.506 + 1.507 + return !mPaused; 1.508 +} 1.509 + 1.510 +void 1.511 +CompositorParent::ScheduleTask(CancelableTask* task, int time) 1.512 +{ 1.513 + if (time == 0) { 1.514 + MessageLoop::current()->PostTask(FROM_HERE, task); 1.515 + } else { 1.516 + MessageLoop::current()->PostDelayedTask(FROM_HERE, task, time); 1.517 + } 1.518 +} 1.519 + 1.520 +void 1.521 +CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite) 1.522 +{ 1.523 + if (mApzcTreeManager && 1.524 + mLayerManager && 1.525 + mLayerManager->GetRoot()) { 1.526 + AutoResolveRefLayers resolve(mCompositionManager); 1.527 + mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId); 1.528 + 1.529 + mLayerManager->NotifyShadowTreeTransaction(); 1.530 + } 1.531 + if (aScheduleComposite) { 1.532 + ScheduleComposition(); 1.533 + } 1.534 + 1.535 + mWantDidCompositeEvent = true; 1.536 +} 1.537 + 1.538 +// Used when layout.frame_rate is -1. Needs to be kept in sync with 1.539 +// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp. 1.540 +static const int32_t kDefaultFrameRate = 60; 1.541 + 1.542 +static int32_t 1.543 +CalculateCompositionFrameRate() 1.544 +{ 1.545 + int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate(); 1.546 + if (compositionFrameRatePref < 0) { 1.547 + // Use the same frame rate for composition as for layout. 1.548 + int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate(); 1.549 + if (layoutFrameRatePref < 0) { 1.550 + // TODO: The main thread frame scheduling code consults the actual 1.551 + // monitor refresh rate in this case. We should do the same. 1.552 + return kDefaultFrameRate; 1.553 + } 1.554 + return layoutFrameRatePref; 1.555 + } 1.556 + return compositionFrameRatePref; 1.557 +} 1.558 + 1.559 +void 1.560 +CompositorParent::ScheduleComposition() 1.561 +{ 1.562 + if (mCurrentCompositeTask || mPaused) { 1.563 + return; 1.564 + } 1.565 + 1.566 + bool initialComposition = mLastCompose.IsNull(); 1.567 + TimeDuration delta; 1.568 + if (!initialComposition) 1.569 + delta = TimeStamp::Now() - mLastCompose; 1.570 + 1.571 + int32_t rate = CalculateCompositionFrameRate(); 1.572 + 1.573 + // If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay. 1.574 + TimeDuration minFrameDelta = TimeDuration::FromMilliseconds( 1.575 + rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate)); 1.576 + 1.577 + 1.578 + mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::Composite); 1.579 + 1.580 + if (!initialComposition && delta < minFrameDelta) { 1.581 + TimeDuration delay = minFrameDelta - delta; 1.582 +#ifdef COMPOSITOR_PERFORMANCE_WARNING 1.583 + mExpectedComposeStartTime = TimeStamp::Now() + delay; 1.584 +#endif 1.585 + ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds()); 1.586 + } else { 1.587 +#ifdef COMPOSITOR_PERFORMANCE_WARNING 1.588 + mExpectedComposeStartTime = TimeStamp::Now(); 1.589 +#endif 1.590 + ScheduleTask(mCurrentCompositeTask, 0); 1.591 + } 1.592 +} 1.593 + 1.594 +void 1.595 +CompositorParent::Composite() 1.596 +{ 1.597 + CompositeToTarget(nullptr); 1.598 +} 1.599 + 1.600 +void 1.601 +CompositorParent::CompositeToTarget(DrawTarget* aTarget) 1.602 +{ 1.603 + profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START); 1.604 + PROFILER_LABEL("CompositorParent", "Composite"); 1.605 + NS_ABORT_IF_FALSE(CompositorThreadID() == PlatformThread::CurrentId(), 1.606 + "Composite can only be called on the compositor thread"); 1.607 + 1.608 +#ifdef COMPOSITOR_PERFORMANCE_WARNING 1.609 + TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime; 1.610 + if (scheduleDelta > TimeDuration::FromMilliseconds(2) || 1.611 + scheduleDelta < TimeDuration::FromMilliseconds(-2)) { 1.612 + printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n", 1.613 + scheduleDelta.ToMilliseconds()); 1.614 + } 1.615 +#endif 1.616 + 1.617 + if (mCurrentCompositeTask) { 1.618 + mCurrentCompositeTask->Cancel(); 1.619 + mCurrentCompositeTask = nullptr; 1.620 + } 1.621 + 1.622 + mLastCompose = TimeStamp::Now(); 1.623 + 1.624 + if (!CanComposite()) { 1.625 + return; 1.626 + } 1.627 + 1.628 + AutoResolveRefLayers resolve(mCompositionManager); 1.629 + 1.630 + if (aTarget) { 1.631 + mLayerManager->BeginTransactionWithDrawTarget(aTarget); 1.632 + } else { 1.633 + mLayerManager->BeginTransaction(); 1.634 + } 1.635 + 1.636 + if (mForceCompositionTask && !mOverrideComposeReadiness) { 1.637 + if (mCompositionManager->ReadyForCompose()) { 1.638 + mForceCompositionTask->Cancel(); 1.639 + mForceCompositionTask = nullptr; 1.640 + } else { 1.641 + return; 1.642 + } 1.643 + } 1.644 + 1.645 + TimeStamp time = mIsTesting ? mTestTime : mLastCompose; 1.646 + bool requestNextFrame = mCompositionManager->TransformShadowTree(time); 1.647 + if (requestNextFrame) { 1.648 + ScheduleComposition(); 1.649 + } 1.650 + 1.651 + RenderTraceLayers(mLayerManager->GetRoot(), "0000"); 1.652 + 1.653 + mCompositionManager->ComputeRotation(); 1.654 + 1.655 +#ifdef MOZ_DUMP_PAINTING 1.656 + static bool gDumpCompositorTree = false; 1.657 + if (gDumpCompositorTree) { 1.658 + printf_stderr("Painting --- compositing layer tree:\n"); 1.659 + mLayerManager->Dump(); 1.660 + } 1.661 +#endif 1.662 + mLayerManager->SetDebugOverlayWantsNextFrame(false); 1.663 + mLayerManager->EndEmptyTransaction(); 1.664 + 1.665 + if (!aTarget && mWantDidCompositeEvent) { 1.666 + DidComposite(); 1.667 + mWantDidCompositeEvent = false; 1.668 + } 1.669 + 1.670 + if (mLayerManager->DebugOverlayWantsNextFrame()) { 1.671 + ScheduleComposition(); 1.672 + } 1.673 + 1.674 +#ifdef COMPOSITOR_PERFORMANCE_WARNING 1.675 + TimeDuration executionTime = TimeStamp::Now() - mLastCompose; 1.676 + TimeDuration frameBudget = TimeDuration::FromMilliseconds(15); 1.677 + int32_t frameRate = CalculateCompositionFrameRate(); 1.678 + if (frameRate > 0) { 1.679 + frameBudget = TimeDuration::FromSeconds(1.0 / frameRate); 1.680 + } 1.681 + if (executionTime > frameBudget) { 1.682 + printf_stderr("Compositor: Composite execution took %4.1f ms\n", 1.683 + executionTime.ToMilliseconds()); 1.684 + } 1.685 +#endif 1.686 + 1.687 + // 0 -> Full-tilt composite 1.688 + if (gfxPrefs::LayersCompositionFrameRate() == 0 1.689 + || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DIAGNOSTIC_FLASH_BORDERS) { 1.690 + // Special full-tilt composite mode for performance testing 1.691 + ScheduleComposition(); 1.692 + } 1.693 + 1.694 + profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END); 1.695 +} 1.696 + 1.697 +void 1.698 +CompositorParent::DidComposite() 1.699 +{ 1.700 + unused << SendDidComposite(0); 1.701 + 1.702 + for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin(); 1.703 + it != sIndirectLayerTrees.end(); it++) { 1.704 + LayerTreeState* lts = &it->second; 1.705 + if (lts->mParent == this && lts->mCrossProcessParent) { 1.706 + unused << lts->mCrossProcessParent->SendDidComposite(it->first); 1.707 + } 1.708 + } 1.709 +} 1.710 + 1.711 +void 1.712 +CompositorParent::ForceComposeToTarget(DrawTarget* aTarget) 1.713 +{ 1.714 + PROFILER_LABEL("CompositorParent", "ForceComposeToTarget"); 1.715 + AutoRestore<bool> override(mOverrideComposeReadiness); 1.716 + mOverrideComposeReadiness = true; 1.717 + 1.718 + CompositeToTarget(aTarget); 1.719 +} 1.720 + 1.721 +bool 1.722 +CompositorParent::CanComposite() 1.723 +{ 1.724 + return !(mPaused || !mLayerManager || !mLayerManager->GetRoot()); 1.725 +} 1.726 + 1.727 +// Go down the composite layer tree, setting properties to match their 1.728 +// content-side counterparts. 1.729 +static void 1.730 +SetShadowProperties(Layer* aLayer) 1.731 +{ 1.732 + // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. 1.733 + LayerComposite* layerComposite = aLayer->AsLayerComposite(); 1.734 + // Set the layerComposite's base transform to the layer's base transform. 1.735 + layerComposite->SetShadowTransform(aLayer->GetBaseTransform()); 1.736 + layerComposite->SetShadowTransformSetByAnimation(false); 1.737 + layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); 1.738 + layerComposite->SetShadowClipRect(aLayer->GetClipRect()); 1.739 + layerComposite->SetShadowOpacity(aLayer->GetOpacity()); 1.740 + 1.741 + for (Layer* child = aLayer->GetFirstChild(); 1.742 + child; child = child->GetNextSibling()) { 1.743 + SetShadowProperties(child); 1.744 + } 1.745 +} 1.746 + 1.747 +void 1.748 +CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, 1.749 + const TargetConfig& aTargetConfig, 1.750 + bool aIsFirstPaint, 1.751 + bool aScheduleComposite) 1.752 +{ 1.753 + if (!aIsFirstPaint && 1.754 + !mCompositionManager->IsFirstPaint() && 1.755 + mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) { 1.756 + if (mForceCompositionTask != nullptr) { 1.757 + mForceCompositionTask->Cancel(); 1.758 + } 1.759 + mForceCompositionTask = NewRunnableMethod(this, &CompositorParent::ForceComposition); 1.760 + ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis()); 1.761 + } 1.762 + 1.763 + // Instruct the LayerManager to update its render bounds now. Since all the orientation 1.764 + // change, dimension change would be done at the stage, update the size here is free of 1.765 + // race condition. 1.766 + mLayerManager->UpdateRenderBounds(aTargetConfig.clientBounds()); 1.767 + mLayerManager->SetRegionToClear(aTargetConfig.clearRegion()); 1.768 + 1.769 + mCompositionManager->Updated(aIsFirstPaint, aTargetConfig); 1.770 + Layer* root = aLayerTree->GetRoot(); 1.771 + mLayerManager->SetRoot(root); 1.772 + 1.773 + if (mApzcTreeManager) { 1.774 + AutoResolveRefLayers resolve(mCompositionManager); 1.775 + mApzcTreeManager->UpdatePanZoomControllerTree(this, root, aIsFirstPaint, mRootLayerTreeID); 1.776 + } 1.777 + 1.778 + if (root) { 1.779 + SetShadowProperties(root); 1.780 + } 1.781 + if (aScheduleComposite) { 1.782 + ScheduleComposition(); 1.783 + // When testing we synchronously update the shadow tree with the animated 1.784 + // values to avoid race conditions when calling GetAnimationTransform etc. 1.785 + // (since the above SetShadowProperties will remove animation effects). 1.786 + // However, we only do this update when a composite operation is already 1.787 + // scheduled in order to better match the behavior under regular sampling 1.788 + // conditions. 1.789 + if (mIsTesting && root && mCurrentCompositeTask) { 1.790 + AutoResolveRefLayers resolve(mCompositionManager); 1.791 + bool requestNextFrame = 1.792 + mCompositionManager->TransformShadowTree(mTestTime); 1.793 + if (!requestNextFrame) { 1.794 + CancelCurrentCompositeTask(); 1.795 + } 1.796 + } 1.797 + } 1.798 + mLayerManager->NotifyShadowTreeTransaction(); 1.799 + mWantDidCompositeEvent = true; 1.800 +} 1.801 + 1.802 +void 1.803 +CompositorParent::ForceComposite(LayerTransactionParent* aLayerTree) 1.804 +{ 1.805 + ScheduleComposition(); 1.806 +} 1.807 + 1.808 +bool 1.809 +CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree, 1.810 + const TimeStamp& aTime) 1.811 +{ 1.812 + if (aTime.IsNull()) { 1.813 + return false; 1.814 + } 1.815 + 1.816 + mIsTesting = true; 1.817 + mTestTime = aTime; 1.818 + 1.819 + // Update but only if we were already scheduled to animate 1.820 + if (mCompositionManager && mCurrentCompositeTask) { 1.821 + AutoResolveRefLayers resolve(mCompositionManager); 1.822 + bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime); 1.823 + if (!requestNextFrame) { 1.824 + CancelCurrentCompositeTask(); 1.825 + } 1.826 + } 1.827 + 1.828 + return true; 1.829 +} 1.830 + 1.831 +void 1.832 +CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree) 1.833 +{ 1.834 + mIsTesting = false; 1.835 +} 1.836 + 1.837 +void 1.838 +CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints) 1.839 +{ 1.840 + NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager"); 1.841 + NS_ASSERTION(!mCompositor, "Already initialised mCompositor"); 1.842 + 1.843 + for (size_t i = 0; i < aBackendHints.Length(); ++i) { 1.844 + RefPtr<Compositor> compositor; 1.845 + if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) { 1.846 + compositor = new CompositorOGL(mWidget, 1.847 + mEGLSurfaceSize.width, 1.848 + mEGLSurfaceSize.height, 1.849 + mUseExternalSurfaceSize); 1.850 + } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) { 1.851 + compositor = new BasicCompositor(mWidget); 1.852 +#ifdef XP_WIN 1.853 + } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) { 1.854 + compositor = new CompositorD3D11(mWidget); 1.855 + } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9) { 1.856 + compositor = new CompositorD3D9(this, mWidget); 1.857 +#endif 1.858 + } 1.859 + 1.860 + if (!compositor) { 1.861 + // We passed a backend hint for which we can't create a compositor. 1.862 + // For example, we sometime pass LayersBackend::LAYERS_NONE as filler in aBackendHints. 1.863 + continue; 1.864 + } 1.865 + 1.866 + compositor->SetCompositorID(mCompositorID); 1.867 + RefPtr<LayerManagerComposite> layerManager = new LayerManagerComposite(compositor); 1.868 + 1.869 + if (layerManager->Initialize()) { 1.870 + mLayerManager = layerManager; 1.871 + MOZ_ASSERT(compositor); 1.872 + mCompositor = compositor; 1.873 + sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = layerManager; 1.874 + return; 1.875 + } 1.876 + } 1.877 +} 1.878 + 1.879 +PLayerTransactionParent* 1.880 +CompositorParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints, 1.881 + const uint64_t& aId, 1.882 + TextureFactoryIdentifier* aTextureFactoryIdentifier, 1.883 + bool *aSuccess) 1.884 +{ 1.885 + MOZ_ASSERT(aId == 0); 1.886 + 1.887 + // mWidget doesn't belong to the compositor thread, so it should be set to 1.888 + // nullptr before returning from this method, to avoid accessing it elsewhere. 1.889 + nsIntRect rect; 1.890 + mWidget->GetClientBounds(rect); 1.891 + InitializeLayerManager(aBackendHints); 1.892 + mWidget = nullptr; 1.893 + 1.894 + if (!mLayerManager) { 1.895 + NS_WARNING("Failed to initialise Compositor"); 1.896 + *aSuccess = false; 1.897 + LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, 0); 1.898 + p->AddIPDLReference(); 1.899 + return p; 1.900 + } 1.901 + 1.902 + mCompositionManager = new AsyncCompositionManager(mLayerManager); 1.903 + *aSuccess = true; 1.904 + 1.905 + *aTextureFactoryIdentifier = mCompositor->GetTextureFactoryIdentifier(); 1.906 + LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, 0); 1.907 + p->AddIPDLReference(); 1.908 + return p; 1.909 +} 1.910 + 1.911 +bool 1.912 +CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor) 1.913 +{ 1.914 + static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference(); 1.915 + return true; 1.916 +} 1.917 + 1.918 + 1.919 +typedef map<uint64_t,CompositorParent*> CompositorMap; 1.920 +static CompositorMap* sCompositorMap; 1.921 + 1.922 +void CompositorParent::CreateCompositorMap() 1.923 +{ 1.924 + if (sCompositorMap == nullptr) { 1.925 + sCompositorMap = new CompositorMap; 1.926 + } 1.927 +} 1.928 + 1.929 +void CompositorParent::DestroyCompositorMap() 1.930 +{ 1.931 + if (sCompositorMap != nullptr) { 1.932 + NS_ASSERTION(sCompositorMap->empty(), 1.933 + "The Compositor map should be empty when destroyed>"); 1.934 + delete sCompositorMap; 1.935 + sCompositorMap = nullptr; 1.936 + } 1.937 +} 1.938 + 1.939 +CompositorParent* CompositorParent::GetCompositor(uint64_t id) 1.940 +{ 1.941 + CompositorMap::iterator it = sCompositorMap->find(id); 1.942 + return it != sCompositorMap->end() ? it->second : nullptr; 1.943 +} 1.944 + 1.945 +void CompositorParent::AddCompositor(CompositorParent* compositor, uint64_t* outID) 1.946 +{ 1.947 + static uint64_t sNextID = 1; 1.948 + 1.949 + ++sNextID; 1.950 + (*sCompositorMap)[sNextID] = compositor; 1.951 + *outID = sNextID; 1.952 +} 1.953 + 1.954 +CompositorParent* CompositorParent::RemoveCompositor(uint64_t id) 1.955 +{ 1.956 + CompositorMap::iterator it = sCompositorMap->find(id); 1.957 + if (it == sCompositorMap->end()) { 1.958 + return nullptr; 1.959 + } 1.960 + CompositorParent *retval = it->second; 1.961 + sCompositorMap->erase(it); 1.962 + return retval; 1.963 +} 1.964 + 1.965 +bool 1.966 +CompositorParent::RecvNotifyChildCreated(const uint64_t& child) 1.967 +{ 1.968 + NotifyChildCreated(child); 1.969 + return true; 1.970 +} 1.971 + 1.972 +void 1.973 +CompositorParent::NotifyChildCreated(uint64_t aChild) 1.974 +{ 1.975 + sIndirectLayerTrees[aChild].mParent = this; 1.976 + sIndirectLayerTrees[aChild].mLayerManager = mLayerManager; 1.977 +} 1.978 + 1.979 +/*static*/ uint64_t 1.980 +CompositorParent::AllocateLayerTreeId() 1.981 +{ 1.982 + MOZ_ASSERT(CompositorLoop()); 1.983 + MOZ_ASSERT(NS_IsMainThread()); 1.984 + static uint64_t ids = 0; 1.985 + return ++ids; 1.986 +} 1.987 + 1.988 +static void 1.989 +EraseLayerState(uint64_t aId) 1.990 +{ 1.991 + sIndirectLayerTrees.erase(aId); 1.992 +} 1.993 + 1.994 +/*static*/ void 1.995 +CompositorParent::DeallocateLayerTreeId(uint64_t aId) 1.996 +{ 1.997 + MOZ_ASSERT(NS_IsMainThread()); 1.998 + CompositorLoop()->PostTask(FROM_HERE, 1.999 + NewRunnableFunction(&EraseLayerState, aId)); 1.1000 +} 1.1001 + 1.1002 +static void 1.1003 +UpdateControllerForLayersId(uint64_t aLayersId, 1.1004 + GeckoContentController* aController) 1.1005 +{ 1.1006 + // Adopt ref given to us by SetControllerForLayerTree() 1.1007 + sIndirectLayerTrees[aLayersId].mController = 1.1008 + already_AddRefed<GeckoContentController>(aController); 1.1009 +} 1.1010 + 1.1011 +ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(uint64_t aLayersId, 1.1012 + Layer* aRoot, 1.1013 + GeckoContentController* aController) 1.1014 + : mLayersId(aLayersId) 1.1015 +{ 1.1016 + sIndirectLayerTrees[aLayersId].mRoot = aRoot; 1.1017 + sIndirectLayerTrees[aLayersId].mController = aController; 1.1018 +} 1.1019 + 1.1020 +ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() 1.1021 +{ 1.1022 + sIndirectLayerTrees.erase(mLayersId); 1.1023 +} 1.1024 + 1.1025 +/*static*/ void 1.1026 +CompositorParent::SetControllerForLayerTree(uint64_t aLayersId, 1.1027 + GeckoContentController* aController) 1.1028 +{ 1.1029 + // This ref is adopted by UpdateControllerForLayersId(). 1.1030 + aController->AddRef(); 1.1031 + CompositorLoop()->PostTask(FROM_HERE, 1.1032 + NewRunnableFunction(&UpdateControllerForLayersId, 1.1033 + aLayersId, 1.1034 + aController)); 1.1035 +} 1.1036 + 1.1037 +/*static*/ APZCTreeManager* 1.1038 +CompositorParent::GetAPZCTreeManager(uint64_t aLayersId) 1.1039 +{ 1.1040 + const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId); 1.1041 + if (state && state->mParent) { 1.1042 + return state->mParent->mApzcTreeManager; 1.1043 + } 1.1044 + return nullptr; 1.1045 +} 1.1046 + 1.1047 +float 1.1048 +CompositorParent::ComputeRenderIntegrity() 1.1049 +{ 1.1050 + if (mLayerManager) { 1.1051 + return mLayerManager->ComputeRenderIntegrity(); 1.1052 + } 1.1053 + 1.1054 + return 1.0f; 1.1055 +} 1.1056 + 1.1057 + 1.1058 +/** 1.1059 + * This class handles layer updates pushed directly from child 1.1060 + * processes to the compositor thread. It's associated with a 1.1061 + * CompositorParent on the compositor thread. While it uses the 1.1062 + * PCompositor protocol to manage these updates, it doesn't actually 1.1063 + * drive compositing itself. For that it hands off work to the 1.1064 + * CompositorParent it's associated with. 1.1065 + */ 1.1066 +class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent, 1.1067 + public ShadowLayersManager 1.1068 +{ 1.1069 + friend class CompositorParent; 1.1070 + 1.1071 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent) 1.1072 +public: 1.1073 + CrossProcessCompositorParent(Transport* aTransport) 1.1074 + : mTransport(aTransport) 1.1075 + {} 1.1076 + 1.1077 + // IToplevelProtocol::CloneToplevel() 1.1078 + virtual IToplevelProtocol* 1.1079 + CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds, 1.1080 + base::ProcessHandle aPeerProcess, 1.1081 + mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE; 1.1082 + 1.1083 + virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; 1.1084 + 1.1085 + // FIXME/bug 774388: work out what shutdown protocol we need. 1.1086 + virtual bool RecvWillStop() MOZ_OVERRIDE { return true; } 1.1087 + virtual bool RecvStop() MOZ_OVERRIDE { return true; } 1.1088 + virtual bool RecvPause() MOZ_OVERRIDE { return true; } 1.1089 + virtual bool RecvResume() MOZ_OVERRIDE { return true; } 1.1090 + virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE; 1.1091 + virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot, 1.1092 + SurfaceDescriptor* aOutSnapshot) 1.1093 + { return true; } 1.1094 + virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; } 1.1095 + virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) { return true; } 1.1096 + virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) MOZ_OVERRIDE { return true; } 1.1097 + virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) MOZ_OVERRIDE { return true; } 1.1098 + 1.1099 + virtual PLayerTransactionParent* 1.1100 + AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints, 1.1101 + const uint64_t& aId, 1.1102 + TextureFactoryIdentifier* aTextureFactoryIdentifier, 1.1103 + bool *aSuccess) MOZ_OVERRIDE; 1.1104 + 1.1105 + virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE; 1.1106 + 1.1107 + virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, 1.1108 + const TargetConfig& aTargetConfig, 1.1109 + bool aIsFirstPaint, 1.1110 + bool aScheduleComposite) MOZ_OVERRIDE; 1.1111 + virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE; 1.1112 + virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree, 1.1113 + const TimeStamp& aTime) MOZ_OVERRIDE; 1.1114 + virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE; 1.1115 + 1.1116 + virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) MOZ_OVERRIDE; 1.1117 + 1.1118 +private: 1.1119 + // Private destructor, to discourage deletion outside of Release(): 1.1120 + virtual ~CrossProcessCompositorParent(); 1.1121 + 1.1122 + void DeferredDestroy(); 1.1123 + 1.1124 + // There can be many CPCPs, and IPDL-generated code doesn't hold a 1.1125 + // reference to top-level actors. So we hold a reference to 1.1126 + // ourself. This is released (deferred) in ActorDestroy(). 1.1127 + nsRefPtr<CrossProcessCompositorParent> mSelfRef; 1.1128 + Transport* mTransport; 1.1129 +}; 1.1130 + 1.1131 +static void 1.1132 +OpenCompositor(CrossProcessCompositorParent* aCompositor, 1.1133 + Transport* aTransport, ProcessHandle aHandle, 1.1134 + MessageLoop* aIOLoop) 1.1135 +{ 1.1136 + DebugOnly<bool> ok = aCompositor->Open(aTransport, aHandle, aIOLoop); 1.1137 + MOZ_ASSERT(ok); 1.1138 +} 1.1139 + 1.1140 +/*static*/ PCompositorParent* 1.1141 +CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess) 1.1142 +{ 1.1143 + nsRefPtr<CrossProcessCompositorParent> cpcp = 1.1144 + new CrossProcessCompositorParent(aTransport); 1.1145 + ProcessHandle handle; 1.1146 + if (!base::OpenProcessHandle(aOtherProcess, &handle)) { 1.1147 + // XXX need to kill |aOtherProcess|, it's boned 1.1148 + return nullptr; 1.1149 + } 1.1150 + cpcp->mSelfRef = cpcp; 1.1151 + CompositorLoop()->PostTask( 1.1152 + FROM_HERE, 1.1153 + NewRunnableFunction(OpenCompositor, cpcp.get(), 1.1154 + aTransport, handle, XRE_GetIOMessageLoop())); 1.1155 + // The return value is just compared to null for success checking, 1.1156 + // we're not sharing a ref. 1.1157 + return cpcp.get(); 1.1158 +} 1.1159 + 1.1160 +IToplevelProtocol* 1.1161 +CompositorParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds, 1.1162 + base::ProcessHandle aPeerProcess, 1.1163 + mozilla::ipc::ProtocolCloneContext* aCtx) 1.1164 +{ 1.1165 + for (unsigned int i = 0; i < aFds.Length(); i++) { 1.1166 + if (aFds[i].protocolId() == (unsigned)GetProtocolId()) { 1.1167 + Transport* transport = OpenDescriptor(aFds[i].fd(), 1.1168 + Transport::MODE_SERVER); 1.1169 + PCompositorParent* compositor = Create(transport, base::GetProcId(aPeerProcess)); 1.1170 + compositor->CloneManagees(this, aCtx); 1.1171 + compositor->IToplevelProtocol::SetTransport(transport); 1.1172 + return compositor; 1.1173 + } 1.1174 + } 1.1175 + return nullptr; 1.1176 +} 1.1177 + 1.1178 +static void 1.1179 +UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig) 1.1180 +{ 1.1181 + sIndirectLayerTrees[aId].mRoot = aRoot; 1.1182 + sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig; 1.1183 +} 1.1184 + 1.1185 +/* static */ const CompositorParent::LayerTreeState* 1.1186 +CompositorParent::GetIndirectShadowTree(uint64_t aId) 1.1187 +{ 1.1188 + LayerTreeMap::const_iterator cit = sIndirectLayerTrees.find(aId); 1.1189 + if (sIndirectLayerTrees.end() == cit) { 1.1190 + return nullptr; 1.1191 + } 1.1192 + return &cit->second; 1.1193 +} 1.1194 + 1.1195 +static void 1.1196 +RemoveIndirectTree(uint64_t aId) 1.1197 +{ 1.1198 + sIndirectLayerTrees.erase(aId); 1.1199 +} 1.1200 + 1.1201 +void 1.1202 +CrossProcessCompositorParent::ActorDestroy(ActorDestroyReason aWhy) 1.1203 +{ 1.1204 + MessageLoop::current()->PostTask( 1.1205 + FROM_HERE, 1.1206 + NewRunnableMethod(this, &CrossProcessCompositorParent::DeferredDestroy)); 1.1207 +} 1.1208 + 1.1209 +PLayerTransactionParent* 1.1210 +CrossProcessCompositorParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>&, 1.1211 + const uint64_t& aId, 1.1212 + TextureFactoryIdentifier* aTextureFactoryIdentifier, 1.1213 + bool *aSuccess) 1.1214 +{ 1.1215 + MOZ_ASSERT(aId != 0); 1.1216 + 1.1217 + if (sIndirectLayerTrees[aId].mLayerManager) { 1.1218 + sIndirectLayerTrees[aId].mCrossProcessParent = this; 1.1219 + LayerManagerComposite* lm = sIndirectLayerTrees[aId].mLayerManager; 1.1220 + *aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier(); 1.1221 + *aSuccess = true; 1.1222 + LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId); 1.1223 + p->AddIPDLReference(); 1.1224 + return p; 1.1225 + } 1.1226 + 1.1227 + NS_WARNING("Created child without a matching parent?"); 1.1228 + // XXX: should be false, but that causes us to fail some tests on Mac w/ OMTC. 1.1229 + // Bug 900745. change *aSuccess to false to see test failures. 1.1230 + *aSuccess = true; 1.1231 + LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId); 1.1232 + p->AddIPDLReference(); 1.1233 + return p; 1.1234 +} 1.1235 + 1.1236 +bool 1.1237 +CrossProcessCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) 1.1238 +{ 1.1239 + LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers); 1.1240 + RemoveIndirectTree(slp->GetId()); 1.1241 + static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference(); 1.1242 + return true; 1.1243 +} 1.1244 + 1.1245 +bool 1.1246 +CrossProcessCompositorParent::RecvNotifyChildCreated(const uint64_t& child) 1.1247 +{ 1.1248 + sIndirectLayerTrees[child].mParent->NotifyChildCreated(child); 1.1249 + return true; 1.1250 +} 1.1251 + 1.1252 +void 1.1253 +CrossProcessCompositorParent::ShadowLayersUpdated( 1.1254 + LayerTransactionParent* aLayerTree, 1.1255 + const TargetConfig& aTargetConfig, 1.1256 + bool aIsFirstPaint, 1.1257 + bool aScheduleComposite) 1.1258 +{ 1.1259 + uint64_t id = aLayerTree->GetId(); 1.1260 + MOZ_ASSERT(id != 0); 1.1261 + Layer* shadowRoot = aLayerTree->GetRoot(); 1.1262 + if (shadowRoot) { 1.1263 + SetShadowProperties(shadowRoot); 1.1264 + } 1.1265 + UpdateIndirectTree(id, shadowRoot, aTargetConfig); 1.1266 + 1.1267 + sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite); 1.1268 +} 1.1269 + 1.1270 +void 1.1271 +CrossProcessCompositorParent::ForceComposite(LayerTransactionParent* aLayerTree) 1.1272 +{ 1.1273 + uint64_t id = aLayerTree->GetId(); 1.1274 + MOZ_ASSERT(id != 0); 1.1275 + sIndirectLayerTrees[id].mParent->ForceComposite(aLayerTree); 1.1276 +} 1.1277 + 1.1278 +bool 1.1279 +CrossProcessCompositorParent::SetTestSampleTime( 1.1280 + LayerTransactionParent* aLayerTree, const TimeStamp& aTime) 1.1281 +{ 1.1282 + uint64_t id = aLayerTree->GetId(); 1.1283 + MOZ_ASSERT(id != 0); 1.1284 + return sIndirectLayerTrees[id].mParent->SetTestSampleTime(aLayerTree, aTime); 1.1285 +} 1.1286 + 1.1287 +void 1.1288 +CrossProcessCompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree) 1.1289 +{ 1.1290 + uint64_t id = aLayerTree->GetId(); 1.1291 + MOZ_ASSERT(id != 0); 1.1292 + sIndirectLayerTrees[id].mParent->LeaveTestMode(aLayerTree); 1.1293 +} 1.1294 + 1.1295 +AsyncCompositionManager* 1.1296 +CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLayerTree) 1.1297 +{ 1.1298 + uint64_t id = aLayerTree->GetId(); 1.1299 + return sIndirectLayerTrees[id].mParent->GetCompositionManager(aLayerTree); 1.1300 +} 1.1301 + 1.1302 +void 1.1303 +CrossProcessCompositorParent::DeferredDestroy() 1.1304 +{ 1.1305 + CrossProcessCompositorParent* self; 1.1306 + mSelfRef.forget(&self); 1.1307 + 1.1308 + nsCOMPtr<nsIRunnable> runnable = 1.1309 + NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release); 1.1310 + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); 1.1311 +} 1.1312 + 1.1313 +CrossProcessCompositorParent::~CrossProcessCompositorParent() 1.1314 +{ 1.1315 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.1316 + new DeleteTask<Transport>(mTransport)); 1.1317 +} 1.1318 + 1.1319 +IToplevelProtocol* 1.1320 +CrossProcessCompositorParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds, 1.1321 + base::ProcessHandle aPeerProcess, 1.1322 + mozilla::ipc::ProtocolCloneContext* aCtx) 1.1323 +{ 1.1324 + for (unsigned int i = 0; i < aFds.Length(); i++) { 1.1325 + if (aFds[i].protocolId() == (unsigned)GetProtocolId()) { 1.1326 + Transport* transport = OpenDescriptor(aFds[i].fd(), 1.1327 + Transport::MODE_SERVER); 1.1328 + PCompositorParent* compositor = 1.1329 + CompositorParent::Create(transport, base::GetProcId(aPeerProcess)); 1.1330 + compositor->CloneManagees(this, aCtx); 1.1331 + compositor->IToplevelProtocol::SetTransport(transport); 1.1332 + return compositor; 1.1333 + } 1.1334 + } 1.1335 + return nullptr; 1.1336 +} 1.1337 + 1.1338 +} // namespace layers 1.1339 +} // namespace mozilla