diff options
Diffstat (limited to 'gfx/layers/ipc/LayerTransactionParent.cpp')
-rw-r--r-- | gfx/layers/ipc/LayerTransactionParent.cpp | 1098 |
1 files changed, 1098 insertions, 0 deletions
diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp new file mode 100644 index 000000000..c30ccee5b --- /dev/null +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -0,0 +1,1098 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=8 et : + */ +/* 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 "LayerTransactionParent.h" +#include <vector> // for vector +#include "apz/src/AsyncPanZoomController.h" +#include "CompositableHost.h" // for CompositableParent, Get, etc +#include "ImageLayers.h" // for ImageLayer +#include "Layers.h" // for Layer, ContainerLayer, etc +#include "ShadowLayerParent.h" // for ShadowLayerParent +#include "CompositableTransactionParent.h" // for EditReplyVector +#include "CompositorBridgeParent.h" +#include "gfxPrefs.h" +#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D +#include "mozilla/layers/CanvasLayerComposite.h" +#include "mozilla/layers/ColorLayerComposite.h" +#include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/ContainerLayerComposite.h" +#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent +#include "mozilla/layers/ImageLayerComposite.h" +#include "mozilla/layers/LayerManagerComposite.h" +#include "mozilla/layers/LayersMessages.h" // for EditReply, etc +#include "mozilla/layers/LayersSurfaces.h" // for PGrallocBufferParent +#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG +#include "mozilla/layers/PCompositableParent.h" +#include "mozilla/layers/PLayerParent.h" // for PLayerParent +#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL +#include "mozilla/layers/PaintedLayerComposite.h" +#include "mozilla/mozalloc.h" // for operator delete, etc +#include "mozilla/Unused.h" +#include "nsCoord.h" // for NSAppUnitsToFloatPixels +#include "nsDebug.h" // for NS_RUNTIMEABORT +#include "nsDeviceContext.h" // for AppUnitsPerCSSPixel +#include "nsISupportsImpl.h" // for Layer::Release, etc +#include "nsLayoutUtils.h" // for nsLayoutUtils +#include "nsMathUtils.h" // for NS_round +#include "nsPoint.h" // for nsPoint +#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc +#include "TreeTraversal.h" // for ForEachNode +#include "GeckoProfiler.h" +#include "mozilla/layers/TextureHost.h" +#include "mozilla/layers/AsyncCompositionManager.h" + +typedef std::vector<mozilla::layers::EditReply> EditReplyVector; + +using mozilla::layout::RenderFrameParent; + +namespace mozilla { +namespace layers { + +//-------------------------------------------------- +// Convenience accessors +static ShadowLayerParent* +cast(const PLayerParent* in) +{ + return const_cast<ShadowLayerParent*>( + static_cast<const ShadowLayerParent*>(in)); +} + +template<class OpCreateT> +static ShadowLayerParent* +AsLayerComposite(const OpCreateT& op) +{ + return cast(op.layerParent()); +} + +static ShadowLayerParent* +AsLayerComposite(const OpSetRoot& op) +{ + return cast(op.rootParent()); +} + +static ShadowLayerParent* +ShadowContainer(const OpInsertAfter& op) +{ + return cast(op.containerParent()); +} +static ShadowLayerParent* +ShadowChild(const OpInsertAfter& op) +{ + return cast(op.childLayerParent()); +} +static ShadowLayerParent* +ShadowAfter(const OpInsertAfter& op) +{ + return cast(op.afterParent()); +} + +static ShadowLayerParent* +ShadowContainer(const OpPrependChild& op) +{ + return cast(op.containerParent()); +} +static ShadowLayerParent* +ShadowChild(const OpPrependChild& op) +{ + return cast(op.childLayerParent()); +} + +static ShadowLayerParent* +ShadowContainer(const OpRemoveChild& op) +{ + return cast(op.containerParent()); +} +static ShadowLayerParent* +ShadowChild(const OpRemoveChild& op) +{ + return cast(op.childLayerParent()); +} + +static ShadowLayerParent* +ShadowContainer(const OpRepositionChild& op) +{ + return cast(op.containerParent()); +} +static ShadowLayerParent* +ShadowChild(const OpRepositionChild& op) +{ + return cast(op.childLayerParent()); +} +static ShadowLayerParent* +ShadowAfter(const OpRepositionChild& op) +{ + return cast(op.afterParent()); +} + +static ShadowLayerParent* +ShadowContainer(const OpRaiseToTopChild& op) +{ + return cast(op.containerParent()); +} +static ShadowLayerParent* +ShadowChild(const OpRaiseToTopChild& op) +{ + return cast(op.childLayerParent()); +} + +//-------------------------------------------------- +// LayerTransactionParent +LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager, + CompositorBridgeParentBase* aBridge, + uint64_t aId) + : mLayerManager(aManager) + , mCompositorBridge(aBridge) + , mId(aId) + , mChildEpoch(0) + , mParentEpoch(0) + , mPendingTransaction(0) + , mPendingCompositorUpdates(0) + , mDestroyed(false) + , mIPCOpen(false) +{ +} + +LayerTransactionParent::~LayerTransactionParent() +{ +} + +void +LayerTransactionParent::SetLayerManager(LayerManagerComposite* aLayerManager) +{ + mLayerManager = aLayerManager; + const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent(); + for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) { + ShadowLayerParent* slp = + static_cast<ShadowLayerParent*>(iter.Get()->GetKey()); + if (slp->AsLayer() && slp->AsLayer()->AsLayerComposite()) { + slp->AsLayer()->AsLayerComposite()->SetLayerManager(aLayerManager); + } + } +} + +bool +LayerTransactionParent::RecvShutdown() +{ + Destroy(); + return Send__delete__(this); +} + +void +LayerTransactionParent::Destroy() +{ + const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent(); + for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) { + ShadowLayerParent* slp = + static_cast<ShadowLayerParent*>(iter.Get()->GetKey()); + slp->Destroy(); + } + mDestroyed = true; +} + +bool +LayerTransactionParent::RecvUpdateNoSwap(InfallibleTArray<Edit>&& cset, + InfallibleTArray<OpDestroy>&& aToDestroy, + const uint64_t& aFwdTransactionId, + const uint64_t& aTransactionId, + const TargetConfig& targetConfig, + PluginsArray&& aPlugins, + const bool& isFirstPaint, + const bool& scheduleComposite, + const uint32_t& paintSequenceNumber, + const bool& isRepeatTransaction, + const mozilla::TimeStamp& aTransactionStart, + const int32_t& aPaintSyncId) +{ + return RecvUpdate(Move(cset), Move(aToDestroy), aFwdTransactionId, + aTransactionId, targetConfig, Move(aPlugins), isFirstPaint, + scheduleComposite, paintSequenceNumber, isRepeatTransaction, + aTransactionStart, aPaintSyncId, nullptr); +} + +class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender +{ +public: + explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction, + InfallibleTArray<OpDestroy>* aDestroyActors = nullptr) + : mLayerTransaction(aLayerTransaction) + , mActorsToDestroy(aDestroyActors) + { + mLayerTransaction->SetAboutToSendAsyncMessages(); + } + + ~AutoLayerTransactionParentAsyncMessageSender() + { + mLayerTransaction->SendPendingAsyncMessages(); + if (mActorsToDestroy) { + // Destroy the actors after sending the async messages because the latter may contain + // references to some actors. + for (const auto& op : *mActorsToDestroy) { + mLayerTransaction->DestroyActor(op); + } + } + } +private: + LayerTransactionParent* mLayerTransaction; + InfallibleTArray<OpDestroy>* mActorsToDestroy; +}; + +bool +LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId, + const TimeDuration& aPaintTime) +{ + mCompositorBridge->UpdatePaintTime(this, aPaintTime); + return true; +} + +bool +LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset, + InfallibleTArray<OpDestroy>&& aToDestroy, + const uint64_t& aFwdTransactionId, + const uint64_t& aTransactionId, + const TargetConfig& targetConfig, + PluginsArray&& aPlugins, + const bool& isFirstPaint, + const bool& scheduleComposite, + const uint32_t& paintSequenceNumber, + const bool& isRepeatTransaction, + const mozilla::TimeStamp& aTransactionStart, + const int32_t& aPaintSyncId, + InfallibleTArray<EditReply>* reply) +{ + profiler_tracing("Paint", "LayerTransaction", TRACING_INTERVAL_START); + PROFILER_LABEL("LayerTransactionParent", "RecvUpdate", + js::ProfileEntry::Category::GRAPHICS); + +#ifdef COMPOSITOR_PERFORMANCE_WARNING + TimeStamp updateStart = TimeStamp::Now(); +#endif + + MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length())); + + UpdateFwdTransactionId(aFwdTransactionId); + + if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + for (const auto& op : aToDestroy) { + DestroyActor(op); + } + return true; + } + + // This ensures that destroy operations are always processed. It is not safe + // to early-return from RecvUpdate without doing so. + AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy); + EditReplyVector replyv; + + { + AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this)); + layer_manager()->BeginTransaction(); + } + + // not all edits require an update to the hit testing tree + bool updateHitTestingTree = false; + + for (EditArray::index_type i = 0; i < cset.Length(); ++i) { + const Edit& edit = cset[i]; + + switch (edit.type()) { + // Create* ops + case Edit::TOpCreatePaintedLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer")); + + RefPtr<PaintedLayerComposite> layer = + layer_manager()->CreatePaintedLayerComposite(); + AsLayerComposite(edit.get_OpCreatePaintedLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + case Edit::TOpCreateContainerLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer")); + + RefPtr<ContainerLayer> layer = layer_manager()->CreateContainerLayerComposite(); + AsLayerComposite(edit.get_OpCreateContainerLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + case Edit::TOpCreateImageLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer")); + + RefPtr<ImageLayerComposite> layer = + layer_manager()->CreateImageLayerComposite(); + AsLayerComposite(edit.get_OpCreateImageLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + case Edit::TOpCreateColorLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer")); + + RefPtr<ColorLayerComposite> layer = layer_manager()->CreateColorLayerComposite(); + AsLayerComposite(edit.get_OpCreateColorLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + case Edit::TOpCreateCanvasLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer")); + + RefPtr<CanvasLayerComposite> layer = + layer_manager()->CreateCanvasLayerComposite(); + AsLayerComposite(edit.get_OpCreateCanvasLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + case Edit::TOpCreateRefLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer")); + + RefPtr<RefLayerComposite> layer = + layer_manager()->CreateRefLayerComposite(); + AsLayerComposite(edit.get_OpCreateRefLayer())->Bind(layer); + + updateHitTestingTree = true; + break; + } + + // Attributes + case Edit::TOpSetLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes")); + + const OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes(); + ShadowLayerParent* layerParent = AsLayerComposite(osla); + Layer* layer = layerParent->AsLayer(); + if (!layer) { + return false; + } + const LayerAttributes& attrs = osla.attrs(); + + const CommonLayerAttributes& common = attrs.common(); + layer->SetLayerBounds(common.layerBounds()); + layer->SetVisibleRegion(common.visibleRegion()); + layer->SetEventRegions(common.eventRegions()); + layer->SetContentFlags(common.contentFlags()); + layer->SetOpacity(common.opacity()); + layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing()); + layer->SetScrolledClip(common.scrolledClip()); + layer->SetBaseTransform(common.transform().value()); + layer->SetTransformIsPerspective(common.transformIsPerspective()); + layer->SetPostScale(common.postXScale(), common.postYScale()); + layer->SetIsFixedPosition(common.isFixedPosition()); + if (common.isFixedPosition()) { + layer->SetFixedPositionData(common.fixedPositionScrollContainerId(), + common.fixedPositionAnchor(), + common.fixedPositionSides()); + } + if (common.isStickyPosition()) { + layer->SetStickyPositionData(common.stickyScrollContainerId(), + common.stickyScrollRangeOuter(), + common.stickyScrollRangeInner()); + } + layer->SetScrollbarData(common.scrollbarTargetContainerId(), + static_cast<Layer::ScrollDirection>(common.scrollbarDirection()), + common.scrollbarThumbRatio()); + if (common.isScrollbarContainer()) { + layer->SetIsScrollbarContainer(); + } + layer->SetMixBlendMode((gfx::CompositionOp)common.mixBlendMode()); + layer->SetForceIsolatedGroup(common.forceIsolatedGroup()); + if (PLayerParent* maskLayer = common.maskLayerParent()) { + layer->SetMaskLayer(cast(maskLayer)->AsLayer()); + } else { + layer->SetMaskLayer(nullptr); + } + layer->SetAnimations(common.animations()); + layer->SetScrollMetadata(common.scrollMetadata()); + layer->SetDisplayListLog(common.displayListLog().get()); + + // The updated invalid region is added to the existing one, since we can + // update multiple times before the next composite. + layer->AddInvalidRegion(common.invalidRegion()); + + nsTArray<RefPtr<Layer>> maskLayers; + for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) { + Layer* maskLayer = cast(common.ancestorMaskLayersParent().ElementAt(i))->AsLayer(); + maskLayers.AppendElement(maskLayer); + } + layer->SetAncestorMaskLayers(maskLayers); + + typedef SpecificLayerAttributes Specific; + const SpecificLayerAttributes& specific = attrs.specific(); + switch (specific.type()) { + case Specific::Tnull_t: + break; + + case Specific::TPaintedLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] painted layer")); + + PaintedLayerComposite* paintedLayer = layerParent->AsPaintedLayerComposite(); + if (!paintedLayer) { + return false; + } + const PaintedLayerAttributes& attrs = + specific.get_PaintedLayerAttributes(); + + paintedLayer->SetValidRegion(attrs.validRegion()); + + break; + } + case Specific::TContainerLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] container layer")); + + ContainerLayerComposite* containerLayer = layerParent->AsContainerLayerComposite(); + if (!containerLayer) { + return false; + } + const ContainerLayerAttributes& attrs = + specific.get_ContainerLayerAttributes(); + containerLayer->SetPreScale(attrs.preXScale(), attrs.preYScale()); + containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale()); + containerLayer->SetScaleToResolution(attrs.scaleToResolution(), + attrs.presShellResolution()); + containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride()); + + break; + } + case Specific::TColorLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] color layer")); + + ColorLayerComposite* colorLayer = layerParent->AsColorLayerComposite(); + if (!colorLayer) { + return false; + } + colorLayer->SetColor(specific.get_ColorLayerAttributes().color().value()); + colorLayer->SetBounds(specific.get_ColorLayerAttributes().bounds()); + break; + } + case Specific::TCanvasLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] canvas layer")); + + CanvasLayerComposite* canvasLayer = layerParent->AsCanvasLayerComposite(); + if (!canvasLayer) { + return false; + } + canvasLayer->SetSamplingFilter(specific.get_CanvasLayerAttributes().samplingFilter()); + canvasLayer->SetBounds(specific.get_CanvasLayerAttributes().bounds()); + break; + } + case Specific::TRefLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] ref layer")); + + RefLayerComposite* refLayer = layerParent->AsRefLayerComposite(); + if (!refLayer) { + return false; + } + refLayer->SetReferentId(specific.get_RefLayerAttributes().id()); + refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride()); + break; + } + case Specific::TImageLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] image layer")); + + ImageLayerComposite* imageLayer = layerParent->AsImageLayerComposite(); + if (!imageLayer) { + return false; + } + const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes(); + imageLayer->SetSamplingFilter(attrs.samplingFilter()); + imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode()); + break; + } + default: + NS_RUNTIMEABORT("not reached"); + } + + updateHitTestingTree = true; + break; + } + case Edit::TOpSetDiagnosticTypes: { + mLayerManager->GetCompositor()->SetDiagnosticTypes( + edit.get_OpSetDiagnosticTypes().diagnostics()); + break; + } + case Edit::TOpWindowOverlayChanged: { + mLayerManager->SetWindowOverlayChanged(); + break; + } + // Tree ops + case Edit::TOpSetRoot: { + MOZ_LAYERS_LOG(("[ParentSide] SetRoot")); + + Layer* newRoot = AsLayerComposite(edit.get_OpSetRoot())->AsLayer(); + if (!newRoot) { + return false; + } + if (newRoot->GetParent()) { + // newRoot is not a root! + return false; + } + mRoot = newRoot; + + updateHitTestingTree = true; + break; + } + case Edit::TOpInsertAfter: { + MOZ_LAYERS_LOG(("[ParentSide] InsertAfter")); + + const OpInsertAfter& oia = edit.get_OpInsertAfter(); + Layer* child = ShadowChild(oia)->AsLayer(); + if (!child) { + return false; + } + ContainerLayerComposite* container = ShadowContainer(oia)->AsContainerLayerComposite(); + if (!container || + !container->InsertAfter(child, ShadowAfter(oia)->AsLayer())) + { + return false; + } + + updateHitTestingTree = true; + break; + } + case Edit::TOpPrependChild: { + MOZ_LAYERS_LOG(("[ParentSide] PrependChild")); + + const OpPrependChild& oac = edit.get_OpPrependChild(); + Layer* child = ShadowChild(oac)->AsLayer(); + if (!child) { + return false; + } + ContainerLayerComposite* container = ShadowContainer(oac)->AsContainerLayerComposite(); + if (!container || + !container->InsertAfter(child, nullptr)) + { + return false; + } + + updateHitTestingTree = true; + break; + } + case Edit::TOpRemoveChild: { + MOZ_LAYERS_LOG(("[ParentSide] RemoveChild")); + + const OpRemoveChild& orc = edit.get_OpRemoveChild(); + Layer* childLayer = ShadowChild(orc)->AsLayer(); + if (!childLayer) { + return false; + } + ContainerLayerComposite* container = ShadowContainer(orc)->AsContainerLayerComposite(); + if (!container || + !container->RemoveChild(childLayer)) + { + return false; + } + + updateHitTestingTree = true; + break; + } + case Edit::TOpRepositionChild: { + MOZ_LAYERS_LOG(("[ParentSide] RepositionChild")); + + const OpRepositionChild& orc = edit.get_OpRepositionChild(); + Layer* child = ShadowChild(orc)->AsLayer(); + if (!child) { + return false; + } + ContainerLayerComposite* container = ShadowContainer(orc)->AsContainerLayerComposite(); + if (!container || + !container->RepositionChild(child, ShadowAfter(orc)->AsLayer())) + { + return false; + } + + updateHitTestingTree = true; + break; + } + case Edit::TOpRaiseToTopChild: { + MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild")); + + const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild(); + Layer* child = ShadowChild(rtc)->AsLayer(); + if (!child) { + return false; + } + ContainerLayerComposite* container = ShadowContainer(rtc)->AsContainerLayerComposite(); + if (!container || + !container->RepositionChild(child, nullptr)) + { + return false; + } + + updateHitTestingTree = true; + break; + } + case Edit::TCompositableOperation: { + if (!ReceiveCompositableUpdate(edit.get_CompositableOperation(), + replyv)) { + return false; + } + break; + } + case Edit::TOpAttachCompositable: { + const OpAttachCompositable& op = edit.get_OpAttachCompositable(); + CompositableHost* host = CompositableHost::FromIPDLActor(op.compositableParent()); + if (mPendingCompositorUpdates) { + // Do not attach compositables from old layer trees. Return true since + // content cannot handle errors. + return true; + } + if (!Attach(cast(op.layerParent()), host, false)) { + return false; + } + host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID()); + break; + } + case Edit::TOpAttachAsyncCompositable: { + const OpAttachAsyncCompositable& op = edit.get_OpAttachAsyncCompositable(); + PCompositableParent* compositableParent = CompositableMap::Get(op.containerID()); + if (!compositableParent) { + NS_ERROR("CompositableParent not found in the map"); + return false; + } + if (mPendingCompositorUpdates) { + // Do not attach compositables from old layer trees. Return true since + // content cannot handle errors. + return true; + } + CompositableHost* host = CompositableHost::FromIPDLActor(compositableParent); + if (!Attach(cast(op.layerParent()), host, true)) { + return false; + } + host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID()); + break; + } + default: + NS_RUNTIMEABORT("not reached"); + } + } + + mCompositorBridge->ShadowLayersUpdated(this, aTransactionId, targetConfig, + aPlugins, isFirstPaint, scheduleComposite, + paintSequenceNumber, isRepeatTransaction, + aPaintSyncId, updateHitTestingTree); + + { + AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this)); + layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW); + } + + if (reply) { + reply->SetCapacity(replyv.size()); + if (replyv.size() > 0) { + reply->AppendElements(&replyv.front(), replyv.size()); + } + } + + if (!IsSameProcess()) { + // Ensure that any pending operations involving back and front + // buffers have completed, so that neither process stomps on the + // other's buffer contents. + LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); + } + +#ifdef COMPOSITOR_PERFORMANCE_WARNING + int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds(); + if (compositeTime > 15) { + printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime); + } +#endif + + // Enable visual warning for long transaction when draw FPS option is enabled + bool drawFps = gfxPrefs::LayersDrawFPS(); + if (drawFps) { + uint32_t visualWarningTrigger = gfxPrefs::LayerTransactionWarning(); + // The default theshold is 200ms to trigger, hit red when it take 4 times longer + TimeDuration latency = TimeStamp::Now() - aTransactionStart; + if (latency > TimeDuration::FromMilliseconds(visualWarningTrigger)) { + float severity = (latency - TimeDuration::FromMilliseconds(visualWarningTrigger)).ToMilliseconds() / + (4 * visualWarningTrigger); + if (severity > 1.f) { + severity = 1.f; + } + mLayerManager->VisualFrameWarning(severity); + PR_LogPrint("LayerTransactionParent::RecvUpdate transaction from process %d took %f ms", + OtherPid(), + latency.ToMilliseconds()); + } + } + + profiler_tracing("Paint", "LayerTransaction", TRACING_INTERVAL_END); + return true; +} + +bool +LayerTransactionParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) +{ + mChildEpoch = aLayerObserverEpoch; + return true; +} + +bool +LayerTransactionParent::ShouldParentObserveEpoch() +{ + if (mParentEpoch == mChildEpoch) { + return false; + } + + mParentEpoch = mChildEpoch; + return true; +} + +bool +LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime) +{ + return mCompositorBridge->SetTestSampleTime(this, aTime); +} + +bool +LayerTransactionParent::RecvLeaveTestMode() +{ + mCompositorBridge->LeaveTestMode(this); + return true; +} + +bool +LayerTransactionParent::RecvGetAnimationOpacity(PLayerParent* aParent, + float* aOpacity, + bool* aHasAnimationOpacity) +{ + *aHasAnimationOpacity = false; + if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + return false; + } + + Layer* layer = cast(aParent)->AsLayer(); + if (!layer) { + return false; + } + + mCompositorBridge->ApplyAsyncProperties(this); + + if (!layer->AsLayerComposite()->GetShadowOpacitySetByAnimation()) { + return true; + } + + *aOpacity = layer->GetLocalOpacity(); + *aHasAnimationOpacity = true; + return true; +} + +bool +LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent, + MaybeTransform* aTransform) +{ + if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + return false; + } + + Layer* layer = cast(aParent)->AsLayer(); + if (!layer) { + return false; + } + + // Make sure we apply the latest animation style or else we can end up with + // a race between when we temporarily clear the animation transform (in + // CompositorBridgeParent::SetShadowProperties) and when animation recalculates + // the value. + mCompositorBridge->ApplyAsyncProperties(this); + + // This method is specific to transforms applied by animation. + // This is because this method uses the information stored with an animation + // such as the origin of the reference frame corresponding to the layer, to + // recover the untranslated transform from the shadow transform. For + // transforms that are not set by animation we don't have this information + // available. + if (!layer->AsLayerComposite()->GetShadowTransformSetByAnimation()) { + *aTransform = mozilla::void_t(); + return true; + } + + // The following code recovers the untranslated transform + // from the shadow transform by undoing the translations in + // AsyncCompositionManager::SampleValue. + + Matrix4x4 transform = layer->AsLayerComposite()->GetShadowBaseTransform(); + if (ContainerLayer* c = layer->AsContainerLayer()) { + // Undo the scale transform applied by AsyncCompositionManager::SampleValue + transform.PostScale(1.0f/c->GetInheritedXScale(), + 1.0f/c->GetInheritedYScale(), + 1.0f); + } + float scale = 1; + Point3D scaledOrigin; + Point3D transformOrigin; + for (uint32_t i=0; i < layer->GetAnimations().Length(); i++) { + if (layer->GetAnimations()[i].data().type() == AnimationData::TTransformData) { + const TransformData& data = layer->GetAnimations()[i].data().get_TransformData(); + scale = data.appUnitsPerDevPixel(); + scaledOrigin = + Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)), + NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), + 0.0f); + transformOrigin = data.transformOrigin(); + break; + } + } + + // If our parent isn't a perspective layer, then the offset into reference + // frame coordinates will have been applied to us. Add an inverse translation + // to cancel it out. + if (!layer->GetParent() || !layer->GetParent()->GetTransformIsPerspective()) { + transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z); + } + + // Undo the rebasing applied by + // nsDisplayTransform::GetResultingTransformMatrixInternal + transform.ChangeBasis(-transformOrigin); + + // Convert to CSS pixels (this undoes the operations performed by + // nsStyleTransformMatrix::ProcessTranslatePart which is called from + // nsDisplayTransform::GetResultingTransformMatrix) + double devPerCss = + double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel()); + transform._41 *= devPerCss; + transform._42 *= devPerCss; + transform._43 *= devPerCss; + + *aTransform = transform; + return true; +} + +static AsyncPanZoomController* +GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID) +{ + AsyncPanZoomController* resultApzc = nullptr; + ForEachNode<ForwardIterator>( + aLayer, + [aScrollID, &resultApzc] (Layer* layer) + { + for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) { + if (layer->GetFrameMetrics(i).GetScrollId() == aScrollID) { + resultApzc = layer->GetAsyncPanZoomController(i); + return TraversalFlag::Abort; + } + } + return TraversalFlag::Continue; + }); + return resultApzc; +} + +bool +LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID, + const float& aX, const float& aY) +{ + if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + return false; + } + + AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID); + if (!controller) { + return false; + } + controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY)); + return true; +} + +bool +LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID, + const float& aValue) +{ + if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { + return false; + } + + AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID); + if (!controller) { + return false; + } + controller->SetTestAsyncZoom(LayerToParentLayerScale(aValue)); + return true; +} + +bool +LayerTransactionParent::RecvFlushApzRepaints() +{ + mCompositorBridge->FlushApzRepaints(this); + return true; +} + +bool +LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData) +{ + mCompositorBridge->GetAPZTestData(this, aOutData); + return true; +} + +bool +LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue) +{ + if (aProperty.Equals(NS_LITERAL_STRING("overdraw"))) { + *aValue = layer_manager()->GetCompositor()->GetFillRatio(); + } else if (aProperty.Equals(NS_LITERAL_STRING("missed_hwc"))) { + *aValue = layer_manager()->LastFrameMissedHWC() ? 1 : 0; + } else { + *aValue = -1; + } + return true; +} + +bool +LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId, + nsTArray<ScrollableLayerGuid>&& aTargets) +{ + mCompositorBridge->SetConfirmedTargetAPZC(this, aBlockId, aTargets); + return true; +} + +bool +LayerTransactionParent::Attach(ShadowLayerParent* aLayerParent, + CompositableHost* aCompositable, + bool aIsAsync) +{ + if (!aCompositable) { + return false; + } + + Layer* baselayer = aLayerParent->AsLayer(); + if (!baselayer) { + return false; + } + LayerComposite* layer = baselayer->AsLayerComposite(); + if (!layer) { + return false; + } + + Compositor* compositor + = static_cast<LayerManagerComposite*>(aLayerParent->AsLayer()->Manager())->GetCompositor(); + + if (!layer->SetCompositableHost(aCompositable)) { + // not all layer types accept a compositable, see bug 967824 + return false; + } + aCompositable->Attach(aLayerParent->AsLayer(), + compositor, + aIsAsync + ? CompositableHost::ALLOW_REATTACH + | CompositableHost::KEEP_ATTACHED + : CompositableHost::NO_FLAGS); + return true; +} + +bool +LayerTransactionParent::RecvClearCachedResources() +{ + if (mRoot) { + // NB: |mRoot| here is the *child* context's root. In this parent + // context, it's just a subtree root. We need to scope the clear + // of resources to exactly that subtree, so we specify it here. + mLayerManager->ClearCachedResources(mRoot); + } + mCompositorBridge->NotifyClearCachedResources(this); + return true; +} + +bool +LayerTransactionParent::RecvForceComposite() +{ + mCompositorBridge->ForceComposite(this); + return true; +} + +PLayerParent* +LayerTransactionParent::AllocPLayerParent() +{ + return new ShadowLayerParent(); +} + +bool +LayerTransactionParent::DeallocPLayerParent(PLayerParent* actor) +{ + delete actor; + return true; +} + +PCompositableParent* +LayerTransactionParent::AllocPCompositableParent(const TextureInfo& aInfo) +{ + return CompositableHost::CreateIPDLActor(this, aInfo, 0); +} + +bool +LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor) +{ + return CompositableHost::DestroyIPDLActor(aActor); +} + +void +LayerTransactionParent::ActorDestroy(ActorDestroyReason why) +{ +} + +bool +LayerTransactionParent::AllocShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + if (!mIPCOpen || mDestroyed) { + return false; + } + return PLayerTransactionParent::AllocShmem(aSize, aType, aShmem); +} + +bool +LayerTransactionParent::AllocUnsafeShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + if (!mIPCOpen || mDestroyed) { + return false; + } + + return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem); +} + +void +LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem) +{ + if (!mIPCOpen || mDestroyed) { + return; + } + PLayerTransactionParent::DeallocShmem(aShmem); +} + +bool LayerTransactionParent::IsSameProcess() const +{ + return OtherPid() == base::GetCurrentProcId(); +} + +void +LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) +{ + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); +} + +void +LayerTransactionParent::SendPendingAsyncMessages() +{ + mCompositorBridge->SendPendingAsyncMessages(); +} + +void +LayerTransactionParent::SetAboutToSendAsyncMessages() +{ + mCompositorBridge->SetAboutToSendAsyncMessages(); +} + +void +LayerTransactionParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) +{ + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); +} + +} // namespace layers +} // namespace mozilla |