/* -*- 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/CrossProcessCompositorBridgeParent.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 "gfxContext.h" // for gfxContext #include "gfxPlatform.h" // for gfxPlatform #include "TreeTraversal.h" // for ForEachNode #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/dom/ContentParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/gfx/2D.h" // for DrawTarget #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/gfx/Rect.h" // for IntSize #include "VRManager.h" // for VRManager #include "mozilla/ipc/Transport.h" // for Transport #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager #include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent #include "mozilla/layers/APZThreadUtils.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/CompositorThread.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/FrameUniformityData.h" #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/LayerTreeOwnerTracker.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/PLayerTransactionParent.h" #include "mozilla/layers/RemoteContentController.h" #include "mozilla/layout/RenderFrameParent.h" #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService #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 "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" #include "mozilla/Telemetry.h" #ifdef MOZ_ENABLE_PROFILER_SPS #include "ProfilerMarkers.h" #endif #include "mozilla/VsyncDispatcher.h" #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) #include "VsyncSource.h" #endif #include "mozilla/widget/CompositorWidget.h" #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING # include "mozilla/widget/CompositorWidgetParent.h" #endif #include "LayerScope.h" namespace mozilla { namespace layers { // defined in CompositorBridgeParent.cpp typedef map<uint64_t, CompositorBridgeParent::LayerTreeState> LayerTreeMap; extern LayerTreeMap sIndirectLayerTrees; extern StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock; bool CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint() { mNotifyAfterRemotePaint = true; return true; } void CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { // We must keep this object alive untill the code handling message // reception is finished on this thread. MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy)); } PLayerTransactionParent* CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent( const nsTArray<LayersBackend>&, const uint64_t& aId, TextureFactoryIdentifier* aTextureFactoryIdentifier, bool *aSuccess) { MOZ_ASSERT(aId != 0); // Check to see if this child process has access to this layer tree. if (!LayerTreeOwnerTracker::Get()->IsMapped(aId, OtherPid())) { NS_ERROR("Unexpected layers id in AllocPLayerTransactionParent; dropping message..."); return nullptr; } MonitorAutoLock lock(*sIndirectLayerTreesLock); CompositorBridgeParent::LayerTreeState* state = nullptr; LayerTreeMap::iterator itr = 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 = new LayerTransactionParent(lm, this, aId); p->AddIPDLReference(); sIndirectLayerTrees[aId].mLayerTree = p; p->SetPendingCompositorUpdates(state->mPendingCompositorUpdates); return p; } NS_WARNING("Created child without a matching parent?"); *aSuccess = false; LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId); p->AddIPDLReference(); return p; } bool CrossProcessCompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) { LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers); EraseLayerState(slp->GetId()); static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference(); return true; } bool CrossProcessCompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ) { // Check to see if this child process has access to this layer tree. if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) { NS_ERROR("Unexpected layers id in RecvAsyncPanZoomEnabled; dropping message..."); return false; } MonitorAutoLock lock(*sIndirectLayerTreesLock); CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId]; *aHasAPZ = state.mParent ? state.mParent->AsyncPanZoomEnabled() : false; return true; } PAPZCTreeManagerParent* CrossProcessCompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) { // Check to see if this child process has access to this layer tree. if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) { NS_ERROR("Unexpected layers id in AllocPAPZCTreeManagerParent; dropping message..."); return nullptr; } MonitorAutoLock lock(*sIndirectLayerTreesLock); CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId]; MOZ_ASSERT(state.mParent); MOZ_ASSERT(!state.mApzcTreeManagerParent); state.mApzcTreeManagerParent = new APZCTreeManagerParent(aLayersId, state.mParent->GetAPZCTreeManager()); return state.mApzcTreeManagerParent; } bool CrossProcessCompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) { APZCTreeManagerParent* parent = static_cast<APZCTreeManagerParent*>(aActor); MonitorAutoLock lock(*sIndirectLayerTreesLock); auto iter = sIndirectLayerTrees.find(parent->LayersId()); if (iter != sIndirectLayerTrees.end()) { CompositorBridgeParent::LayerTreeState& state = iter->second; MOZ_ASSERT(state.mApzcTreeManagerParent == parent); state.mApzcTreeManagerParent = nullptr; } delete parent; return true; } PAPZParent* CrossProcessCompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId) { // Check to see if this child process has access to this layer tree. if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) { NS_ERROR("Unexpected layers id in AllocPAPZParent; dropping message..."); return nullptr; } RemoteContentController* controller = new RemoteContentController(); // Increment the controller's refcount before we return it. This will keep the // controller alive until it is released by IPDL in DeallocPAPZParent. controller->AddRef(); MonitorAutoLock lock(*sIndirectLayerTreesLock); CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId]; MOZ_ASSERT(!state.mController); state.mController = controller; return controller; } bool CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) { RemoteContentController* controller = static_cast<RemoteContentController*>(aActor); controller->Release(); return true; } bool CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child) { MonitorAutoLock lock(*sIndirectLayerTreesLock); for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) { CompositorBridgeParent::LayerTreeState* lts = &it->second; if (lts->mParent && lts->mCrossProcessParent == this) { lts->mParent->NotifyChildCreated(child); return true; } } return false; } void CrossProcessCompositorBridgeParent::ShadowLayersUpdated( LayerTransactionParent* aLayerTree, const uint64_t& aTransactionId, const TargetConfig& aTargetConfig, const InfallibleTArray<PluginWindowData>& aPlugins, bool aIsFirstPaint, bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aIsRepeatTransaction, int32_t /*aPaintSyncId: unused*/, bool aHitTestUpdate) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return; } MOZ_ASSERT(state->mParent); state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint); Layer* shadowRoot = aLayerTree->GetRoot(); if (shadowRoot) { CompositorBridgeParent::SetShadowProperties(shadowRoot); } UpdateIndirectTree(id, shadowRoot, aTargetConfig); // Cache the plugin data for this remote layer tree state->mPluginData = aPlugins; state->mUpdatedPluginDataAvailable = true; state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite, aPaintSequenceNumber, aIsRepeatTransaction, aHitTestUpdate); // Send the 'remote paint ready' message to the content thread if it has already asked. if(mNotifyAfterRemotePaint) { Unused << SendRemotePaintIsReady(); mNotifyAfterRemotePaint = false; } if (aLayerTree->ShouldParentObserveEpoch()) { // Note that we send this through the window compositor, since this needs // to reach the widget owning the tab. Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), true); } aLayerTree->SetPendingTransactionId(aTransactionId); } void CrossProcessCompositorBridgeParent::DidComposite( uint64_t aId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) { sIndirectLayerTreesLock->AssertCurrentThreadOwns(); if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) { Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd); layerTree->SetPendingTransactionId(0); } } void CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); CompositorBridgeParent* parent; { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); parent = sIndirectLayerTrees[id].mParent; } if (parent) { parent->ForceComposite(aLayerTree); } } void CrossProcessCompositorBridgeParent::NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (state && state->mParent) { // Note that we send this through the window compositor, since this needs // to reach the widget owning the tab. Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), false); } } bool CrossProcessCompositorBridgeParent::SetTestSampleTime( LayerTransactionParent* aLayerTree, const TimeStamp& aTime) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return false; } MOZ_ASSERT(state->mParent); return state->mParent->SetTestSampleTime(aLayerTree, aTime); } void CrossProcessCompositorBridgeParent::LeaveTestMode(LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return; } MOZ_ASSERT(state->mParent); state->mParent->LeaveTestMode(aLayerTree); } void CrossProcessCompositorBridgeParent::ApplyAsyncProperties( LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return; } MOZ_ASSERT(state->mParent); state->mParent->ApplyAsyncProperties(aLayerTree); } void CrossProcessCompositorBridgeParent::FlushApzRepaints(const LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return; } MOZ_ASSERT(state->mParent); state->mParent->FlushApzRepaints(aLayerTree); } void CrossProcessCompositorBridgeParent::GetAPZTestData( const LayerTransactionParent* aLayerTree, APZTestData* aOutData) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); MonitorAutoLock lock(*sIndirectLayerTreesLock); *aOutData = sIndirectLayerTrees[id].mApzTestData; } void CrossProcessCompositorBridgeParent::SetConfirmedTargetAPZC( const LayerTransactionParent* aLayerTree, const uint64_t& aInputBlockId, const nsTArray<ScrollableLayerGuid>& aTargets) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state || !state->mParent) { return; } state->mParent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets); } AsyncCompositionManager* CrossProcessCompositorBridgeParent::GetCompositionManager(LayerTransactionParent* aLayerTree) { uint64_t id = aLayerTree->GetId(); const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state) { return nullptr; } MOZ_ASSERT(state->mParent); return state->mParent->GetCompositionManager(aLayerTree); } bool CrossProcessCompositorBridgeParent::RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId) { MonitorAutoLock lock(*sIndirectLayerTreesLock); CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId]; if (LayerTransactionParent* ltp = state.mLayerTree) { ltp->AcknowledgeCompositorUpdate(); } MOZ_ASSERT(state.mPendingCompositorUpdates > 0); state.mPendingCompositorUpdates--; return true; } void CrossProcessCompositorBridgeParent::DeferredDestroy() { mCompositorThreadHolder = nullptr; mSelfRef = nullptr; } CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent() { MOZ_ASSERT(XRE_GetIOMessageLoop()); MOZ_ASSERT(IToplevelProtocol::GetTransport()); } PTextureParent* CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aId, const uint64_t& aSerial) { CompositorBridgeParent::LayerTreeState* state = nullptr; LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId); if (sIndirectLayerTrees.end() != itr) { state = &itr->second; } TextureFlags flags = aFlags; if (!state || state->mPendingCompositorUpdates) { // The compositor was recreated, and we're receiving layers updates for a // a layer manager that will soon be discarded or invalidated. We can't // return null because this will mess up deserialization later and we'll // kill the content process. Instead, we signal that the underlying // TextureHost should not attempt to access the compositor. flags |= TextureFlags::INVALID_COMPOSITOR; } else if (state->mLayerManager && state->mLayerManager->GetCompositor() && aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) { gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong"; } return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial); } bool CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) { return TextureHost::DestroyIPDLActor(actor); } bool CrossProcessCompositorBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); } bool CrossProcessCompositorBridgeParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId, const uint32_t& aPresShellId) { CompositorBridgeParent* parent; { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); parent = sIndirectLayerTrees[aLayersId].mParent; } if (parent) { parent->ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId)); } return true; } bool CrossProcessCompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, const CSSIntRegion& aRegion) { CompositorBridgeParent* parent; { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); parent = sIndirectLayerTrees[aGuid.mLayersId].mParent; } if (parent) { return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion); } return true; } void CrossProcessCompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) { uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(id != 0); CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(id); if (!state || !state->mParent) { return; } state->mParent->UpdatePaintTime(aLayerTree, aPaintTime); } } // namespace layers } // namespace mozilla