/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set sw=2 ts=2 et tw=80 : *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/layers/CompositorParent.h"#include<stdio.h> // for fprintf, stdout#include<stdint.h> // for uint64_t#include<map> // for _Rb_tree_iterator, etc#include<utility> // for pair#include"LayerTransactionParent.h" // for LayerTransactionParent#include"RenderTrace.h" // for RenderTraceLayers#include"base/message_loop.h" // for MessageLoop#include"base/process.h" // for ProcessId#include"base/task.h" // for CancelableTask, etc#include"base/thread.h" // for Thread#include"base/tracked.h" // for FROM_HERE#include"gfxContext.h" // for gfxContext#include"gfxPlatform.h" // for gfxPlatform#ifdef MOZ_WIDGET_GTK#include"gfxPlatformGtk.h" // for gfxPlatform#endif#include"gfxPrefs.h" // for gfxPrefs#include"mozilla/AutoRestore.h" // for AutoRestore#include"mozilla/ClearOnShutdown.h" // for ClearOnShutdown#include"mozilla/DebugOnly.h" // for DebugOnly#include"mozilla/gfx/2D.h" // for DrawTarget#include"mozilla/gfx/Point.h" // for IntSize#include"mozilla/ipc/Transport.h" // for Transport#include"mozilla/layers/APZCTreeManager.h" // for APZCTreeManager#include"mozilla/layers/AsyncCompositionManager.h"#include"mozilla/layers/BasicCompositor.h" // for BasicCompositor#include"mozilla/layers/Compositor.h" // for Compositor#include"mozilla/layers/CompositorOGL.h" // for CompositorOGL#include"mozilla/layers/CompositorTypes.h"#include"mozilla/layers/LayerManagerComposite.h"#include"mozilla/layers/LayersTypes.h"#include"mozilla/layers/PLayerTransactionParent.h"#include"mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager#include"mozilla/mozalloc.h" // for operator new, etc#include"mozilla/Telemetry.h"#ifdef MOZ_WIDGET_GTK#include"basic/X11BasicCompositor.h" // for X11BasicCompositor#endif#include"nsCOMPtr.h" // for already_AddRefed#include"nsDebug.h" // for NS_ASSERTION, etc#include"nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc#include"nsIWidget.h" // for nsIWidget#include"nsRect.h" // for nsIntRect#include"nsTArray.h" // for nsTArray#include"nsThreadUtils.h" // for NS_IsMainThread#include"nsXULAppAPI.h" // for XRE_GetIOMessageLoop#ifdef XP_WIN#include"mozilla/layers/CompositorD3D11.h"#include"mozilla/layers/CompositorD3D9.h"#endif#include"GeckoProfiler.h"#include"mozilla/ipc/ProtocolTypes.h"#include"mozilla/unused.h"#include"mozilla/Hal.h"#include"mozilla/HalTypes.h"#include"mozilla/StaticPtr.h"#ifdef MOZ_ENABLE_PROFILER_SPS#include"ProfilerMarkers.h"#endif#include"mozilla/VsyncDispatcher.h"#ifdef MOZ_WIDGET_GONK#include"GeckoTouchDispatcher.h"#endifnamespacemozilla{namespacelayers{usingnamespacemozilla::ipc;usingnamespacemozilla::gfx;usingnamespacestd;usingbase::ProcessId;usingbase::Thread;CompositorParent::LayerTreeState::LayerTreeState():mParent(nullptr),mLayerManager(nullptr),mCrossProcessParent(nullptr),mLayerTree(nullptr),mUpdatedPluginDataAvailable(false){}CompositorParent::LayerTreeState::~LayerTreeState(){if(mController){mController->Destroy();}}typedefmap<uint64_t,CompositorParent::LayerTreeState>LayerTreeMap;staticLayerTreeMapsIndirectLayerTrees;staticStaticAutoPtr<mozilla::Monitor>sIndirectLayerTreesLock;staticvoidEnsureLayerTreeMapReady(){MOZ_ASSERT(NS_IsMainThread());if(!sIndirectLayerTreesLock){sIndirectLayerTreesLock=newMonitor("IndirectLayerTree");mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);}}/** * A global map referencing each compositor by ID. * * This map is used by the ImageBridge protocol to trigger * compositions without having to keep references to the * compositor */typedefmap<uint64_t,CompositorParent*>CompositorMap;staticCompositorMap*sCompositorMap;staticvoidCreateCompositorMap(){MOZ_ASSERT(!sCompositorMap);sCompositorMap=newCompositorMap;}staticvoidDestroyCompositorMap(){MOZ_ASSERT(sCompositorMap);MOZ_ASSERT(sCompositorMap->empty());deletesCompositorMap;sCompositorMap=nullptr;}// See ImageBridgeChild.cppvoidReleaseImageBridgeParentSingleton();CompositorThreadHolder::CompositorThreadHolder():mCompositorThread(CreateCompositorThread()){MOZ_ASSERT(NS_IsMainThread());MOZ_COUNT_CTOR(CompositorThreadHolder);}CompositorThreadHolder::~CompositorThreadHolder(){MOZ_ASSERT(NS_IsMainThread());MOZ_COUNT_DTOR(CompositorThreadHolder);DestroyCompositorThread(mCompositorThread);}staticStaticRefPtr<CompositorThreadHolder>sCompositorThreadHolder;staticboolsFinishedCompositorShutDown=false;CompositorThreadHolder*GetCompositorThreadHolder(){returnsCompositorThreadHolder;}/* static */Thread*CompositorThreadHolder::CreateCompositorThread(){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(!sCompositorThreadHolder,"The compositor thread has already been started!");Thread*compositorThread=newThread("Compositor");Thread::Optionsoptions;/* Timeout values are powers-of-two to enable us get better data. 128ms is chosen for transient hangs because 8Hz should be the minimally acceptable goal for Compositor responsiveness (normal goal is 60Hz). */options.transient_hang_timeout=128;// milliseconds/* 2048ms is chosen for permanent hangs because it's longer than most * Compositor hangs seen in the wild, but is short enough to not miss getting * native hang stacks. */options.permanent_hang_timeout=2048;// milliseconds#if defined(_WIN32)/* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As * such the thread is a gui thread, and must process a windows message queue or * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */options.message_loop_type=MessageLoop::TYPE_UI;#endifif(!compositorThread->StartWithOptions(options)){deletecompositorThread;returnnullptr;}EnsureLayerTreeMapReady();CreateCompositorMap();returncompositorThread;}/* static */voidCompositorThreadHolder::DestroyCompositorThread(Thread*aCompositorThread){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(!sCompositorThreadHolder,"We shouldn't be destroying the compositor thread yet.");DestroyCompositorMap();deleteaCompositorThread;sFinishedCompositorShutDown=true;}staticThread*CompositorThread(){returnsCompositorThreadHolder?sCompositorThreadHolder->GetCompositorThread():nullptr;}staticvoidSetThreadPriority(){hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);}CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent*aCompositorParent,nsIWidget*aWidget):mNeedsComposite(false),mIsObservingVsync(false),mVsyncNotificationsSkipped(0),mCompositorParent(aCompositorParent),mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor"),mCurrentCompositeTask(nullptr),mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor"),mSetNeedsCompositeTask(nullptr){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(aWidget!=nullptr);mCompositorVsyncDispatcher=aWidget->GetCompositorVsyncDispatcher();#ifdef MOZ_WIDGET_GONKGeckoTouchDispatcher::GetInstance()->SetCompositorVsyncObserver(this);#endif}CompositorVsyncObserver::~CompositorVsyncObserver(){MOZ_ASSERT(!mIsObservingVsync);// The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listenersmCompositorParent=nullptr;mCompositorVsyncDispatcher=nullptr;}voidCompositorVsyncObserver::Destroy(){MOZ_ASSERT(CompositorParent::IsInCompositorThread());UnobserveVsync();CancelCurrentCompositeTask();CancelCurrentSetNeedsCompositeTask();}voidCompositorVsyncObserver::CancelCurrentSetNeedsCompositeTask(){MOZ_ASSERT(CompositorParent::IsInCompositorThread());MonitorAutoLocklock(mSetNeedsCompositeMonitor);if(mSetNeedsCompositeTask){mSetNeedsCompositeTask->Cancel();mSetNeedsCompositeTask=nullptr;}mNeedsComposite=false;}/** * TODO Potential performance heuristics: * If a composite takes 17 ms, do we composite ASAP or wait until next vsync? * If a layer transaction comes after vsync, do we composite ASAP or wait until * next vsync? * How many skipped vsync events until we stop listening to vsync events? */voidCompositorVsyncObserver::SetNeedsComposite(boolaNeedsComposite){if(!CompositorParent::IsInCompositorThread()){MonitorAutoLocklock(mSetNeedsCompositeMonitor);mSetNeedsCompositeTask=NewRunnableMethod(this,&CompositorVsyncObserver::SetNeedsComposite,aNeedsComposite);MOZ_ASSERT(CompositorParent::CompositorLoop());CompositorParent::CompositorLoop()->PostTask(FROM_HERE,mSetNeedsCompositeTask);return;}else{MonitorAutoLocklock(mSetNeedsCompositeMonitor);mSetNeedsCompositeTask=nullptr;}mNeedsComposite=aNeedsComposite;if(!mIsObservingVsync&&mNeedsComposite){ObserveVsync();}}boolCompositorVsyncObserver::NotifyVsync(TimeStampaVsyncTimestamp){// Called from the vsync dispatch threadMOZ_ASSERT(!CompositorParent::IsInCompositorThread());MOZ_ASSERT(!NS_IsMainThread());MonitorAutoLocklock(mCurrentCompositeTaskMonitor);if(mCurrentCompositeTask==nullptr){mCurrentCompositeTask=NewRunnableMethod(this,&CompositorVsyncObserver::Composite,aVsyncTimestamp);MOZ_ASSERT(CompositorParent::CompositorLoop());CompositorParent::CompositorLoop()->PostTask(FROM_HERE,mCurrentCompositeTask);}returntrue;}voidCompositorVsyncObserver::CancelCurrentCompositeTask(){MOZ_ASSERT(CompositorParent::IsInCompositorThread()||NS_IsMainThread());MonitorAutoLocklock(mCurrentCompositeTaskMonitor);if(mCurrentCompositeTask){mCurrentCompositeTask->Cancel();mCurrentCompositeTask=nullptr;}}voidCompositorVsyncObserver::Composite(TimeStampaVsyncTimestamp){MOZ_ASSERT(CompositorParent::IsInCompositorThread());{MonitorAutoLocklock(mCurrentCompositeTaskMonitor);mCurrentCompositeTask=nullptr;}DispatchTouchEvents(aVsyncTimestamp);if(mNeedsComposite&&mCompositorParent){mNeedsComposite=false;mCompositorParent->CompositeCallback(aVsyncTimestamp);mVsyncNotificationsSkipped=0;}elseif(mVsyncNotificationsSkipped++>gfxPrefs::CompositorUnobserveCount()){UnobserveVsync();}}voidCompositorVsyncObserver::OnForceComposeToTarget(){/** * bug 1138502 - There are cases such as during long-running window resizing events * where we receive many sync RecvFlushComposites. We also get vsync notifications which * will increment mVsyncNotificationsSkipped because a composite just occurred. After * enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next * ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will * force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not * free and this oscillating behavior causes a performance hit. In order to avoid this problem, * we reset the mVsyncNotificationsSkipped counter to keep vsync enabled. */MOZ_ASSERT(CompositorParent::IsInCompositorThread());mVsyncNotificationsSkipped=0;}boolCompositorVsyncObserver::NeedsComposite(){MOZ_ASSERT(CompositorParent::IsInCompositorThread());returnmNeedsComposite;}voidCompositorVsyncObserver::ObserveVsync(){MOZ_ASSERT(CompositorParent::IsInCompositorThread());mCompositorVsyncDispatcher->SetCompositorVsyncObserver(this);mIsObservingVsync=true;}voidCompositorVsyncObserver::UnobserveVsync(){MOZ_ASSERT(CompositorParent::IsInCompositorThread());mCompositorVsyncDispatcher->SetCompositorVsyncObserver(nullptr);mIsObservingVsync=false;}voidCompositorVsyncObserver::DispatchTouchEvents(TimeStampaVsyncTimestamp){#ifdef MOZ_WIDGET_GONKGeckoTouchDispatcher::GetInstance()->NotifyVsync(aVsyncTimestamp);#endif}voidCompositorParent::StartUp(){MOZ_ASSERT(NS_IsMainThread(),"Should be on the main Thread!");MOZ_ASSERT(!sCompositorThreadHolder,"The compositor thread has already been started!");sCompositorThreadHolder=newCompositorThreadHolder();}voidCompositorParent::ShutDown(){MOZ_ASSERT(NS_IsMainThread(),"Should be on the main Thread!");MOZ_ASSERT(sCompositorThreadHolder,"The compositor thread has already been shut down!");ReleaseImageBridgeParentSingleton();sCompositorThreadHolder=nullptr;// No locking is needed around sFinishedCompositorShutDown because it is only// ever accessed on the main thread.while(!sFinishedCompositorShutDown){NS_ProcessNextEvent(nullptr,true);}}MessageLoop*CompositorParent::CompositorLoop(){returnCompositorThread()?CompositorThread()->message_loop():nullptr;}staticboolIsInCompositorAsapMode(){// Returns true if the compositor is allowed to be in ASAP mode// and layout is not in ASAP modereturngfxPrefs::LayersCompositionFrameRate()==0&&!gfxPlatform::IsInLayoutAsapMode();}staticboolUseVsyncComposition(){returngfxPrefs::VsyncAlignedCompositor()&&gfxPrefs::HardwareVsyncEnabled()&&!IsInCompositorAsapMode()&&!gfxPlatform::IsInLayoutAsapMode();}CompositorParent::CompositorParent(nsIWidget*aWidget,boolaUseExternalSurfaceSize,intaSurfaceWidth,intaSurfaceHeight):mWidget(aWidget),mCurrentCompositeTask(nullptr),mIsTesting(false),mPendingTransaction(0),mPaused(false),mUseExternalSurfaceSize(aUseExternalSurfaceSize),mEGLSurfaceSize(aSurfaceWidth,aSurfaceHeight),mPauseCompositionMonitor("PauseCompositionMonitor"),mResumeCompositionMonitor("ResumeCompositionMonitor"),mOverrideComposeReadiness(false),mForceCompositionTask(nullptr),mCompositorThreadHolder(sCompositorThreadHolder),mCompositorVsyncObserver(nullptr){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(CompositorThread(),"The compositor thread must be Initialized before instanciating a CompositorParent.");MOZ_COUNT_CTOR(CompositorParent);mCompositorID=0;// FIXME: This holds on the the fact that right now the only thing that// can destroy this instance is initialized on the compositor thread after// this task has been processed.MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(&AddCompositor,this,&mCompositorID));CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(SetThreadPriority));mRootLayerTreeID=AllocateLayerTreeId();{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[mRootLayerTreeID].mParent=this;}if(gfxPrefs::AsyncPanZoomEnabled()){mApzcTreeManager=newAPZCTreeManager();}if(UseVsyncComposition()){NS_WARNING("Enabling vsync compositor\n");mCompositorVsyncObserver=newCompositorVsyncObserver(this,aWidget);}gfxPlatform::GetPlatform()->ComputeTileSize();}boolCompositorParent::IsInCompositorThread(){returnCompositorThread()&&CompositorThread()->thread_id()==PlatformThread::CurrentId();}uint64_tCompositorParent::RootLayerTreeId(){returnmRootLayerTreeID;}CompositorParent::~CompositorParent(){MOZ_ASSERT(NS_IsMainThread());MOZ_COUNT_DTOR(CompositorParent);}voidCompositorParent::Destroy(){MOZ_ASSERT(ManagedPLayerTransactionParent().Length()==0,"CompositorParent destroyed before managed PLayerTransactionParent");MOZ_ASSERT(mPaused);// Ensure RecvWillStop was called// Ensure that the layer manager is destructed on the compositor thread.mLayerManager=nullptr;if(mCompositor){mCompositor->Destroy();}mCompositor=nullptr;mCompositionManager=nullptr;if(mApzcTreeManager){mApzcTreeManager->ClearTree();mApzcTreeManager=nullptr;}{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees.erase(mRootLayerTreeID);}if(mCompositorVsyncObserver){mCompositorVsyncObserver->Destroy();mCompositorVsyncObserver=nullptr;}}voidCompositorParent::ForceIsFirstPaint(){mCompositionManager->ForceIsFirstPaint();}boolCompositorParent::RecvWillStop(){mPaused=true;RemoveCompositor(mCompositorID);// Ensure that the layer manager is destroyed before CompositorChild.if(mLayerManager){MonitorAutoLocklock(*sIndirectLayerTreesLock);for(LayerTreeMap::iteratorit=sIndirectLayerTrees.begin();it!=sIndirectLayerTrees.end();it++){LayerTreeState*lts=&it->second;if(lts->mParent==this){mLayerManager->ClearCachedResources(lts->mRoot);lts->mLayerManager=nullptr;lts->mParent=nullptr;}}mLayerManager->Destroy();mLayerManager=nullptr;mCompositionManager=nullptr;}returntrue;}voidCompositorParent::DeferredDestroy(){MOZ_ASSERT(!NS_IsMainThread());mCompositorThreadHolder=nullptr;Release();}boolCompositorParent::RecvStop(){Destroy();// There are chances that the ref count reaches zero on the main thread shortly// after this function returns while some ipdl code still needs to run on// this thread.// We must keep the compositor parent alive untill the code handling message// reception is finished on this thread.this->AddRef();// Corresponds to DeferredDestroy's ReleaseMessageLoop::current()->PostTask(FROM_HERE,NewRunnableMethod(this,&CompositorParent::DeferredDestroy));returntrue;}boolCompositorParent::RecvPause(){PauseComposition();returntrue;}boolCompositorParent::RecvResume(){ResumeComposition();returntrue;}boolCompositorParent::RecvMakeSnapshot(constSurfaceDescriptor&aInSnapshot,constnsIntRect&aRect){RefPtr<DrawTarget>target=GetDrawTargetForDescriptor(aInSnapshot,gfx::BackendType::CAIRO);ForceComposeToTarget(target,&aRect);returntrue;}boolCompositorParent::RecvFlushRendering(){if(mCompositorVsyncObserver&&mCompositorVsyncObserver->NeedsComposite()){mCompositorVsyncObserver->SetNeedsComposite(false);CancelCurrentCompositeTask();ForceComposeToTarget(nullptr);}elseif(mCurrentCompositeTask){// If we're waiting to do a composite, then cancel it// and do it immediately instead.CancelCurrentCompositeTask();ForceComposeToTarget(nullptr);}returntrue;}boolCompositorParent::RecvGetTileSize(int32_t*aWidth,int32_t*aHeight){*aWidth=gfxPlatform::GetPlatform()->GetTileWidth();*aHeight=gfxPlatform::GetPlatform()->GetTileHeight();returntrue;}boolCompositorParent::RecvNotifyRegionInvalidated(constnsIntRegion&aRegion){if(mLayerManager){mLayerManager->AddInvalidRegion(aRegion);}returntrue;}boolCompositorParent::RecvStartFrameTimeRecording(constint32_t&aBufferSize,uint32_t*aOutStartIndex){if(mLayerManager){*aOutStartIndex=mLayerManager->StartFrameTimeRecording(aBufferSize);}else{*aOutStartIndex=0;}returntrue;}boolCompositorParent::RecvStopFrameTimeRecording(constuint32_t&aStartIndex,InfallibleTArray<float>*intervals){if(mLayerManager){mLayerManager->StopFrameTimeRecording(aStartIndex,*intervals);}returntrue;}voidCompositorParent::ActorDestroy(ActorDestroyReasonwhy){CancelCurrentCompositeTask();if(mForceCompositionTask){mForceCompositionTask->Cancel();mForceCompositionTask=nullptr;}mPaused=true;RemoveCompositor(mCompositorID);if(mLayerManager){mLayerManager->Destroy();mLayerManager=nullptr;{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[mRootLayerTreeID].mLayerManager=nullptr;}mCompositionManager=nullptr;mCompositor=nullptr;}}voidCompositorParent::ScheduleRenderOnCompositorThread(){CancelableTask*renderTask=NewRunnableMethod(this,&CompositorParent::ScheduleComposition);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(FROM_HERE,renderTask);}voidCompositorParent::PauseComposition(){MOZ_ASSERT(IsInCompositorThread(),"PauseComposition() can only be called on the compositor thread");MonitorAutoLocklock(mPauseCompositionMonitor);if(!mPaused){mPaused=true;mCompositor->Pause();DidComposite();}// if anyone's waiting to make sure that composition really got paused, tell themlock.NotifyAll();}voidCompositorParent::ResumeComposition(){MOZ_ASSERT(IsInCompositorThread(),"ResumeComposition() can only be called on the compositor thread");MonitorAutoLocklock(mResumeCompositionMonitor);if(!mCompositor->Resume()){#ifdef MOZ_WIDGET_ANDROID// We can't get a surface. This could be because the activity changed between// the time resume was scheduled and now.__android_log_print(ANDROID_LOG_INFO,"CompositorParent","Unable to renew compositor surface; remaining in paused state");#endiflock.NotifyAll();return;}mPaused=false;mLastCompose=TimeStamp::Now();CompositeToTarget(nullptr);// if anyone's waiting to make sure that composition really got resumed, tell themlock.NotifyAll();}voidCompositorParent::ForceComposition(){// Cancel the orientation changed state to force compositionmForceCompositionTask=nullptr;ScheduleRenderOnCompositorThread();}voidCompositorParent::CancelCurrentCompositeTask(){if(mCompositorVsyncObserver){mCompositorVsyncObserver->CancelCurrentCompositeTask();}elseif(mCurrentCompositeTask){mCurrentCompositeTask->Cancel();mCurrentCompositeTask=nullptr;}}voidCompositorParent::SetEGLSurfaceSize(intwidth,intheight){NS_ASSERTION(mUseExternalSurfaceSize,"Compositor created without UseExternalSurfaceSize provided");mEGLSurfaceSize.SizeTo(width,height);if(mCompositor){mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width,mEGLSurfaceSize.height));}}voidCompositorParent::ResumeCompositionAndResize(intwidth,intheight){SetEGLSurfaceSize(width,height);ResumeComposition();}/* * This will execute a pause synchronously, waiting to make sure that the compositor * really is paused. */voidCompositorParent::SchedulePauseOnCompositorThread(){MonitorAutoLocklock(mPauseCompositionMonitor);CancelableTask*pauseTask=NewRunnableMethod(this,&CompositorParent::PauseComposition);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(FROM_HERE,pauseTask);// Wait until the pause has actually been processed by the compositor threadlock.Wait();}boolCompositorParent::ScheduleResumeOnCompositorThread(intwidth,intheight){MonitorAutoLocklock(mResumeCompositionMonitor);CancelableTask*resumeTask=NewRunnableMethod(this,&CompositorParent::ResumeCompositionAndResize,width,height);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(FROM_HERE,resumeTask);// Wait until the resume has actually been processed by the compositor threadlock.Wait();return!mPaused;}voidCompositorParent::ScheduleTask(CancelableTask*task,inttime){if(time==0){MessageLoop::current()->PostTask(FROM_HERE,task);}else{MessageLoop::current()->PostDelayedTask(FROM_HERE,task,time);}}voidCompositorParent::NotifyShadowTreeTransaction(uint64_taId,boolaIsFirstPaint,boolaScheduleComposite,uint32_taPaintSequenceNumber,boolaIsRepeatTransaction){if(mApzcTreeManager&&!aIsRepeatTransaction&&mLayerManager&&mLayerManager->GetRoot()){AutoResolveRefLayersresolve(mCompositionManager);mApzcTreeManager->UpdateHitTestingTree(this,mLayerManager->GetRoot(),aIsFirstPaint,aId,aPaintSequenceNumber);mLayerManager->NotifyShadowTreeTransaction();}if(aScheduleComposite){ScheduleComposition();}}// Used when layout.frame_rate is -1. Needs to be kept in sync with// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.staticconstint32_tkDefaultFrameRate=60;staticint32_tCalculateCompositionFrameRate(){int32_tcompositionFrameRatePref=gfxPrefs::LayersCompositionFrameRate();if(compositionFrameRatePref<0){// Use the same frame rate for composition as for layout.int32_tlayoutFrameRatePref=gfxPrefs::LayoutFrameRate();if(layoutFrameRatePref<0){// TODO: The main thread frame scheduling code consults the actual// monitor refresh rate in this case. We should do the same.returnkDefaultFrameRate;}returnlayoutFrameRatePref;}returncompositionFrameRatePref;}voidCompositorParent::ScheduleSoftwareTimerComposition(){MOZ_ASSERT(!mCompositorVsyncObserver);if(mCurrentCompositeTask){return;}boolinitialComposition=mLastCompose.IsNull();TimeDurationdelta;if(!initialComposition)delta=TimeStamp::Now()-mLastCompose;int32_trate=CalculateCompositionFrameRate();// If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.TimeDurationminFrameDelta=TimeDuration::FromMilliseconds(rate==0?0.0:std::max(0.0,1000.0/rate));mCurrentCompositeTask=NewRunnableMethod(this,&CompositorParent::CompositeCallback,TimeStamp::Now());if(!initialComposition&&delta<minFrameDelta){TimeDurationdelay=minFrameDelta-delta;#ifdef COMPOSITOR_PERFORMANCE_WARNINGmExpectedComposeStartTime=TimeStamp::Now()+delay;#endifScheduleTask(mCurrentCompositeTask,delay.ToMilliseconds());}else{#ifdef COMPOSITOR_PERFORMANCE_WARNINGmExpectedComposeStartTime=TimeStamp::Now();#endifScheduleTask(mCurrentCompositeTask,0);}}voidCompositorParent::ScheduleComposition(){MOZ_ASSERT(IsInCompositorThread());if(mPaused){return;}if(mCompositorVsyncObserver){mCompositorVsyncObserver->SetNeedsComposite(true);}else{ScheduleSoftwareTimerComposition();}}voidCompositorParent::CompositeCallback(TimeStampaScheduleTime){if(mCompositorVsyncObserver){// Align OMTA to vsync time.// TODO: ensure it aligns with the refresh / start time of// animationsmLastCompose=aScheduleTime;}else{mLastCompose=TimeStamp::Now();}mCurrentCompositeTask=nullptr;CompositeToTarget(nullptr);}// Go down the composite layer tree, setting properties to match their// content-side counterparts./* static */voidCompositorParent::SetShadowProperties(Layer*aLayer){if(Layer*maskLayer=aLayer->GetMaskLayer()){SetShadowProperties(maskLayer);}// FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate.LayerComposite*layerComposite=aLayer->AsLayerComposite();// Set the layerComposite's base transform to the layer's base transform.layerComposite->SetShadowTransform(aLayer->GetBaseTransform());layerComposite->SetShadowTransformSetByAnimation(false);layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion());layerComposite->SetShadowClipRect(aLayer->GetClipRect());layerComposite->SetShadowOpacity(aLayer->GetOpacity());for(Layer*child=aLayer->GetFirstChild();child;child=child->GetNextSibling()){SetShadowProperties(child);}}voidCompositorParent::CompositeToTarget(DrawTarget*aTarget,constnsIntRect*aRect){profiler_tracing("Paint","Composite",TRACING_INTERVAL_START);PROFILER_LABEL("CompositorParent","Composite",js::ProfileEntry::Category::GRAPHICS);MOZ_ASSERT(IsInCompositorThread(),"Composite can only be called on the compositor thread");TimeStampstart=TimeStamp::Now();#ifdef COMPOSITOR_PERFORMANCE_WARNINGTimeDurationscheduleDelta=TimeStamp::Now()-mExpectedComposeStartTime;if(scheduleDelta>TimeDuration::FromMilliseconds(2)||scheduleDelta<TimeDuration::FromMilliseconds(-2)){printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",scheduleDelta.ToMilliseconds());}#endifif(!CanComposite()){DidComposite();return;}AutoResolveRefLayersresolve(mCompositionManager);if(aTarget){mLayerManager->BeginTransactionWithDrawTarget(aTarget,*aRect);}else{mLayerManager->BeginTransaction();}SetShadowProperties(mLayerManager->GetRoot());if(mForceCompositionTask&&!mOverrideComposeReadiness){if(mCompositionManager->ReadyForCompose()){mForceCompositionTask->Cancel();mForceCompositionTask=nullptr;}else{return;}}mCompositionManager->ComputeRotation();TimeStamptime=mIsTesting?mTestTime:mLastCompose;boolrequestNextFrame=mCompositionManager->TransformShadowTree(time);if(requestNextFrame){ScheduleComposition();}RenderTraceLayers(mLayerManager->GetRoot(),"0000");#ifdef MOZ_DUMP_PAINTINGif(gfxPrefs::DumpHostLayers()){printf_stderr("Painting --- compositing layer tree:\n");mLayerManager->Dump();}#endifmLayerManager->SetDebugOverlayWantsNextFrame(false);mLayerManager->EndEmptyTransaction();if(!aTarget){DidComposite();}if(mLayerManager->DebugOverlayWantsNextFrame()){ScheduleComposition();}#ifdef COMPOSITOR_PERFORMANCE_WARNINGTimeDurationexecutionTime=TimeStamp::Now()-mLastCompose;TimeDurationframeBudget=TimeDuration::FromMilliseconds(15);int32_tframeRate=CalculateCompositionFrameRate();if(frameRate>0){frameBudget=TimeDuration::FromSeconds(1.0/frameRate);}if(executionTime>frameBudget){printf_stderr("Compositor: Composite execution took %4.1f ms\n",executionTime.ToMilliseconds());}#endif// 0 -> Full-tilt compositeif(gfxPrefs::LayersCompositionFrameRate()==0||mLayerManager->GetCompositor()->GetDiagnosticTypes()&DiagnosticTypes::FLASH_BORDERS){// Special full-tilt composite mode for performance testingScheduleComposition();}mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,start);profiler_tracing("Paint","Composite",TRACING_INTERVAL_END);}voidCompositorParent::ForceComposeToTarget(DrawTarget*aTarget,constnsIntRect*aRect){PROFILER_LABEL("CompositorParent","ForceComposeToTarget",js::ProfileEntry::Category::GRAPHICS);if(mCompositorVsyncObserver){mCompositorVsyncObserver->OnForceComposeToTarget();}AutoRestore<bool>override(mOverrideComposeReadiness);mOverrideComposeReadiness=true;mLastCompose=TimeStamp::Now();CompositeToTarget(aTarget,aRect);}boolCompositorParent::CanComposite(){returnmLayerManager&&mLayerManager->GetRoot()&&!mPaused;}voidCompositorParent::ScheduleRotationOnCompositorThread(constTargetConfig&aTargetConfig,boolaIsFirstPaint){MOZ_ASSERT(IsInCompositorThread());if(!aIsFirstPaint&&!mCompositionManager->IsFirstPaint()&&mCompositionManager->RequiresReorientation(aTargetConfig.orientation())){if(mForceCompositionTask!=nullptr){mForceCompositionTask->Cancel();}mForceCompositionTask=NewRunnableMethod(this,&CompositorParent::ForceComposition);ScheduleTask(mForceCompositionTask,gfxPrefs::OrientationSyncMillis());}}voidCompositorParent::ShadowLayersUpdated(LayerTransactionParent*aLayerTree,constuint64_t&aTransactionId,constTargetConfig&aTargetConfig,constInfallibleTArray<PluginWindowData>&aUnused,boolaIsFirstPaint,boolaScheduleComposite,uint32_taPaintSequenceNumber,boolaIsRepeatTransaction){ScheduleRotationOnCompositorThread(aTargetConfig,aIsFirstPaint);// Instruct the LayerManager to update its render bounds now. Since all the orientation// change, dimension change would be done at the stage, update the size here is free of// race condition.mLayerManager->UpdateRenderBounds(aTargetConfig.naturalBounds());mLayerManager->SetRegionToClear(aTargetConfig.clearRegion());mCompositionManager->Updated(aIsFirstPaint,aTargetConfig);Layer*root=aLayerTree->GetRoot();mLayerManager->SetRoot(root);if(mApzcTreeManager&&!aIsRepeatTransaction){AutoResolveRefLayersresolve(mCompositionManager);mApzcTreeManager->UpdateHitTestingTree(this,root,aIsFirstPaint,mRootLayerTreeID,aPaintSequenceNumber);}#ifdef DEBUGif(aTransactionId<=mPendingTransaction){// Logging added to help diagnose why we're triggering the assert below.// See bug 1145295printf_stderr("CRASH: aTransactionId %"PRIu64" <= mPendingTransaction %"PRIu64"\n",aTransactionId,mPendingTransaction);}#endifMOZ_ASSERT(aTransactionId>mPendingTransaction);mPendingTransaction=aTransactionId;if(root){SetShadowProperties(root);}if(aScheduleComposite){ScheduleComposition();if(mPaused){DidComposite();}// When testing we synchronously update the shadow tree with the animated// values to avoid race conditions when calling GetAnimationTransform etc.// (since the above SetShadowProperties will remove animation effects).if(mIsTesting){ApplyAsyncProperties(aLayerTree);}}mLayerManager->NotifyShadowTreeTransaction();}voidCompositorParent::ForceComposite(LayerTransactionParent*aLayerTree){ScheduleComposition();}boolCompositorParent::SetTestSampleTime(LayerTransactionParent*aLayerTree,constTimeStamp&aTime){if(aTime.IsNull()){returnfalse;}mIsTesting=true;mTestTime=aTime;booltestComposite=mCompositionManager&&(mCurrentCompositeTask||(mCompositorVsyncObserver&&mCompositorVsyncObserver->NeedsComposite()));// Update but only if we were already scheduled to animateif(testComposite){AutoResolveRefLayersresolve(mCompositionManager);boolrequestNextFrame=mCompositionManager->TransformShadowTree(aTime);if(!requestNextFrame){CancelCurrentCompositeTask();// Pretend we composited in case someone is wating for this event.DidComposite();}}returntrue;}voidCompositorParent::LeaveTestMode(LayerTransactionParent*aLayerTree){mIsTesting=false;}voidCompositorParent::ApplyAsyncProperties(LayerTransactionParent*aLayerTree){// NOTE: This should only be used for testing. For example, when mIsTesting is// true or when called from test-only methods like// LayerTransactionParent::RecvGetAnimationTransform.// Synchronously update the layer tree, but only if a composite was already// scehduled.if(aLayerTree->GetRoot()&&(mCurrentCompositeTask||(mCompositorVsyncObserver&&mCompositorVsyncObserver->NeedsComposite()))){AutoResolveRefLayersresolve(mCompositionManager);TimeStamptime=mIsTesting?mTestTime:mLastCompose;boolrequestNextFrame=mCompositionManager->TransformShadowTree(time);if(!requestNextFrame){CancelCurrentCompositeTask();// Pretend we composited in case someone is waiting for this event.DidComposite();}}}boolCompositorParent::RecvRequestOverfill(){uint32_toverfillRatio=mCompositor->GetFillRatio();unused<<SendOverfill(overfillRatio);returntrue;}voidCompositorParent::GetAPZTestData(constLayerTransactionParent*aLayerTree,APZTestData*aOutData){MonitorAutoLocklock(*sIndirectLayerTreesLock);*aOutData=sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;}voidCompositorParent::InitializeLayerManager(constnsTArray<LayersBackend>&aBackendHints){NS_ASSERTION(!mLayerManager,"Already initialised mLayerManager");NS_ASSERTION(!mCompositor,"Already initialised mCompositor");for(size_ti=0;i<aBackendHints.Length();++i){RefPtr<Compositor>compositor;if(aBackendHints[i]==LayersBackend::LAYERS_OPENGL){compositor=newCompositorOGL(mWidget,mEGLSurfaceSize.width,mEGLSurfaceSize.height,mUseExternalSurfaceSize);}elseif(aBackendHints[i]==LayersBackend::LAYERS_BASIC){#ifdef MOZ_WIDGET_GTKif(gfxPlatformGtk::GetPlatform()->UseXRender()){compositor=newX11BasicCompositor(mWidget);}else#endif{compositor=newBasicCompositor(mWidget);}#ifdef XP_WIN}elseif(aBackendHints[i]==LayersBackend::LAYERS_D3D11){compositor=newCompositorD3D11(mWidget);}elseif(aBackendHints[i]==LayersBackend::LAYERS_D3D9){compositor=newCompositorD3D9(this,mWidget);#endif}if(!compositor){// We passed a backend hint for which we can't create a compositor.// For example, we sometime pass LayersBackend::LAYERS_NONE as filler in aBackendHints.continue;}compositor->SetCompositorID(mCompositorID);RefPtr<LayerManagerComposite>layerManager=newLayerManagerComposite(compositor);if(layerManager->Initialize()){mLayerManager=layerManager;MOZ_ASSERT(compositor);mCompositor=compositor;MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[mRootLayerTreeID].mLayerManager=layerManager;return;}}}PLayerTransactionParent*CompositorParent::AllocPLayerTransactionParent(constnsTArray<LayersBackend>&aBackendHints,constuint64_t&aId,TextureFactoryIdentifier*aTextureFactoryIdentifier,bool*aSuccess){MOZ_ASSERT(aId==0);// mWidget doesn't belong to the compositor thread, so it should be set to// nullptr before returning from this method, to avoid accessing it elsewhere.nsIntRectrect;mWidget->GetClientBounds(rect);InitializeLayerManager(aBackendHints);mWidget=nullptr;if(!mLayerManager){NS_WARNING("Failed to initialise Compositor");*aSuccess=false;LayerTransactionParent*p=newLayerTransactionParent(nullptr,this,0);p->AddIPDLReference();returnp;}mCompositionManager=newAsyncCompositionManager(mLayerManager);*aSuccess=true;*aTextureFactoryIdentifier=mCompositor->GetTextureFactoryIdentifier();LayerTransactionParent*p=newLayerTransactionParent(mLayerManager,this,0);p->AddIPDLReference();returnp;}boolCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent*actor){static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();returntrue;}CompositorParent*CompositorParent::GetCompositor(uint64_tid){CompositorMap::iteratorit=sCompositorMap->find(id);returnit!=sCompositorMap->end()?it->second:nullptr;}voidCompositorParent::AddCompositor(CompositorParent*compositor,uint64_t*outID){staticuint64_tsNextID=1;++sNextID;(*sCompositorMap)[sNextID]=compositor;*outID=sNextID;}CompositorParent*CompositorParent::RemoveCompositor(uint64_tid){CompositorMap::iteratorit=sCompositorMap->find(id);if(it==sCompositorMap->end()){returnnullptr;}CompositorParent*retval=it->second;sCompositorMap->erase(it);returnretval;}boolCompositorParent::RecvNotifyChildCreated(constuint64_t&child){MonitorAutoLocklock(*sIndirectLayerTreesLock);NotifyChildCreated(child);returntrue;}voidCompositorParent::NotifyChildCreated(constuint64_t&aChild){sIndirectLayerTreesLock->AssertCurrentThreadOwns();sIndirectLayerTrees[aChild].mParent=this;sIndirectLayerTrees[aChild].mLayerManager=mLayerManager;}boolCompositorParent::RecvAdoptChild(constuint64_t&child){MonitorAutoLocklock(*sIndirectLayerTreesLock);NotifyChildCreated(child);if(sIndirectLayerTrees[child].mLayerTree){sIndirectLayerTrees[child].mLayerTree->mLayerManager=mLayerManager;}if(sIndirectLayerTrees[child].mRoot){sIndirectLayerTrees[child].mRoot->AsLayerComposite()->SetLayerManager(mLayerManager);}returntrue;}/*static*/uint64_tCompositorParent::AllocateLayerTreeId(){MOZ_ASSERT(CompositorLoop());MOZ_ASSERT(NS_IsMainThread());staticuint64_tids=0;return++ids;}staticvoidEraseLayerState(uint64_taId){MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees.erase(aId);}/*static*/voidCompositorParent::DeallocateLayerTreeId(uint64_taId){MOZ_ASSERT(NS_IsMainThread());// Here main thread notifies compositor to remove an element from// sIndirectLayerTrees. This removed element might be queried soon.// Checking the elements of sIndirectLayerTrees exist or not before using.MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(&EraseLayerState,aId));}staticvoidUpdateControllerForLayersId(uint64_taLayersId,GeckoContentController*aController){// Adopt ref given to us by SetControllerForLayerTree()MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mController=already_AddRefed<GeckoContentController>(aController);}ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(uint64_taLayersId,Layer*aRoot,GeckoContentController*aController):mLayersId(aLayersId){EnsureLayerTreeMapReady();MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mRoot=aRoot;sIndirectLayerTrees[aLayersId].mController=aController;}ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration(){MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees.erase(mLayersId);}/*static*/voidCompositorParent::SetControllerForLayerTree(uint64_taLayersId,GeckoContentController*aController){// This ref is adopted by UpdateControllerForLayersId().aController->AddRef();CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(&UpdateControllerForLayersId,aLayersId,aController));}/*static*/APZCTreeManager*CompositorParent::GetAPZCTreeManager(uint64_taLayersId){constCompositorParent::LayerTreeState*state=CompositorParent::GetIndirectShadowTree(aLayersId);if(state&&state->mParent){returnstate->mParent->mApzcTreeManager;}returnnullptr;}floatCompositorParent::ComputeRenderIntegrity(){if(mLayerManager){returnmLayerManager->ComputeRenderIntegrity();}return1.0f;}staticvoidInsertVsyncProfilerMarker(TimeStampaVsyncTimestamp){#ifdef MOZ_ENABLE_PROFILER_SPSMOZ_ASSERT(CompositorParent::IsInCompositorThread());VsyncPayload*payload=newVsyncPayload(aVsyncTimestamp);PROFILER_MARKER_PAYLOAD("VsyncTimestamp",payload);#endif}/*static */voidCompositorParent::PostInsertVsyncProfilerMarker(TimeStampaVsyncTimestamp){// Called in the vsync threadif(profiler_is_active()&&sCompositorThreadHolder){CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(InsertVsyncProfilerMarker,aVsyncTimestamp));}}/* static */voidCompositorParent::RequestNotifyLayerTreeReady(uint64_taLayersId,CompositorUpdateObserver*aObserver){EnsureLayerTreeMapReady();MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mLayerTreeReadyObserver=aObserver;}/* static */voidCompositorParent::RequestNotifyLayerTreeCleared(uint64_taLayersId,CompositorUpdateObserver*aObserver){EnsureLayerTreeMapReady();MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mLayerTreeClearedObserver=aObserver;}/** * This class handles layer updates pushed directly from child * processes to the compositor thread. It's associated with a * CompositorParent on the compositor thread. While it uses the * PCompositor protocol to manage these updates, it doesn't actually * drive compositing itself. For that it hands off work to the * CompositorParent it's associated with. */classCrossProcessCompositorParentfinal:publicPCompositorParent,publicShadowLayersManager{friendclassCompositorParent;NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)public:explicitCrossProcessCompositorParent(Transport*aTransport):mTransport(aTransport),mCompositorThreadHolder(sCompositorThreadHolder),mNotifyAfterRemotePaint(false){MOZ_ASSERT(NS_IsMainThread());gfxPlatform::GetPlatform()->ComputeTileSize();}// IToplevelProtocol::CloneToplevel()virtualIToplevelProtocol*CloneToplevel(constInfallibleTArray<mozilla::ipc::ProtocolFdMapping>&aFds,base::ProcessHandleaPeerProcess,mozilla::ipc::ProtocolCloneContext*aCtx)override;virtualvoidActorDestroy(ActorDestroyReasonaWhy)override;// FIXME/bug 774388: work out what shutdown protocol we need.virtualboolRecvRequestOverfill()override{returntrue;}virtualboolRecvWillStop()override{returntrue;}virtualboolRecvStop()override{returntrue;}virtualboolRecvPause()override{returntrue;}virtualboolRecvResume()override{returntrue;}virtualboolRecvNotifyChildCreated(constuint64_t&child)override;virtualboolRecvAdoptChild(constuint64_t&child)override{returnfalse;}virtualboolRecvMakeSnapshot(constSurfaceDescriptor&aInSnapshot,constnsIntRect&aRect)override{returntrue;}virtualboolRecvFlushRendering()override{returntrue;}virtualboolRecvNotifyRegionInvalidated(constnsIntRegion&aRegion)override{returntrue;}virtualboolRecvStartFrameTimeRecording(constint32_t&aBufferSize,uint32_t*aOutStartIndex)override{returntrue;}virtualboolRecvStopFrameTimeRecording(constuint32_t&aStartIndex,InfallibleTArray<float>*intervals)override{returntrue;}virtualboolRecvGetTileSize(int32_t*aWidth,int32_t*aHeight)override{*aWidth=gfxPlatform::GetPlatform()->GetTileWidth();*aHeight=gfxPlatform::GetPlatform()->GetTileHeight();returntrue;}/** * Tells this CompositorParent to send a message when the compositor has received the transaction. */virtualboolRecvRequestNotifyAfterRemotePaint()override;virtualPLayerTransactionParent*AllocPLayerTransactionParent(constnsTArray<LayersBackend>&aBackendHints,constuint64_t&aId,TextureFactoryIdentifier*aTextureFactoryIdentifier,bool*aSuccess)override;virtualboolDeallocPLayerTransactionParent(PLayerTransactionParent*aLayers)override;virtualvoidShadowLayersUpdated(LayerTransactionParent*aLayerTree,constuint64_t&aTransactionId,constTargetConfig&aTargetConfig,constInfallibleTArray<PluginWindowData>&aPlugins,boolaIsFirstPaint,boolaScheduleComposite,uint32_taPaintSequenceNumber,boolaIsRepeatTransaction)override;virtualvoidForceComposite(LayerTransactionParent*aLayerTree)override;virtualvoidNotifyClearCachedResources(LayerTransactionParent*aLayerTree)override;virtualboolSetTestSampleTime(LayerTransactionParent*aLayerTree,constTimeStamp&aTime)override;virtualvoidLeaveTestMode(LayerTransactionParent*aLayerTree)override;virtualvoidGetAPZTestData(constLayerTransactionParent*aLayerTree,APZTestData*aOutData)override;virtualAsyncCompositionManager*GetCompositionManager(LayerTransactionParent*aParent)override;voidDidComposite(uint64_taId);private:// Private destructor, to discourage deletion outside of Release():virtual~CrossProcessCompositorParent();voidDeferredDestroy();// There can be many CPCPs, and IPDL-generated code doesn't hold a// reference to top-level actors. So we hold a reference to// ourself. This is released (deferred) in ActorDestroy().nsRefPtr<CrossProcessCompositorParent>mSelfRef;Transport*mTransport;nsRefPtr<CompositorThreadHolder>mCompositorThreadHolder;// If true, we should send a RemotePaintIsReady message when the layer transaction// is receivedboolmNotifyAfterRemotePaint;};voidCompositorParent::DidComposite(){if(mPendingTransaction){unused<<SendDidComposite(0,mPendingTransaction);mPendingTransaction=0;}MonitorAutoLocklock(*sIndirectLayerTreesLock);for(LayerTreeMap::iteratorit=sIndirectLayerTrees.begin();it!=sIndirectLayerTrees.end();it++){LayerTreeState*lts=&it->second;if(lts->mParent==this&<s->mCrossProcessParent){static_cast<CrossProcessCompositorParent*>(lts->mCrossProcessParent)->DidComposite(it->first);}}}staticvoidOpenCompositor(CrossProcessCompositorParent*aCompositor,Transport*aTransport,ProcessIdaOtherPid,MessageLoop*aIOLoop){DebugOnly<bool>ok=aCompositor->Open(aTransport,aOtherPid,aIOLoop);MOZ_ASSERT(ok);}/*static*/PCompositorParent*CompositorParent::Create(Transport*aTransport,ProcessIdaOtherPid){gfxPlatform::InitLayersIPC();nsRefPtr<CrossProcessCompositorParent>cpcp=newCrossProcessCompositorParent(aTransport);cpcp->mSelfRef=cpcp;CompositorLoop()->PostTask(FROM_HERE,NewRunnableFunction(OpenCompositor,cpcp.get(),aTransport,aOtherPid,XRE_GetIOMessageLoop()));// The return value is just compared to null for success checking,// we're not sharing a ref.returncpcp.get();}IToplevelProtocol*CompositorParent::CloneToplevel(constInfallibleTArray<mozilla::ipc::ProtocolFdMapping>&aFds,base::ProcessHandleaPeerProcess,mozilla::ipc::ProtocolCloneContext*aCtx){for(unsignedinti=0;i<aFds.Length();i++){if(aFds[i].protocolId()==(unsigned)GetProtocolId()){Transport*transport=OpenDescriptor(aFds[i].fd(),Transport::MODE_SERVER);PCompositorParent*compositor=Create(transport,base::GetProcId(aPeerProcess));compositor->CloneManagees(this,aCtx);compositor->IToplevelProtocol::SetTransport(transport);returncompositor;}}returnnullptr;}staticvoidUpdateIndirectTree(uint64_taId,Layer*aRoot,constTargetConfig&aTargetConfig){MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aId].mRoot=aRoot;sIndirectLayerTrees[aId].mTargetConfig=aTargetConfig;}/* static */CompositorParent::LayerTreeState*CompositorParent::GetIndirectShadowTree(uint64_taId){MonitorAutoLocklock(*sIndirectLayerTreesLock);LayerTreeMap::iteratorcit=sIndirectLayerTrees.find(aId);if(sIndirectLayerTrees.end()==cit){returnnullptr;}return&cit->second;}boolCrossProcessCompositorParent::RecvRequestNotifyAfterRemotePaint(){mNotifyAfterRemotePaint=true;returntrue;}voidCrossProcessCompositorParent::ActorDestroy(ActorDestroyReasonaWhy){MessageLoop::current()->PostTask(FROM_HERE,NewRunnableMethod(this,&CrossProcessCompositorParent::DeferredDestroy));}PLayerTransactionParent*CrossProcessCompositorParent::AllocPLayerTransactionParent(constnsTArray<LayersBackend>&,constuint64_t&aId,TextureFactoryIdentifier*aTextureFactoryIdentifier,bool*aSuccess){MOZ_ASSERT(aId!=0);MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorParent::LayerTreeState*state=nullptr;LayerTreeMap::iteratoritr=sIndirectLayerTrees.find(aId);if(sIndirectLayerTrees.end()!=itr){state=&itr->second;}if(state&&state->mLayerManager){state->mCrossProcessParent=this;LayerManagerComposite*lm=state->mLayerManager;*aTextureFactoryIdentifier=lm->GetCompositor()->GetTextureFactoryIdentifier();*aSuccess=true;LayerTransactionParent*p=newLayerTransactionParent(lm,this,aId);p->AddIPDLReference();sIndirectLayerTrees[aId].mLayerTree=p;returnp;}NS_WARNING("Created child without a matching parent?");// XXX: should be false, but that causes us to fail some tests on Mac w/ OMTC.// Bug 900745. change *aSuccess to false to see test failures.*aSuccess=true;LayerTransactionParent*p=newLayerTransactionParent(nullptr,this,aId);p->AddIPDLReference();returnp;}boolCrossProcessCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent*aLayers){LayerTransactionParent*slp=static_cast<LayerTransactionParent*>(aLayers);EraseLayerState(slp->GetId());static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference();returntrue;}boolCrossProcessCompositorParent::RecvNotifyChildCreated(constuint64_t&child){MonitorAutoLocklock(*sIndirectLayerTreesLock);for(LayerTreeMap::iteratorit=sIndirectLayerTrees.begin();it!=sIndirectLayerTrees.end();it++){CompositorParent::LayerTreeState*lts=&it->second;if(lts->mParent&<s->mCrossProcessParent==this){lts->mParent->NotifyChildCreated(child);returntrue;}}returnfalse;}voidCrossProcessCompositorParent::ShadowLayersUpdated(LayerTransactionParent*aLayerTree,constuint64_t&aTransactionId,constTargetConfig&aTargetConfig,constInfallibleTArray<PluginWindowData>&aPlugins,boolaIsFirstPaint,boolaScheduleComposite,uint32_taPaintSequenceNumber,boolaIsRepeatTransaction){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);CompositorParent::LayerTreeState*state=CompositorParent::GetIndirectShadowTree(id);if(!state){return;}MOZ_ASSERT(state->mParent);state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig,aIsFirstPaint);Layer*shadowRoot=aLayerTree->GetRoot();if(shadowRoot){CompositorParent::SetShadowProperties(shadowRoot);}UpdateIndirectTree(id,shadowRoot,aTargetConfig);// Cache the plugin data for this remote layer treestate->mPluginData=aPlugins;state->mUpdatedPluginDataAvailable=true;state->mParent->NotifyShadowTreeTransaction(id,aIsFirstPaint,aScheduleComposite,aPaintSequenceNumber,aIsRepeatTransaction);// Send the 'remote paint ready' message to the content thread if it has already asked.if(mNotifyAfterRemotePaint){unused<<SendRemotePaintIsReady();mNotifyAfterRemotePaint=false;}if(state->mLayerTreeReadyObserver){nsRefPtr<CompositorUpdateObserver>observer=state->mLayerTreeReadyObserver;state->mLayerTreeReadyObserver=nullptr;observer->ObserveUpdate(id,true);}aLayerTree->SetPendingTransactionId(aTransactionId);}#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)// Sends plugin window state changes to the main threadstaticvoidUpdatePluginWindowState(uint64_taId){CompositorParent::LayerTreeState<s=sIndirectLayerTrees[aId];if(!lts.mPluginData.Length()&&!lts.mUpdatedPluginDataAvailable){return;}boolshouldComposePlugin=!!lts.mRoot&&!!lts.mRoot->GetParent();boolshouldHidePlugin=(!lts.mRoot||!lts.mRoot->GetParent())&&!lts.mUpdatedPluginDataAvailable;if(shouldComposePlugin){if(!lts.mPluginData.Length()){// We will pass through here in cases where the previous shadow layer// tree contained visible plugins and the new tree does not. All we need// to do here is hide the plugins for the old tree, so don't waste time// calculating clipping.nsTArray<uintptr_t>aVisibleIdList;unused<<lts.mParent->SendUpdatePluginVisibility(aVisibleIdList);lts.mUpdatedPluginDataAvailable=false;return;}// Retrieve the offset and visible region of the layer that hosts// the plugins, CompositorChild needs these in calculating proper// plugin clipping.LayerTransactionParent*layerTree=lts.mLayerTree;Layer*contentRoot=layerTree->GetRoot();if(contentRoot){nsIntPointoffset;nsIntRegionvisibleRegion;if(contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion,&offset)){unused<<lts.mParent->SendUpdatePluginConfigurations(offset,visibleRegion,lts.mPluginData);lts.mUpdatedPluginDataAvailable=false;}else{shouldHidePlugin=true;}}}// Hide all plugins, this remote layer tree is no longer activeif(shouldHidePlugin){// hide all the pluginsfor(uint32_tpluginsIdx=0;pluginsIdx<lts.mPluginData.Length();pluginsIdx++){lts.mPluginData[pluginsIdx].visible()=false;}nsIntPointoffset;nsIntRegionregion;unused<<lts.mParent->SendUpdatePluginConfigurations(offset,region,lts.mPluginData);// Clear because there's no recovering from this until we receive// new shadow layer plugin data in ShadowLayersUpdated.lts.mPluginData.Clear();}}#endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)voidCrossProcessCompositorParent::DidComposite(uint64_taId){sIndirectLayerTreesLock->AssertCurrentThreadOwns();LayerTransactionParent*layerTree=sIndirectLayerTrees[aId].mLayerTree;if(layerTree&&layerTree->GetPendingTransactionId()){unused<<SendDidComposite(aId,layerTree->GetPendingTransactionId());layerTree->SetPendingTransactionId(0);}#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)UpdatePluginWindowState(aId);#endif}voidCrossProcessCompositorParent::ForceComposite(LayerTransactionParent*aLayerTree){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);CompositorParent*parent;{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);parent=sIndirectLayerTrees[id].mParent;}if(parent){parent->ForceComposite(aLayerTree);}}voidCrossProcessCompositorParent::NotifyClearCachedResources(LayerTransactionParent*aLayerTree){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);nsRefPtr<CompositorUpdateObserver>observer;{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);observer=sIndirectLayerTrees[id].mLayerTreeClearedObserver;sIndirectLayerTrees[id].mLayerTreeClearedObserver=nullptr;}if(observer){observer->ObserveUpdate(id,false);}}boolCrossProcessCompositorParent::SetTestSampleTime(LayerTransactionParent*aLayerTree,constTimeStamp&aTime){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);constCompositorParent::LayerTreeState*state=CompositorParent::GetIndirectShadowTree(id);if(!state){returnfalse;}MOZ_ASSERT(state->mParent);returnstate->mParent->SetTestSampleTime(aLayerTree,aTime);}voidCrossProcessCompositorParent::LeaveTestMode(LayerTransactionParent*aLayerTree){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);constCompositorParent::LayerTreeState*state=CompositorParent::GetIndirectShadowTree(id);if(!state){return;}MOZ_ASSERT(state->mParent);state->mParent->LeaveTestMode(aLayerTree);}voidCrossProcessCompositorParent::GetAPZTestData(constLayerTransactionParent*aLayerTree,APZTestData*aOutData){uint64_tid=aLayerTree->GetId();MOZ_ASSERT(id!=0);MonitorAutoLocklock(*sIndirectLayerTreesLock);*aOutData=sIndirectLayerTrees[id].mApzTestData;}AsyncCompositionManager*CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent*aLayerTree){uint64_tid=aLayerTree->GetId();constCompositorParent::LayerTreeState*state=CompositorParent::GetIndirectShadowTree(id);if(!state){returnnullptr;}MOZ_ASSERT(state->mParent);returnstate->mParent->GetCompositionManager(aLayerTree);}voidCrossProcessCompositorParent::DeferredDestroy(){mCompositorThreadHolder=nullptr;mSelfRef=nullptr;}CrossProcessCompositorParent::~CrossProcessCompositorParent(){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(XRE_GetIOMessageLoop());XRE_GetIOMessageLoop()->PostTask(FROM_HERE,newDeleteTask<Transport>(mTransport));}IToplevelProtocol*CrossProcessCompositorParent::CloneToplevel(constInfallibleTArray<mozilla::ipc::ProtocolFdMapping>&aFds,base::ProcessHandleaPeerProcess,mozilla::ipc::ProtocolCloneContext*aCtx){for(unsignedinti=0;i<aFds.Length();i++){if(aFds[i].protocolId()==(unsigned)GetProtocolId()){Transport*transport=OpenDescriptor(aFds[i].fd(),Transport::MODE_SERVER);PCompositorParent*compositor=CompositorParent::Create(transport,base::GetProcId(aPeerProcess));compositor->CloneManagees(this,aCtx);compositor->IToplevelProtocol::SetTransport(transport);returncompositor;}}returnnullptr;}}// namespace layers}// namespace mozilla