diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index c6f3a248a82a3..a9d8dfec98620 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -8,6 +8,7 @@ #include "MobileViewportManager.h" #include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "nsPresContext.h" #include "nsCaret.h" #include "nsContentList.h" diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index 86a5cc876c1c7..af5d09df135b3 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -20,6 +20,7 @@ #include "mozilla/ipc/Shmem.h" #include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/OOPCanvasRenderer.h" #include "mozilla/layers/TextureClientSharedSurface.h" #include "mozilla/layers/WebRenderUserData.h" diff --git a/dom/canvas/HostWebGLContext.cpp b/dom/canvas/HostWebGLContext.cpp index 9d0b47d9a03e8..e009f1942600d 100644 --- a/dom/canvas/HostWebGLContext.cpp +++ b/dom/canvas/HostWebGLContext.cpp @@ -6,6 +6,7 @@ #include "HostWebGLContext.h" #include "CompositableHost.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/LayersSurfaces.h" #include "MozFramebuffer.h" diff --git a/dom/canvas/PWebGL.ipdl b/dom/canvas/PWebGL.ipdl index 5403b8c82d413..44086b1746116 100644 --- a/dom/canvas/PWebGL.ipdl +++ b/dom/canvas/PWebGL.ipdl @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PCompositorBridge; +include protocol PLayerTransaction; using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::SurfaceDescriptor from "mozilla/layers/LayersTypes.h"; diff --git a/dom/canvas/WebGLParent.cpp b/dom/canvas/WebGLParent.cpp index d72422b79f024..7042027d9078a 100644 --- a/dom/canvas/WebGLParent.cpp +++ b/dom/canvas/WebGLParent.cpp @@ -6,6 +6,7 @@ #include "WebGLParent.h" #include "WebGLChild.h" +#include "mozilla/layers/LayerTransactionParent.h" #include "mozilla/layers/TextureClientSharedSurface.h" #include "ImageContainer.h" #include "HostWebGLContext.h" diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index 44e24f3937708..5ef18e7479c1f 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -92,6 +92,7 @@ #include "mozilla/layers/IAPZCTreeManager.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/InputAPZContext.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/WebRenderLayerManager.h" #include "nsBrowserStatusFilter.h" #include "nsColorPickerProxy.h" diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index e882460612a09..b20770774d16b 100644 --- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -158,6 +158,7 @@ enum class CompositableType : uint8_t { UNKNOWN, CONTENT_TILED, // tiled painted layer IMAGE, // image with single buffering + IMAGE_BRIDGE, // ImageBridge protocol CONTENT_SINGLE, // painted layer interface, single buffering CONTENT_DOUBLE, // painted layer interface, double buffering COUNT diff --git a/gfx/layers/LayerManager.h b/gfx/layers/LayerManager.h index 97b82b6c549ed..0c7e4d8bad5aa 100644 --- a/gfx/layers/LayerManager.h +++ b/gfx/layers/LayerManager.h @@ -72,6 +72,8 @@ class RefLayer; class HostLayer; class FocusTarget; class KnowsCompositor; +class ShadowableLayer; +class ShadowLayerForwarder; class LayerManagerComposite; class TransactionIdAllocator; class FrameUniformityData; diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index edce6fc97ee94..1451769a8fb49 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -46,6 +46,7 @@ #include "mozilla/layers/LayerManagerComposite.h" // for HostLayer #include "mozilla/layers/LayersMessages.h" // for SpecificLayerAttributes, CompositorAnimations (ptr only), ContainerLayerAt... #include "mozilla/layers/LayersTypes.h" // for EventRegions, operator<<, CompositionPayload, CSSTransformMatrix, MOZ_LAYE... +#include "mozilla/layers/ShadowLayers.h" // for ShadowableLayer #include "nsBaseHashtable.h" // for nsBaseHashtable<>::Iterator, nsBaseHashtable<>::LookupResult #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE #include "nsPrintfCString.h" // for nsPrintfCString @@ -1157,6 +1158,8 @@ void Layer::Dump(std::stringstream& aStream, const char* aPrefix, bool dumpCompositorTexture = gfxEnv::DumpCompositorTextures() && AsHostLayer() && AsHostLayer()->GetCompositableHost(); + bool dumpClientTexture = gfxEnv::DumpPaint() && AsShadowableLayer() && + AsShadowableLayer()->GetCompositableClient(); nsCString layerId(Name()); layerId.Append('-'); layerId.AppendInt((uint64_t)this); @@ -1164,7 +1167,7 @@ void Layer::Dump(std::stringstream& aStream, const char* aPrefix, if (aDumpHtml) { aStream << nsPrintfCString(R"(
  • GetCompositableHost()->Dump(aStream, aPrefix, aDumpHtml); + } else if (dumpClientTexture) { + if (aDumpHtml) { + aStream << nsPrintfCString(R"()"; + } } #endif if (aDumpHtml) { aStream << ""; +#ifdef MOZ_DUMP_PAINTING + if (dumpClientTexture) { + aStream << nsPrintfCString("
    \n", + layerId.BeginReading()) + .get(); + } +#endif } if (Layer* mask = GetMaskLayer()) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 6b7495f1b0cba..8440406df30b5 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -74,6 +74,7 @@ class CompositorAnimations; class CanvasLayer; class RefLayer; class HostLayer; +class ShadowableLayer; class SpecificLayerAttributes; class Compositor; class TransformData; @@ -917,6 +918,12 @@ class Layer { */ virtual HostLayer* AsHostLayer() { return nullptr; } + /** + * Dynamic cast to a ShadowableLayer. Return null if this is not a + * ShadowableLayer. Can be used anytime. + */ + virtual ShadowableLayer* AsShadowableLayer() { return nullptr; } + // These getters can be used anytime. They return the effective // values that should be used when drawing this layer to screen, // accounting for this layer possibly being a shadow. diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index f6523e33212f2..c9a63fcc5ced3 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -23,7 +23,12 @@ #endif #define MOZ_LAYERS_LOG(_args) \ MOZ_LOG(LayerManager::GetLog(), LogLevel::Debug, _args) -#define MOZ_LAYERS_LOG_IF_SHADOWABLE(layer, _args) +#define MOZ_LAYERS_LOG_IF_SHADOWABLE(layer, _args) \ + do { \ + if (layer->AsShadowableLayer()) { \ + MOZ_LOG(LayerManager::GetLog(), LogLevel::Debug, _args); \ + } \ + } while (0) #define INVALID_OVERLAY -1 diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index e214489351f79..0c64c6a756083 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -7,8 +7,8 @@ #include "PersistentBufferProvider.h" #include "Layers.h" +#include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/TextureClient.h" -#include "mozilla/layers/TextureForwarder.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Logging.h" #include "mozilla/Maybe.h" diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 08f92df085dd0..f5e7b160b3cdd 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -69,6 +69,7 @@ #include "mozilla/layers/APZUtils.h" // for AsyncTransform #include "mozilla/layers/CompositorController.h" // for CompositorController #include "mozilla/layers/DirectionUtils.h" // for GetAxis{Start,End,Length,Scale} +#include "mozilla/layers/LayerTransactionParent.h" // for LayerTransactionParent #include "mozilla/layers/MetricsSharingController.h" // for MetricsSharingController #include "mozilla/mozalloc.h" // for operator new, etc #include "mozilla/Unused.h" // for unused @@ -3659,6 +3660,7 @@ Maybe AsyncPanZoomController::GetCurrentAnimationDestination( ParentLayerPoint AsyncPanZoomController::AdjustHandoffVelocityForOverscrollBehavior( ParentLayerPoint& aHandoffVelocity) const { + ParentLayerPoint residualVelocity; ScrollDirections handoffDirections = GetAllowedHandoffDirections(); if (!handoffDirections.contains(ScrollDirection::eHorizontal)) { diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index 89b4df6da41ce..1230840e3e510 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -14,6 +14,7 @@ #include "mozilla/dom/MouseEventBinding.h" #include "mozilla/dom/BrowserParent.h" #include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/RepaintRequest.h" #include "mozilla/layers/WebRenderLayerManager.h" #include "mozilla/layers/WebRenderBridgeChild.h" diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index 9f4216b4a2d2a..d5ad5c26e48d8 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -23,8 +23,8 @@ #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc #include "mozilla/layers/ISurfaceAllocator.h" -#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc -#include "mozilla/layers/TextureForwarder.h" +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder #include "mozilla/layers/TextureClient.h" // for TextureClient, etc #include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient #include "mozilla/mozalloc.h" // for operator delete, etc @@ -48,6 +48,9 @@ already_AddRefed ImageClient::CreateImageClient( result = new ImageClientSingle(aForwarder, aFlags, CompositableType::IMAGE); break; + case CompositableType::IMAGE_BRIDGE: + result = new ImageClientBridge(aForwarder, aFlags); + break; case CompositableType::UNKNOWN: result = nullptr; break; @@ -274,5 +277,29 @@ ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags, mType(aType), mLastUpdateGenerationCounter(0) {} +ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd, + TextureFlags aFlags) + : ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE) {} + +bool ImageClientBridge::UpdateImage(ImageContainer* aContainer, + uint32_t aContentFlags) { + if (!GetForwarder() || !mLayer) { + return false; + } + if (mAsyncContainerHandle == aContainer->GetAsyncContainerHandle()) { + return true; + } + + mAsyncContainerHandle = aContainer->GetAsyncContainerHandle(); + if (!mAsyncContainerHandle) { + // If we couldn't contact a working ImageBridgeParent, just return. + return true; + } + + static_cast(GetForwarder()) + ->AttachAsyncCompositable(mAsyncContainerHandle, mLayer); + return true; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/client/ImageClient.h b/gfx/layers/client/ImageClient.h index 77f3e57c5d9d8..19b169c132968 100644 --- a/gfx/layers/client/ImageClient.h +++ b/gfx/layers/client/ImageClient.h @@ -118,6 +118,24 @@ class ImageClientSingle : public ImageClient { nsTArray mBuffers; }; +/** + * Image class to be used for async image uploads using the image bridge + * protocol. + * We store the ImageBridge id in the TextureClientIdentifier. + */ +class ImageClientBridge : public ImageClient { + public: + ImageClientBridge(CompositableForwarder* aFwd, TextureFlags aFlags); + + bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override; + bool Connect(ImageContainer* aImageContainer) override { return false; } + + TextureInfo GetTextureInfo() const override { return TextureInfo(mType); } + + protected: + CompositableHandle mAsyncContainerHandle; +}; + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index f1cff13f4b913..fe7c75ebebc89 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -33,6 +33,7 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/PTextureChild.h" +#include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/TextureClientOGL.h" #include "mozilla/layers/TextureClientRecycleAllocator.h" #include "mozilla/layers/TextureRecorded.h" @@ -1033,6 +1034,13 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return false; } + if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) { + // Do the DOM labeling. + if (nsISerialEventTarget* target = forwarder->GetEventTarget()) { + forwarder->GetCompositorBridgeChild()->ReplaceEventTargetForActor( + mActor, target); + } + } mActor->mCompositableForwarder = aForwarder; mActor->mUsesImageBridge = aForwarder->GetTextureForwarder()->UsesImageBridge(); @@ -1051,6 +1059,12 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) { mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId(); + nsISerialEventTarget* target = nullptr; + // Get the layers id if the forwarder is a ShadowLayerForwarder. + if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) { + target = forwarder->GetEventTarget(); + } + ReadLockDescriptor readLockDescriptor = null_t(); if (mReadLock) { mReadLock->Serialize(readLockDescriptor, GetAllocator()->GetParentPid()); @@ -1058,7 +1072,7 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) { PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture( desc, readLockDescriptor, aForwarder->GetCompositorBackendType(), - GetFlags(), mSerial, mExternalImageId, nullptr); + GetFlags(), mSerial, mExternalImageId, target); if (!actor) { gfxCriticalNote << static_cast(desc.type()) << ", " diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index d229ca791869c..056f26de04a21 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -110,6 +110,9 @@ already_AddRefed CompositableHost::Create( const TextureInfo& aTextureInfo, bool aUseWebRender) { RefPtr result; switch (aTextureInfo.mCompositableType) { + case CompositableType::IMAGE_BRIDGE: + NS_ERROR("Cannot create an image bridge compositable this way"); + break; case CompositableType::CONTENT_TILED: result = new TiledContentHost(aTextureInfo); break; diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 45c8bdac2c6f8..412af3e859e63 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -22,6 +22,7 @@ class CompositableClient; class CompositableHandle; class ImageContainer; class PTextureChild; +class ShadowLayerForwarder; class SurfaceDescriptorTiles; class TextureClient; class ThebesBufferData; @@ -111,6 +112,8 @@ class CompositableForwarder : public KnowsCompositor { static uint32_t GetMaxFileDescriptorsPerMessage(); + virtual ShadowLayerForwarder* AsLayerForwarder() { return nullptr; } + protected: nsTArray> mTexturesToRemove; nsTArray> mCompositableClientsToRemove; diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index a809069f1c5e0..ed2d28a1c311a 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -17,6 +17,8 @@ #include "mozilla/layers/APZCTreeManagerChild.h" #include "mozilla/layers/CanvasChild.h" #include "mozilla/layers/LayerManager.h" +#include "mozilla/layers/LayerTransactionChild.h" +#include "mozilla/layers/PLayerTransactionChild.h" #include "mozilla/layers/PTextureChild.h" #include "mozilla/layers/TextureClient.h" // for TextureClient #include "mozilla/layers/TextureClientPool.h" // for TextureClientPool @@ -55,6 +57,7 @@ using mozilla::Unused; using mozilla::gfx::GPUProcessManager; +using mozilla::layers::LayerTransactionChild; namespace mozilla { namespace layers { @@ -170,6 +173,14 @@ void CompositorBridgeChild::Destroy() { return; } + AutoTArray transactions; + ManagedPLayerTransactionChild(transactions); + for (int i = transactions.Length() - 1; i >= 0; --i) { + RefPtr layers = + static_cast(transactions[i]); + layers->Destroy(); + } + AutoTArray wrBridges; ManagedPWebRenderBridgeChild(wrBridges); for (int i = wrBridges.Length() - 1; i >= 0; --i) { @@ -303,6 +314,22 @@ bool CompositorBridgeChild::CompositorIsInGPUProcess() { return bridge->OtherPid() != dom::ContentChild::GetSingleton()->OtherPid(); } +PLayerTransactionChild* CompositorBridgeChild::AllocPLayerTransactionChild( + const nsTArray& aBackendHints, const LayersId& aId) { + LayerTransactionChild* c = new LayerTransactionChild(aId); + c->AddIPDLReference(); + + return c; +} + +bool CompositorBridgeChild::DeallocPLayerTransactionChild( + PLayerTransactionChild* actor) { + LayersId childId = static_cast(actor)->GetId(); + ClearSharedFrameMetricsData(childId); + static_cast(actor)->ReleaseIPDLReference(); + return true; +} + mozilla::ipc::IPCResult CompositorBridgeChild::RecvInvalidateLayers( const LayersId& aLayersId) { if (mLayerManager) { diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h index abf0476c0dd62..45c6b9beb8087 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -241,6 +241,11 @@ class CompositorBridgeChild final : public PCompositorBridgeChild, void PrepareFinalDestroy(); void AfterDestroy(); + PLayerTransactionChild* AllocPLayerTransactionChild( + const nsTArray& aBackendHints, const LayersId& aId); + + bool DeallocPLayerTransactionChild(PLayerTransactionChild* aChild); + void ActorDestroy(ActorDestroyReason aWhy) override; mozilla::ipc::IPCResult RecvSharedCompositorFrameMetrics( diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index e901099c76365..14889396fa7d0 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -12,6 +12,7 @@ #include // for pair #include "apz/src/APZCTreeManager.h" // for APZCTreeManager +#include "LayerTransactionParent.h" // for LayerTransactionParent #include "RenderTrace.h" // for RenderTraceLayers #include "base/process.h" // for ProcessId #include "gfxContext.h" // for gfxContext @@ -56,6 +57,7 @@ #include "mozilla/layers/LayerTreeOwnerTracker.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/OMTASampler.h" +#include "mozilla/layers/PLayerTransactionParent.h" #include "mozilla/layers/RemoteContentController.h" #include "mozilla/layers/UiCompositorControllerParent.h" #include "mozilla/layers/WebRenderBridgeParent.h" @@ -222,7 +224,8 @@ CompositorBridgeParent::LayerTreeState::LayerTreeState() : mApzcTreeManagerParent(nullptr), mParent(nullptr), mLayerManager(nullptr), - mContentCompositorBridgeParent(nullptr) {} + mContentCompositorBridgeParent(nullptr), + mLayerTree(nullptr) {} CompositorBridgeParent::LayerTreeState::~LayerTreeState() { if (mController) { @@ -773,6 +776,27 @@ void CompositorBridgeParent::ResumeCompositionAndResize(int x, int y, int width, ResumeComposition(); } +void CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, + const TimeDuration& aPaintTime) { + // We get a lot of paint timings for things with empty transactions. + if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) { + return; + } + + mLayerManager->SetPaintTime(aPaintTime); +} + +void CompositorBridgeParent::RegisterPayloads( + LayerTransactionParent* aLayerTree, + const nsTArray& aPayload) { + // We get a lot of paint timings for things with empty transactions. + if (!mLayerManager) { + return; + } + + mLayerManager->RegisterPayloads(aPayload); +} + void CompositorBridgeParent::NotifyShadowTreeTransaction( LayersId aId, bool aIsFirstPaint, const FocusTarget& aFocusTarget, bool aScheduleComposite, uint32_t aPaintSequenceNumber, @@ -839,6 +863,107 @@ void CompositorBridgeParent::SetShadowProperties(Layer* aLayer) { }); } +void CompositorBridgeParent::CompositeToTarget(VsyncId aId, DrawTarget* aTarget, + const gfx::IntRect* aRect) { + AUTO_PROFILER_TRACING_MARKER("Paint", "Composite", GRAPHICS); + AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget", GRAPHICS); + PerfStats::AutoMetricRecording autoRecording; + + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(), + "Composite can only be called on the compositor thread"); + TimeStamp start = TimeStamp::Now(); + + if (!CanComposite()) { + TimeStamp end = TimeStamp::Now(); + DidComposite(aId, start, end); + return; + } + + AutoResolveRefLayers resolve(mCompositionManager, this); + + nsCString none; + if (aTarget) { + mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); + } else { + mLayerManager->BeginTransaction(none); + } + + SetShadowProperties(mLayerManager->GetRoot()); + + if (mForceCompositionTask && !mOverrideComposeReadiness) { + if (mCompositionManager->ReadyForCompose()) { + mForceCompositionTask->Cancel(); + mForceCompositionTask = nullptr; + } else { + return; + } + } + + mCompositionManager->ComputeRotation(); + + SampleTime time = mTestTime ? SampleTime::FromTest(*mTestTime) + : mCompositorScheduler->GetLastComposeTime(); + bool requestNextFrame = + mCompositionManager->TransformShadowTree(time, mVsyncRate); + + if (requestNextFrame) { + ScheduleComposition(); + } + + RenderTraceLayers(mLayerManager->GetRoot(), "0000"); + + if (StaticPrefs::layers_dump_host_layers() || StaticPrefs::layers_dump()) { + printf_stderr("Painting --- compositing layer tree:\n"); + mLayerManager->Dump(/* aSorted = */ true); + } + mLayerManager->SetDebugOverlayWantsNextFrame(false); + mLayerManager->EndTransaction(time.Time()); + + if (!aTarget) { + TimeStamp end = TimeStamp::Now(); + DidComposite(aId, start, end); + } + + // We're not really taking advantage of the stored composite-again-time here. + // We might be able to skip the next few composites altogether. However, + // that's a bit complex to implement and we'll get most of the advantage + // by skipping compositing when we detect there's nothing invalid. This is why + // we do "composite until" rather than "composite again at". + // + // TODO(bug 1328602) Figure out what we should do here with the render thread. + if (!mLayerManager->GetCompositeUntilTime().IsNull() || + mLayerManager->DebugOverlayWantsNextFrame()) { + ScheduleComposition(); + } + +#ifdef COMPOSITOR_PERFORMANCE_WARNING + TimeDuration executionTime = + TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime().Time(); + TimeDuration frameBudget = TimeDuration::FromMilliseconds(15); + int32_t frameRate = 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 composite + if (StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 || + mLayerManager->AlwaysScheduleComposite()) { + // Special full-tilt composite mode for performance testing + ScheduleComposition(); + } + + // TODO(bug 1328602) Need an equivalent that works with the rende thread. + mLayerManager->SetCompositionTime(TimeStamp()); + + mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, + start); +} + void CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect) { AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS); @@ -991,6 +1116,68 @@ void CompositorBridgeParent::ScheduleRotationOnCompositorThread( } } +void CompositorBridgeParent::ShadowLayersUpdated( + LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo, + bool aHitTestUpdate) { + const TargetConfig& targetConfig = aInfo.targetConfig(); + + ScheduleRotationOnCompositorThread(targetConfig, aInfo.isFirstPaint()); + + // 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(targetConfig.naturalBounds()); + mLayerManager->SetRegionToClear(targetConfig.clearRegion()); + if (mLayerManager->GetCompositor()) { + mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation()); + } + + mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig); + Layer* root = aLayerTree->GetRoot(); + mLayerManager->SetRoot(root); + + if (mApzUpdater && !aInfo.isRepeatTransaction()) { + mApzUpdater->UpdateFocusState(mRootLayerTreeID, mRootLayerTreeID, + aInfo.focusTarget()); + + if (aHitTestUpdate) { + AutoResolveRefLayers resolve(mCompositionManager); + + mApzUpdater->UpdateHitTestingTree(root, aInfo.isFirstPaint(), + mRootLayerTreeID, + aInfo.paintSequenceNumber()); + } + } + + // The transaction ID might get reset to 1 if the page gets reloaded, see + // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41 + // Otherwise, it should be continually increasing. + MOZ_ASSERT(aInfo.id() == TransactionId{1} || mPendingTransactions.IsEmpty() || + aInfo.id() > mPendingTransactions.LastElement()); + mPendingTransactions.AppendElement(aInfo.id()); + mRefreshStartTime = aInfo.refreshStart(); + mTxnStartTime = aInfo.transactionStart(); + mFwdTime = aInfo.fwdTime(); + RegisterPayloads(aLayerTree, aInfo.payload()); + + if (root) { + SetShadowProperties(root); + } + if (aInfo.scheduleComposite()) { + ScheduleComposition(); + if (mPaused) { + TimeStamp now = TimeStamp::Now(); + DidComposite(VsyncId(), now, now); + } + } + mLayerManager->NotifyShadowTreeTransaction(); +} + +void CompositorBridgeParent::ScheduleComposite( + LayerTransactionParent* aLayerTree) { + ScheduleComposition(); +} + bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); @@ -1035,6 +1222,34 @@ void CompositorBridgeParent::LeaveTestMode(const LayersId& aId) { } } +void CompositorBridgeParent::ApplyAsyncProperties( + LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) { + // NOTE: This should only be used for testing. For example, when mTestTime is + // non-empty, or when called from test-only methods like + // LayerTransactionParent::RecvGetAnimationTransform. + + // Synchronously update the layer tree + if (aLayerTree->GetRoot()) { + AutoResolveRefLayers resolve(mCompositionManager); + SetShadowProperties(mLayerManager->GetRoot()); + + SampleTime time; + if (mTestTime) { + time = SampleTime::FromTest(*mTestTime); + } else { + time = mCompositorScheduler->GetLastComposeTime(); + } + bool requestNextFrame = + mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip); + if (!requestNextFrame) { + CancelCurrentCompositeTask(); + // Pretend we composited in case someone is waiting for this event. + TimeStamp now = TimeStamp::Now(); + DidComposite(VsyncId(), now, now); + } + } +} + CompositorAnimationStorage* CompositorBridgeParent::GetAnimationStorage() { if (!mAnimationStorage) { mAnimationStorage = new CompositorAnimationStorage(this); @@ -1132,8 +1347,8 @@ void CompositorBridgeParent::SetConfirmedTargetAPZC( void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop, ScreenIntCoord aBottom) { - if (mCompositionManager) { - mCompositionManager->SetFixedLayerMargins(aTop, aBottom); + if (AsyncCompositionManager* manager = GetCompositionManager(nullptr)) { + manager->SetFixedLayerMargins(aTop, aBottom); } if (mApzcTreeManager) { @@ -1239,6 +1454,44 @@ RefPtr CompositorBridgeParent::NewCompositor( return nullptr; } +PLayerTransactionParent* CompositorBridgeParent::AllocPLayerTransactionParent( + const nsTArray& aBackendHints, const LayersId& aId) { + MOZ_ASSERT(!aId.IsValid()); + +#ifdef XP_WIN + // This is needed to avoid freezing the window on a device crash on double + // buffering, see bug 1549674. + if (gfxVars::UseDoubleBufferingWithCompositor() && XRE_IsGPUProcess() && + aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) { + mWidget->AsWindows()->EnsureCompositorWindow(); + } +#endif + + InitializeLayerManager(aBackendHints); + + if (!mLayerManager) { + NS_WARNING("Failed to initialise Compositor"); + LayerTransactionParent* p = new LayerTransactionParent( + /* aManager */ nullptr, this, /* aAnimStorage */ nullptr, + mRootLayerTreeID, mVsyncRate); + p->AddIPDLReference(); + return p; + } + + mCompositionManager = new AsyncCompositionManager(this, mLayerManager); + + LayerTransactionParent* p = new LayerTransactionParent( + mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate); + p->AddIPDLReference(); + return p; +} + +bool CompositorBridgeParent::DeallocPLayerTransactionParent( + PLayerTransactionParent* actor) { + static_cast(actor)->ReleaseIPDLReference(); + return true; +} + CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent( uint64_t id) { AssertIsInCompositorThread(); @@ -1423,6 +1676,14 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild( oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater; } NotifyChildCreated(child); + if (sIndirectLayerTrees[child].mLayerTree) { + sIndirectLayerTrees[child].mLayerTree->SetLayerManager( + mLayerManager, GetAnimationStorage()); + // Trigger composition to handle a case that mLayerTree was not composited + // yet by previous CompositorBridgeParent, since nsRefreshDriver might + // wait composition complete. + scheduleComposition = true; + } if (mWrBridge) { childWrBridge = sIndirectLayerTrees[child].mWrBridge; } @@ -1884,6 +2145,22 @@ bool CompositorBridgeParent::DeallocPCompositorWidgetParent( #endif } +bool CompositorBridgeParent::IsPendingComposite() { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + if (!mCompositor) { + return false; + } + return mCompositor->IsPendingComposite(); +} + +void CompositorBridgeParent::FinishPendingComposite() { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + if (!mCompositor) { + return; + } + return mCompositor->FinishPendingComposite(); +} + CompositorController* CompositorBridgeParent::LayerTreeState::GetCompositorController() const { return mParent; diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 7c73cdd9354a0..dd9fdbf6ccd48 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -90,6 +90,7 @@ class GeckoContentController; class HostLayerManager; class IAPZCTreeManager; class Layer; +class LayerTransactionParent; class OMTASampler; class ContentCompositorBridgeParent; class CompositorThreadHolder; @@ -121,11 +122,25 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, public: explicit CompositorBridgeParentBase(CompositorManagerParent* aManager); + virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, + const TransactionInfo& aInfo, + bool aHitTestUpdate) = 0; + + virtual AsyncCompositionManager* GetCompositionManager( + LayerTransactionParent* aLayerTree) { + return nullptr; + } + + virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) {} + + virtual void ScheduleComposite(LayerTransactionParent* aLayerTree) {} virtual bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) { return true; } virtual void LeaveTestMode(const LayersId& aId) {} enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 }; + virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree, + TransformsToSkip aSkip) = 0; virtual void SetTestAsyncScrollOffset( const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId, const CSSPoint& aPoint) = 0; @@ -140,6 +155,10 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, virtual void SetConfirmedTargetAPZC( const LayersId& aLayersId, const uint64_t& aInputBlockId, nsTArray&& aTargets) = 0; + virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, + const TimeDuration& aPaintTime) {} + virtual void RegisterPayloads(LayerTransactionParent* aLayerTree, + const nsTArray& aPayload) {} IShmemAllocator* AsShmemAllocator() override { return this; } @@ -211,6 +230,12 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, virtual bool DeallocPAPZCTreeManagerParent( PAPZCTreeManagerParent* aActor) = 0; + virtual PLayerTransactionParent* AllocPLayerTransactionParent( + const nsTArray& layersBackendHints, + const LayersId& id) = 0; + virtual bool DeallocPLayerTransactionParent( + PLayerTransactionParent* aActor) = 0; + virtual PTextureParent* AllocPTextureParent( const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock, const LayersBackend& aBackend, const TextureFlags& aTextureFlags, @@ -283,7 +308,8 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS( CompositorBridgeParentBase::TransformsToSkip) class CompositorBridgeParent final : public CompositorBridgeParentBase, - public CompositorController { + public CompositorController, + public CompositorVsyncSchedulerOwner { friend class CompositorThreadHolder; friend class InProcessCompositorSession; friend class gfx::GPUProcessManager; @@ -358,8 +384,14 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, void ActorDestroy(ActorDestroyReason why) override; + void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, + const TransactionInfo& aInfo, + bool aHitTestUpdate) override; + void ScheduleComposite(LayerTransactionParent* aLayerTree) override; bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) override; void LeaveTestMode(const LayersId& aId) override; + void ApplyAsyncProperties(LayerTransactionParent* aLayerTree, + TransformsToSkip aSkip) override; CompositorAnimationStorage* GetAnimationStorage(); using JankedAnimations = std::unordered_map, LayersId::HashFn>; @@ -378,6 +410,10 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, void SetConfirmedTargetAPZC( const LayersId& aLayersId, const uint64_t& aInputBlockId, nsTArray&& aTargets) override; + AsyncCompositionManager* GetCompositionManager( + LayerTransactionParent* aLayerTree) override { + return mCompositionManager; + } void SetFixedLayerMargins(ScreenIntCoord aTop, ScreenIntCoord aBottom); PTextureParent* AllocPTextureParent( @@ -443,6 +479,11 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, bool aIsRepeatTransaction, bool aHitTestUpdate); + void UpdatePaintTime(LayerTransactionParent* aLayerTree, + const TimeDuration& aPaintTime) override; + void RegisterPayloads(LayerTransactionParent* aLayerTree, + const nsTArray& aPayload) override; + /** * Check rotation info and schedule a rendering task if needed. * Only can be called from compositor thread. @@ -506,6 +547,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, // the PCompositorBridgeChild ContentCompositorBridgeParent* mContentCompositorBridgeParent; TargetConfig mTargetConfig; + LayerTransactionParent* mLayerTree; CompositorController* GetCompositorController() const; MetricsSharingController* CrossProcessSharingController() const; @@ -574,7 +616,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, CompositorOptions GetOptions() const { return mOptions; } - TimeDuration GetVsyncInterval() const { + TimeDuration GetVsyncInterval() const override { // the variable is called "rate" but really it's an interval return mVsyncRate; } @@ -665,6 +707,12 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, void DeferredDestroy(); + PLayerTransactionParent* AllocPLayerTransactionParent( + const nsTArray& aBackendHints, + const LayersId& aId) override; + bool DeallocPLayerTransactionParent( + PLayerTransactionParent* aLayers) override; + void SetEGLSurfaceRect(int x, int y, int width, int height); void InitializeLayerManager(const nsTArray& aBackendHints); @@ -680,6 +728,12 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, void ForceComposition(); void CancelCurrentCompositeTask(); + // CompositorVsyncSchedulerOwner + bool IsPendingComposite() override; + void FinishPendingComposite() override; + void CompositeToTarget(VsyncId aId, gfx::DrawTarget* aTarget, + const gfx::IntRect* aRect = nullptr) override; + RefPtr NewCompositor( const nsTArray& aBackendHints); diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp index daa7bbad16d9c..454b8487f3ed6 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp @@ -8,6 +8,7 @@ #include // for uint64_t +#include "LayerTransactionParent.h" // for LayerTransactionParent #include "apz/src/APZCTreeManager.h" // for APZCTreeManager #include "gfxUtils.h" #ifdef XP_WIN @@ -24,6 +25,7 @@ #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/LayerTreeOwnerTracker.h" +#include "mozilla/layers/PLayerTransactionParent.h" #include "mozilla/layers/RemoteContentController.h" #include "mozilla/layers/WebRenderBridgeParent.h" #include "mozilla/layers/AsyncImagePipelineManager.h" @@ -61,6 +63,57 @@ void ContentCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { &ContentCompositorBridgeParent::DeferredDestroy)); } +PLayerTransactionParent* +ContentCompositorBridgeParent::AllocPLayerTransactionParent( + const nsTArray&, const LayersId& aId) { + MOZ_ASSERT(aId.IsValid()); + + // 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->mContentCompositorBridgeParent = this; + HostLayerManager* lm = state->mLayerManager; + CompositorAnimationStorage* animStorage = + state->mParent ? state->mParent->GetAnimationStorage() : nullptr; + TimeDuration vsyncRate = + state->mParent ? state->mParent->GetVsyncInterval() : TimeDuration(); + LayerTransactionParent* p = + new LayerTransactionParent(lm, this, animStorage, aId, vsyncRate); + p->AddIPDLReference(); + sIndirectLayerTrees[aId].mLayerTree = p; + return p; + } + + NS_WARNING("Created child without a matching parent?"); + LayerTransactionParent* p = new LayerTransactionParent( + /* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId, + TimeDuration()); + p->AddIPDLReference(); + return p; +} + +bool ContentCompositorBridgeParent::DeallocPLayerTransactionParent( + PLayerTransactionParent* aLayers) { + LayerTransactionParent* slp = static_cast(aLayers); + EraseLayerState(slp->GetId()); + static_cast(aLayers)->ReleaseIPDLReference(); + return true; +} + PAPZCTreeManagerParent* ContentCompositorBridgeParent::AllocPAPZCTreeManagerParent( const LayersId& aLayersId) { @@ -267,15 +320,104 @@ mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvCheckContentOnlyTDR( return IPC_OK(); }; +void ContentCompositorBridgeParent::ShadowLayersUpdated( + LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo, + bool aHitTestUpdate) { + LayersId id = aLayerTree->GetId(); + + MOZ_ASSERT(id.IsValid()); + + CompositorBridgeParent::LayerTreeState* state = + CompositorBridgeParent::GetIndirectShadowTree(id); + if (!state) { + return; + } + MOZ_ASSERT(state->mParent); + state->mParent->ScheduleRotationOnCompositorThread(aInfo.targetConfig(), + aInfo.isFirstPaint()); + + Layer* shadowRoot = aLayerTree->GetRoot(); + if (shadowRoot) { + CompositorBridgeParent::SetShadowProperties(shadowRoot); + } + UpdateIndirectTree(id, shadowRoot, aInfo.targetConfig()); + + state->mParent->NotifyShadowTreeTransaction( + id, aInfo.isFirstPaint(), aInfo.focusTarget(), aInfo.scheduleComposite(), + aInfo.paintSequenceNumber(), aInfo.isRepeatTransaction(), aHitTestUpdate); + + 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->SendObserveLayersUpdate( + id, aLayerTree->GetChildEpoch(), true); + } + + auto endTime = TimeStamp::Now(); + if (profiler_can_accept_markers()) { + profiler_add_marker( + "CONTENT_FULL_PAINT_TIME", geckoprofiler::category::GRAPHICS, + MarkerTiming::Interval(aInfo.transactionStart(), endTime), + baseprofiler::markers::ContentBuildMarker{}); + } + Telemetry::Accumulate( + Telemetry::CONTENT_FULL_PAINT_TIME, + static_cast( + (endTime - aInfo.transactionStart()).ToMilliseconds())); + + RegisterPayloads(aLayerTree, aInfo.payload()); + + aLayerTree->SetPendingTransactionId( + aInfo.id(), aInfo.vsyncId(), aInfo.vsyncStart(), aInfo.refreshStart(), + aInfo.transactionStart(), endTime, aInfo.containsSVG(), aInfo.url(), + aInfo.fwdTime()); +} + void ContentCompositorBridgeParent::DidCompositeLocked( LayersId aId, const VsyncId& aVsyncId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) { sIndirectLayerTreesLock->AssertCurrentThreadOwns(); - if (sIndirectLayerTrees[aId].mWrBridge) { + if (LayerTransactionParent* layerTree = sIndirectLayerTrees[aId].mLayerTree) { + nsTArray transactions; + layerTree->FlushPendingTransactions(aVsyncId, aCompositeEnd, transactions); + if (!transactions.IsEmpty()) { + Unused << SendDidComposite(aId, transactions, aCompositeStart, + aCompositeEnd); + } + } else if (sIndirectLayerTrees[aId].mWrBridge) { MOZ_ASSERT(false); // this should never get called for a WR compositor } } +void ContentCompositorBridgeParent::ScheduleComposite( + LayerTransactionParent* aLayerTree) { + LayersId id = aLayerTree->GetId(); + MOZ_ASSERT(id.IsValid()); + CompositorBridgeParent* parent; + { // scope lock + MonitorAutoLock lock(*sIndirectLayerTreesLock); + parent = sIndirectLayerTrees[id].mParent; + } + if (parent) { + parent->ScheduleComposite(aLayerTree); + } +} + +void ContentCompositorBridgeParent::NotifyClearCachedResources( + LayerTransactionParent* aLayerTree) { + LayersId id = aLayerTree->GetId(); + MOZ_ASSERT(id.IsValid()); + + 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->SendObserveLayersUpdate( + id, aLayerTree->GetChildEpoch(), false); + } +} + bool ContentCompositorBridgeParent::SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) { MOZ_ASSERT(aId.IsValid()); @@ -301,6 +443,20 @@ void ContentCompositorBridgeParent::LeaveTestMode(const LayersId& aId) { state->mParent->LeaveTestMode(aId); } +void ContentCompositorBridgeParent::ApplyAsyncProperties( + LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) { + LayersId id = aLayerTree->GetId(); + MOZ_ASSERT(id.IsValid()); + const CompositorBridgeParent::LayerTreeState* state = + CompositorBridgeParent::GetIndirectShadowTree(id); + if (!state) { + return; + } + + MOZ_ASSERT(state->mParent); + state->mParent->ApplyAsyncProperties(aLayerTree, aSkip); +} + void ContentCompositorBridgeParent::SetTestAsyncScrollOffset( const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId, const CSSPoint& aPoint) { @@ -379,6 +535,19 @@ void ContentCompositorBridgeParent::SetConfirmedTargetAPZC( std::move(aTargets)); } +AsyncCompositionManager* ContentCompositorBridgeParent::GetCompositionManager( + LayerTransactionParent* aLayerTree) { + LayersId id = aLayerTree->GetId(); + const CompositorBridgeParent::LayerTreeState* state = + CompositorBridgeParent::GetIndirectShadowTree(id); + if (!state) { + return nullptr; + } + + MOZ_ASSERT(state->mParent); + return state->mParent->GetCompositionManager(aLayerTree); +} + void ContentCompositorBridgeParent::DeferredDestroy() { mSelfRef = nullptr; } ContentCompositorBridgeParent::~ContentCompositorBridgeParent() { @@ -455,6 +624,35 @@ bool ContentCompositorBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); } +void ContentCompositorBridgeParent::UpdatePaintTime( + LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) { + LayersId id = aLayerTree->GetId(); + MOZ_ASSERT(id.IsValid()); + + CompositorBridgeParent::LayerTreeState* state = + CompositorBridgeParent::GetIndirectShadowTree(id); + if (!state || !state->mParent) { + return; + } + + state->mParent->UpdatePaintTime(aLayerTree, aPaintTime); +} + +void ContentCompositorBridgeParent::RegisterPayloads( + LayerTransactionParent* aLayerTree, + const nsTArray& aPayload) { + LayersId id = aLayerTree->GetId(); + MOZ_ASSERT(id.IsValid()); + + CompositorBridgeParent::LayerTreeState* state = + CompositorBridgeParent::GetIndirectShadowTree(id); + if (!state || !state->mParent) { + return; + } + + state->mParent->RegisterPayloads(aLayerTree, aPayload); +} + void ContentCompositorBridgeParent::ObserveLayersUpdate( LayersId aLayersId, LayersObserverEpoch aEpoch, bool aActive) { MOZ_ASSERT(aLayersId.IsValid()); diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.h b/gfx/layers/ipc/ContentCompositorBridgeParent.h index 579e69be50c83..bfdfd22237e35 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.h +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.h @@ -108,8 +108,22 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { return IPC_OK(); } + PLayerTransactionParent* AllocPLayerTransactionParent( + const nsTArray& aBackendHints, + const LayersId& aId) override; + + bool DeallocPLayerTransactionParent( + PLayerTransactionParent* aLayers) override; + + void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, + const TransactionInfo& aInfo, + bool aHitTestUpdate) override; + void ScheduleComposite(LayerTransactionParent* aLayerTree) override; + void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) override; bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) override; void LeaveTestMode(const LayersId& aId) override; + void ApplyAsyncProperties(LayerTransactionParent* aLayerTree, + TransformsToSkip aSkip) override; void SetTestAsyncScrollOffset(const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId, const CSSPoint& aPoint) override; @@ -125,6 +139,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { const LayersId& aLayersId, const uint64_t& aInputBlockId, nsTArray&& aTargets) override; + AsyncCompositionManager* GetCompositionManager( + LayerTransactionParent* aParent) override; + already_AddRefed AllocPWebGLParent() override; // Use DidCompositeLocked if you already hold a lock on @@ -166,6 +183,11 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { PAPZParent* AllocPAPZParent(const LayersId& aLayersId) override; bool DeallocPAPZParent(PAPZParent* aActor) override; + void UpdatePaintTime(LayerTransactionParent* aLayerTree, + const TimeDuration& aPaintTime) override; + void RegisterPayloads(LayerTransactionParent* aLayerTree, + const nsTArray& aPayload) override; + PWebRenderBridgeParent* AllocPWebRenderBridgeParent( const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize, const WindowKind& aWindowKind) override; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 92bad5111f8c1..0c3024426fa46 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -11,6 +11,7 @@ #include "ImageBridgeParent.h" // for ImageBridgeParent #include "ImageContainer.h" // for ImageContainer #include "Layers.h" // for Layer, etc +#include "ShadowLayers.h" // for ShadowLayerForwarder #include "SynchronousTask.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock @@ -402,6 +403,10 @@ void ImageBridgeChild::EndTransaction() { cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size()); } + if (!IsSameProcess()) { + ShadowLayerForwarder::PlatformSyncBeforeUpdate(); + } + if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) { NS_WARNING("could not send async texture transaction"); return; diff --git a/gfx/layers/ipc/KnowsCompositor.cpp b/gfx/layers/ipc/KnowsCompositor.cpp deleted file mode 100644 index 69c24d85f390d..0000000000000 --- a/gfx/layers/ipc/KnowsCompositor.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 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 "KnowsCompositor.h" -#include "mozilla/layers/ImageDataSerializer.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/ipc/ProtocolUtils.h" - -namespace mozilla { -namespace layers { - -void KnowsCompositor::IdentifyTextureHost( - const TextureFactoryIdentifier& aIdentifier) { - auto lock = mData.Lock(); - lock.ref().mTextureFactoryIdentifier = aIdentifier; - - lock.ref().mSyncObject = - SyncObjectClient::CreateSyncObjectClientForContentDevice( - aIdentifier.mSyncHandle); -} - -KnowsCompositor::KnowsCompositor() - : mData("KnowsCompositorMutex"), mSerial(++sSerialCounter) {} - -KnowsCompositor::~KnowsCompositor() = default; - -KnowsCompositorMediaProxy::KnowsCompositorMediaProxy( - const TextureFactoryIdentifier& aIdentifier) { - auto lock = mData.Lock(); - lock.ref().mTextureFactoryIdentifier = aIdentifier; - // overwrite mSerial's value set by the parent class because we use the same - // serial as the KnowsCompositor we are proxying. - mThreadSafeAllocator = ImageBridgeChild::GetSingleton(); - lock.ref().mSyncObject = mThreadSafeAllocator->GetSyncObject(); -} - -KnowsCompositorMediaProxy::~KnowsCompositorMediaProxy() = default; - -TextureForwarder* KnowsCompositorMediaProxy::GetTextureForwarder() { - return mThreadSafeAllocator->GetTextureForwarder(); -} - -LayersIPCActor* KnowsCompositorMediaProxy::GetLayersIPCActor() { - return mThreadSafeAllocator->GetLayersIPCActor(); -} - -ActiveResourceTracker* KnowsCompositorMediaProxy::GetActiveResourceTracker() { - return mThreadSafeAllocator->GetActiveResourceTracker(); -} - -void KnowsCompositorMediaProxy::SyncWithCompositor() { - mThreadSafeAllocator->SyncWithCompositor(); -} - -bool IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface) { - return aSurface.type() != SurfaceDescriptor::T__None && - aSurface.type() != SurfaceDescriptor::Tnull_t; -} - -uint8_t* GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor) { - MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor)); - MOZ_RELEASE_ASSERT( - aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer, - "GFX: surface descriptor is not the right type."); - - auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data(); - if (memOrShmem.type() == MemoryOrShmem::TShmem) { - return memOrShmem.get_Shmem().get(); - } else { - return reinterpret_cast(memOrShmem.get_uintptr_t()); - } -} - -already_AddRefed GetSurfaceForDescriptor( - const SurfaceDescriptor& aDescriptor) { - if (aDescriptor.type() != SurfaceDescriptor::TSurfaceDescriptorBuffer) { - return nullptr; - } - uint8_t* data = GetAddressFromDescriptor(aDescriptor); - auto rgb = - aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor(); - uint32_t stride = ImageDataSerializer::GetRGBStride(rgb); - return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(), - rgb.format()); -} - -already_AddRefed GetDrawTargetForDescriptor( - const SurfaceDescriptor& aDescriptor) { - uint8_t* data = GetAddressFromDescriptor(aDescriptor); - auto rgb = - aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor(); - uint32_t stride = ImageDataSerializer::GetRGBStride(rgb); - return gfx::Factory::CreateDrawTargetForData( - gfx::BackendType::SKIA, data, rgb.size(), stride, rgb.format()); -} - -void DestroySurfaceDescriptor(IShmemAllocator* aAllocator, - SurfaceDescriptor* aSurface) { - MOZ_ASSERT(aSurface); - - SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer(); - switch (desc.data().type()) { - case MemoryOrShmem::TShmem: { - aAllocator->DeallocShmem(desc.data().get_Shmem()); - break; - } - case MemoryOrShmem::Tuintptr_t: { - uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t(); - GfxMemoryImageReporter::WillFree(ptr); - delete[] ptr; - break; - } - default: - MOZ_CRASH("surface type not implemented!"); - } - *aSurface = SurfaceDescriptor(); -} - -} // namespace layers -} // namespace mozilla diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp new file mode 100644 index 0000000000000..4dbd40e089908 --- /dev/null +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "LayerTransactionChild.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder +#include "mozilla/mozalloc.h" // for operator delete, etc +#include "nsTArray.h" // for nsTArray +#include "mozilla/layers/TextureClient.h" + +namespace mozilla { +namespace layers { + +void LayerTransactionChild::Destroy() { + if (!IPCOpen()) { + return; + } + // mDestroyed is used to prevent calling Send__delete__() twice. + // When this function is called from CompositorBridgeChild::Destroy(), + // under Send__delete__() call, this function is called from + // ShadowLayerForwarder's destructor. + // When it happens, IPCOpen() is still true. + // See bug 1004191. + mDestroyed = true; + + SendShutdown(); +} + +void LayerTransactionChild::ActorDestroy(ActorDestroyReason why) { + mDestroyed = true; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/LayerTransactionChild.h b/gfx/layers/ipc/LayerTransactionChild.h new file mode 100644 index 0000000000000..83ce36b02245f --- /dev/null +++ b/gfx/layers/ipc/LayerTransactionChild.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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/. */ + +#ifndef MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H +#define MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H + +#include // for uint32_t +#include "mozilla/Attributes.h" // for override +#include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/layers/PLayerTransactionChild.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { + +namespace layers { + +class ShadowLayerForwarder; + +class LayerTransactionChild : public PLayerTransactionChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild) + /** + * Clean this up, finishing with SendShutDown() which will cause __delete__ + * to be sent from the parent side. + * + * It is expected (checked with an assert) that all shadow layers + * created by this have already been destroyed and + * Send__delete__()d by the time this method is called. + */ + void Destroy(); + + bool IPCOpen() const { return mIPCOpen && !mDestroyed; } + bool IsDestroyed() const { return mDestroyed; } + + void SetForwarder(ShadowLayerForwarder* aForwarder) { + mForwarder = aForwarder; + } + + LayersId GetId() const { return mId; } + + void MarkDestroyed() { mDestroyed = true; } + + protected: + explicit LayerTransactionChild(const LayersId& aId) + : mForwarder(nullptr), mIPCOpen(false), mDestroyed(false), mId(aId) {} + virtual ~LayerTransactionChild() = default; + + void ActorDestroy(ActorDestroyReason why) override; + + void AddIPDLReference() { + MOZ_ASSERT(mIPCOpen == false); + mIPCOpen = true; + AddRef(); + } + void ReleaseIPDLReference() { + MOZ_ASSERT(mIPCOpen == true); + mIPCOpen = false; + Release(); + } + friend class CompositorBridgeChild; + + ShadowLayerForwarder* mForwarder; + bool mIPCOpen; + bool mDestroyed; + LayersId mId; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp new file mode 100644 index 0000000000000..510cf0a431e3d --- /dev/null +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -0,0 +1,1019 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "LayerTransactionParent.h" +#include // for vector +#include "CompositableHost.h" // for CompositableParent, Get, etc +#include "ImageLayers.h" // for ImageLayer +#include "Layers.h" // for Layer, ContainerLayer, etc +#include "CompositableTransactionParent.h" // for EditReplyVector +#include "CompositorBridgeParent.h" +#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D +#include "mozilla/layers/AnimationHelper.h" // for GetAnimatedPropValue +#include "mozilla/layers/CanvasLayerComposite.h" +#include "mozilla/layers/ColorLayerComposite.h" +#include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/CompositorAnimationStorage.h" // for CompositorAnimationStorage +#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/LayersTypes.h" // for MOZ_LAYERS_LOG +#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL +#include "mozilla/layers/PaintedLayerComposite.h" +#include "mozilla/mozalloc.h" // for operator delete, etc +#include "mozilla/PerfStats.h" +#include "mozilla/StaticPrefs_layers.h" +#include "mozilla/StaticPrefs_layout.h" +#include "mozilla/Telemetry.h" +#include "mozilla/Unused.h" +#include "nsCoord.h" // for NSAppUnitsToFloatPixels +#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 "mozilla/ProfilerLabels.h" +#include "mozilla/ProfilerMarkers.h" +#include "mozilla/layers/TextureHost.h" +#include "mozilla/layers/AsyncCompositionManager.h" + +using mozilla::Telemetry::LABELS_CONTENT_FRAME_TIME_REASON; + +namespace mozilla { +namespace layers { + +//-------------------------------------------------- +// LayerTransactionParent +LayerTransactionParent::LayerTransactionParent( + HostLayerManager* aManager, CompositorBridgeParentBase* aBridge, + CompositorAnimationStorage* aAnimStorage, LayersId aId, + TimeDuration aVsyncRate) + : mLayerManager(aManager), + mCompositorBridge(aBridge), + mAnimStorage(aAnimStorage), + mId(aId), + mChildEpoch{0}, + mParentEpoch{0}, + mVsyncRate(aVsyncRate), + mDestroyed(false), + mIPCOpen(false), + mUpdateHitTestingTree(false) { + MOZ_ASSERT(mId.IsValid()); +} + +LayerTransactionParent::~LayerTransactionParent() = default; + +void LayerTransactionParent::SetLayerManager( + HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage) { + if (mDestroyed) { + return; + } + mLayerManager = aLayerManager; + for (const auto& layer : mLayerMap.Values()) { + if (mAnimStorage && layer->GetCompositorAnimationsId()) { + mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); + } + layer->AsHostLayer()->SetLayerManager(aLayerManager); + } + mAnimStorage = aAnimStorage; +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvShutdown() { + Destroy(); + IProtocol* mgr = Manager(); + if (!Send__delete__(this)) { + return IPC_FAIL_NO_REASON(mgr); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvShutdownSync() { + return RecvShutdown(); +} + +void LayerTransactionParent::Destroy() { + if (mDestroyed) { + return; + } + mDestroyed = true; + if (mAnimStorage) { + for (const auto& layer : mLayerMap.Values()) { + if (layer->GetCompositorAnimationsId()) { + mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); + } + layer->Disconnect(); + } + } + mCompositables.clear(); + mAnimStorage = nullptr; +} + +class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender final { + public: + explicit AutoLayerTransactionParentAsyncMessageSender( + LayerTransactionParent* aLayerTransaction, + const nsTArray* 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; + const nsTArray* mActorsToDestroy; +}; + +mozilla::ipc::IPCResult LayerTransactionParent::RecvPaintTime( + const TransactionId& aTransactionId, const TimeDuration& aPaintTime) { + mCompositorBridge->UpdatePaintTime(this, aPaintTime); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvUpdate( + const TransactionInfo& aInfo) { + AUTO_PROFILER_TRACING_MARKER("Paint", "LayerTransaction", GRAPHICS); + AUTO_PROFILER_LABEL("LayerTransactionParent::RecvUpdate", GRAPHICS); + PerfStats::AutoMetricRecording + autoRecording; + + TimeStamp updateStart = TimeStamp::Now(); + + MOZ_LAYERS_LOG( + ("[ParentSide] received txn with %zu edits", aInfo.cset().Length())); + + UpdateFwdTransactionId(aInfo.fwdTransactionId()); + + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + for (const auto& op : aInfo.toDestroy()) { + DestroyActor(op); + } + return IPC_OK(); + } + + // This ensures that destroy operations are always processed. It is not safe + // to early-return from RecvUpdate without doing so. + AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender( + this, &aInfo.toDestroy()); + + { + AutoResolveRefLayers resolve( + mCompositorBridge->GetCompositionManager(this)); + nsCString none; + mLayerManager->BeginTransaction(none); + } + + // Not all edits require an update to the hit testing tree. + mUpdateHitTestingTree = false; + + for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) { + const Edit& edit = const_cast(aInfo.cset()[i]); + + switch (edit.type()) { + // Create* ops + case Edit::TOpCreatePaintedLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer")); + + RefPtr layer = mLayerManager->CreatePaintedLayer(); + if (!BindLayer(layer, edit.get_OpCreatePaintedLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreatePaintedLayer"); + break; + } + case Edit::TOpCreateContainerLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer")); + + RefPtr layer = mLayerManager->CreateContainerLayer(); + if (!BindLayer(layer, edit.get_OpCreateContainerLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreateContainerLayer"); + break; + } + case Edit::TOpCreateImageLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer")); + + RefPtr layer = mLayerManager->CreateImageLayer(); + if (!BindLayer(layer, edit.get_OpCreateImageLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreateImageLayer"); + break; + } + case Edit::TOpCreateColorLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer")); + + RefPtr layer = mLayerManager->CreateColorLayer(); + if (!BindLayer(layer, edit.get_OpCreateColorLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreateColorLayer"); + break; + } + case Edit::TOpCreateCanvasLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer")); + + RefPtr layer = mLayerManager->CreateCanvasLayer(); + if (!BindLayer(layer, edit.get_OpCreateCanvasLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreateCanvasLayer"); + break; + } + case Edit::TOpCreateRefLayer: { + MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer")); + + RefPtr layer = mLayerManager->CreateRefLayer(); + if (!BindLayer(layer, edit.get_OpCreateRefLayer())) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "CreateRefLayer"); + break; + } + case Edit::TOpSetDiagnosticTypes: { + mLayerManager->SetDiagnosticTypes( + edit.get_OpSetDiagnosticTypes().diagnostics()); + break; + } + // Tree ops + case Edit::TOpSetRoot: { + MOZ_LAYERS_LOG(("[ParentSide] SetRoot")); + + Layer* newRoot = AsLayer(edit.get_OpSetRoot().root()); + if (!newRoot) { + return IPC_FAIL_NO_REASON(this); + } + if (newRoot->GetParent()) { + // newRoot is not a root! + return IPC_FAIL_NO_REASON(this); + } + mRoot = newRoot; + + UpdateHitTestingTree(mRoot, "SetRoot"); + break; + } + case Edit::TOpInsertAfter: { + MOZ_LAYERS_LOG(("[ParentSide] InsertAfter")); + + const OpInsertAfter& oia = edit.get_OpInsertAfter(); + Layer* child = AsLayer(oia.childLayer()); + Layer* layer = AsLayer(oia.container()); + Layer* after = AsLayer(oia.after()); + if (!child || !layer || !after) { + return IPC_FAIL_NO_REASON(this); + } + ContainerLayer* container = layer->AsContainerLayer(); + if (!container || !container->InsertAfter(child, after)) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "InsertAfter"); + break; + } + case Edit::TOpPrependChild: { + MOZ_LAYERS_LOG(("[ParentSide] PrependChild")); + + const OpPrependChild& oac = edit.get_OpPrependChild(); + Layer* child = AsLayer(oac.childLayer()); + Layer* layer = AsLayer(oac.container()); + if (!child || !layer) { + return IPC_FAIL_NO_REASON(this); + } + ContainerLayer* container = layer->AsContainerLayer(); + if (!container || !container->InsertAfter(child, nullptr)) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "PrependChild"); + break; + } + case Edit::TOpRemoveChild: { + MOZ_LAYERS_LOG(("[ParentSide] RemoveChild")); + + const OpRemoveChild& orc = edit.get_OpRemoveChild(); + Layer* childLayer = AsLayer(orc.childLayer()); + Layer* layer = AsLayer(orc.container()); + if (!childLayer || !layer) { + return IPC_FAIL_NO_REASON(this); + } + ContainerLayer* container = layer->AsContainerLayer(); + if (!container || !container->RemoveChild(childLayer)) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "RemoveChild"); + break; + } + case Edit::TOpRepositionChild: { + MOZ_LAYERS_LOG(("[ParentSide] RepositionChild")); + + const OpRepositionChild& orc = edit.get_OpRepositionChild(); + Layer* child = AsLayer(orc.childLayer()); + Layer* after = AsLayer(orc.after()); + Layer* layer = AsLayer(orc.container()); + if (!child || !layer || !after) { + return IPC_FAIL_NO_REASON(this); + } + ContainerLayer* container = layer->AsContainerLayer(); + if (!container || !container->RepositionChild(child, after)) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "RepositionChild"); + break; + } + case Edit::TOpRaiseToTopChild: { + MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild")); + + const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild(); + Layer* child = AsLayer(rtc.childLayer()); + if (!child) { + return IPC_FAIL_NO_REASON(this); + } + Layer* layer = AsLayer(rtc.container()); + if (!layer) { + return IPC_FAIL_NO_REASON(this); + } + ContainerLayer* container = layer->AsContainerLayer(); + if (!container || !container->RepositionChild(child, nullptr)) { + return IPC_FAIL_NO_REASON(this); + } + + UpdateHitTestingTree(layer, "RaiseToTopChild"); + break; + } + case Edit::TCompositableOperation: { + if (!ReceiveCompositableUpdate(edit.get_CompositableOperation())) { + return IPC_FAIL_NO_REASON(this); + } + break; + } + case Edit::TOpAttachCompositable: { + const OpAttachCompositable& op = edit.get_OpAttachCompositable(); + RefPtr host = FindCompositable(op.compositable()); + if (!Attach(AsLayer(op.layer()), host, false)) { + return IPC_FAIL_NO_REASON(this); + } + host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID()); + break; + } + case Edit::TOpAttachAsyncCompositable: { + const OpAttachAsyncCompositable& op = + edit.get_OpAttachAsyncCompositable(); + RefPtr imageBridge = + ImageBridgeParent::GetInstance(OtherPid()); + if (!imageBridge) { + return IPC_FAIL_NO_REASON(this); + } + RefPtr host = imageBridge->FindCompositable( + op.compositable(), /* aAllowDisablingWebRender */ true); + if (!host) { + // This normally should not happen, but can after a GPU process crash. + // Media may not have had time to update the ImageContainer associated + // with a video frame, and we may try to attach a stale + // CompositableHandle. Rather than break the whole transaction, we + // just continue. + gfxCriticalNote << "CompositableHost " << op.compositable().Value() + << " not found"; + continue; + } + if (!Attach(AsLayer(op.layer()), host, true)) { + return IPC_FAIL_NO_REASON(this); + } + host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID()); + break; + } + default: + MOZ_CRASH("not reached"); + } + } + + // Process simple attribute updates. + for (const auto& op : aInfo.setSimpleAttrs()) { + MOZ_LAYERS_LOG(("[ParentSide] SetSimpleLayerAttributes")); + Layer* layer = AsLayer(op.layer()); + if (!layer) { + return IPC_FAIL_NO_REASON(this); + } + const SimpleLayerAttributes& attrs = op.attrs(); + const SimpleLayerAttributes& orig = layer->GetSimpleAttributes(); + if (!attrs.HitTestingInfoIsEqual(orig)) { + UpdateHitTestingTree(layer, "scrolling info changed"); + } + layer->SetSimpleAttributes(op.attrs()); + } + + // Process attribute updates. + for (const auto& op : aInfo.setAttrs()) { + MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes")); + if (!SetLayerAttributes(op)) { + return IPC_FAIL_NO_REASON(this); + } + } + + // Process paints separately, after all normal edits. + for (const auto& op : aInfo.paints()) { + if (!ReceiveCompositableUpdate(op)) { + return IPC_FAIL_NO_REASON(this); + } + } + + mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree); + + { + AutoResolveRefLayers resolve( + mCompositorBridge->GetCompositionManager(this)); + mLayerManager->EndTransaction(TimeStamp(), + LayerManager::END_NO_IMMEDIATE_REDRAW); + } + + 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 = StaticPrefs::layers_acceleration_draw_fps(); + if (drawFps) { + uint32_t visualWarningTrigger = + StaticPrefs::layers_transaction_warning_ms(); + // The default theshold is 200ms to trigger, hit red when it take 4 times + // longer + TimeDuration latency = TimeStamp::Now() - aInfo.transactionStart(); + if (latency > TimeDuration::FromMilliseconds(visualWarningTrigger)) { + float severity = + (latency - TimeDuration::FromMilliseconds(visualWarningTrigger)) + .ToMilliseconds() / + (4 * visualWarningTrigger); + if (severity > 1.f) { + severity = 1.f; + } + mLayerManager->VisualFrameWarning(severity); + printf_stderr( + "LayerTransactionParent::RecvUpdate transaction from process %d took " + "%f ms", + OtherPid(), latency.ToMilliseconds()); + } + + mLayerManager->RecordUpdateTime( + (TimeStamp::Now() - updateStart).ToMilliseconds()); + } + + return IPC_OK(); +} + +bool LayerTransactionParent::SetLayerAttributes( + const OpSetLayerAttributes& aOp) { + Layer* layer = AsLayer(aOp.layer()); + if (!layer) { + return false; + } + + const LayerAttributes& attrs = aOp.attrs(); + const CommonLayerAttributes& common = attrs.common(); + if (common.visibleRegion() != layer->GetVisibleRegion()) { + UpdateHitTestingTree(layer, "visible region changed"); + layer->SetVisibleRegion(common.visibleRegion()); + } + if (common.eventRegions() != layer->GetEventRegions()) { + UpdateHitTestingTree(layer, "event regions changed"); + layer->SetEventRegions(common.eventRegions()); + } + Maybe clipRect = + common.useClipRect() ? Some(common.clipRect()) : Nothing(); + if (clipRect != layer->GetClipRect()) { + UpdateHitTestingTree(layer, "clip rect changed"); + layer->SetClipRect(clipRect); + } + if (LayerHandle maskLayer = common.maskLayer()) { + layer->SetMaskLayer(AsLayer(maskLayer)); + } else { + layer->SetMaskLayer(nullptr); + } + layer->SetCompositorAnimations(mId, common.compositorAnimations()); + // Clean up the Animations by id in the CompositorAnimationStorage + // if there are no active animations on the layer + if (mAnimStorage && layer->GetCompositorAnimationsId() && + layer->GetPropertyAnimationGroups().IsEmpty()) { + mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); + } + if (common.scrollMetadata() != layer->GetAllScrollMetadata()) { + UpdateHitTestingTree(layer, "scroll metadata changed"); + 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> maskLayers; + for (size_t i = 0; i < common.ancestorMaskLayers().Length(); i++) { + Layer* maskLayer = AsLayer(common.ancestorMaskLayers().ElementAt(i)); + if (!maskLayer) { + return false; + } + 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")); + + PaintedLayer* paintedLayer = layer->AsPaintedLayer(); + if (!paintedLayer) { + return false; + } + const PaintedLayerAttributes& attrs = + specific.get_PaintedLayerAttributes(); + + paintedLayer->SetValidRegion(attrs.validRegion()); + break; + } + case Specific::TContainerLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] container layer")); + + ContainerLayer* containerLayer = layer->AsContainerLayer(); + 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.presShellResolution()); + break; + } + case Specific::TColorLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] color layer")); + + ColorLayer* colorLayer = layer->AsColorLayer(); + 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")); + + CanvasLayer* canvasLayer = layer->AsCanvasLayer(); + 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")); + + RefLayer* refLayer = layer->AsRefLayer(); + if (!refLayer) { + return false; + } + refLayer->SetReferentId(specific.get_RefLayerAttributes().id()); + refLayer->SetEventRegionsOverride( + specific.get_RefLayerAttributes().eventRegionsOverride()); + refLayer->SetRemoteDocumentSize( + specific.get_RefLayerAttributes().remoteDocumentSize()); + UpdateHitTestingTree(layer, "ref layer attributes changed"); + break; + } + case Specific::TImageLayerAttributes: { + MOZ_LAYERS_LOG(("[ParentSide] image layer")); + + ImageLayer* imageLayer = layer->AsImageLayer(); + if (!imageLayer) { + return false; + } + const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes(); + imageLayer->SetSamplingFilter(attrs.samplingFilter()); + imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode()); + break; + } + default: + MOZ_CRASH("not reached"); + } + + return true; +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvSetLayersObserverEpoch( + const LayersObserverEpoch& aChildEpoch) { + mChildEpoch = aChildEpoch; + return IPC_OK(); +} + +bool LayerTransactionParent::ShouldParentObserveEpoch() { + if (mParentEpoch == mChildEpoch) { + return false; + } + + mParentEpoch = mChildEpoch; + return true; +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvSetTestSampleTime( + const TimeStamp& aTime) { + if (!mCompositorBridge->SetTestSampleTime(GetId(), aTime)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvLeaveTestMode() { + if (mDestroyed) { + return IPC_FAIL_NO_REASON(this); + } + + mCompositorBridge->LeaveTestMode(GetId()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvGetAnimationValue( + const uint64_t& aCompositorAnimationsId, OMTAValue* aValue) { + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + return IPC_FAIL_NO_REASON(this); + } + + // 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, CompositorBridgeParentBase::TransformsToSkip::APZ); + + if (!mAnimStorage) { + return IPC_FAIL_NO_REASON(this); + } + + *aValue = mAnimStorage->GetOMTAValue(aCompositorAnimationsId); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvGetTransform( + const LayerHandle& aLayerHandle, Maybe* aTransform) { + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + return IPC_FAIL_NO_REASON(this); + } + + Layer* layer = AsLayer(aLayerHandle); + if (!layer) { + return IPC_FAIL_NO_REASON(this); + } + + mCompositorBridge->ApplyAsyncProperties( + this, CompositorBridgeParentBase::TransformsToSkip::NoneOfThem); + + Matrix4x4 transform = layer->AsHostLayer()->GetShadowBaseTransform(); + // Undo the scale transform applied by FrameTransformToTransformInDevice in + // AsyncCompositionManager.cpp. + if (ContainerLayer* c = layer->AsContainerLayer()) { + transform.PostScale(1.0f / c->GetInheritedXScale(), + 1.0f / c->GetInheritedYScale(), 1.0f); + } + float scale = 1; + Point3D scaledOrigin; + if (layer->GetTransformData()) { + const TransformData& data = *layer->GetTransformData(); + scale = data.appUnitsPerDevPixel(); + scaledOrigin = Point3D( + NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)), + NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), 0.0f); + } + + // 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); + } + + *aTransform = Some(transform); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvSetAsyncScrollOffset( + const ScrollableLayerGuid::ViewID& aScrollID, const float& aX, + const float& aY) { + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + return IPC_FAIL_NO_REASON(this); + } + + mCompositorBridge->SetTestAsyncScrollOffset(GetId(), aScrollID, + CSSPoint(aX, aY)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvSetAsyncZoom( + const ScrollableLayerGuid::ViewID& aScrollID, const float& aValue) { + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + return IPC_FAIL_NO_REASON(this); + } + + mCompositorBridge->SetTestAsyncZoom(GetId(), aScrollID, + LayerToParentLayerScale(aValue)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvFlushApzRepaints() { + mCompositorBridge->FlushApzRepaints(GetId()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvGetAPZTestData( + APZTestData* aOutData) { + mCompositorBridge->GetAPZTestData(GetId(), aOutData); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvGetFrameUniformity( + FrameUniformityData* aOutData) { + mCompositorBridge->GetFrameUniformity(GetId(), aOutData); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvRequestProperty( + const nsString& aProperty, float* aValue) { + *aValue = -1; + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvSetConfirmedTargetAPZC( + const uint64_t& aBlockId, nsTArray&& aTargets) { + for (size_t i = 0; i < aTargets.Length(); i++) { + // Guard against bad data from hijacked child processes + if (aTargets[i].mLayersId != GetId()) { + NS_ERROR( + "Unexpected layers id in RecvSetConfirmedTargetAPZC; dropping " + "message..."); + return IPC_FAIL(this, "Bad layers id"); + } + } + mCompositorBridge->SetConfirmedTargetAPZC(GetId(), aBlockId, + std::move(aTargets)); + return IPC_OK(); +} + +bool LayerTransactionParent::Attach(Layer* aLayer, + CompositableHost* aCompositable, + bool aIsAsync) { + if (!aCompositable || !aLayer) { + return false; + } + + HostLayer* layer = aLayer->AsHostLayer(); + if (!layer) { + return false; + } + + TextureSourceProvider* provider = + static_cast(aLayer->Manager()) + ->GetTextureSourceProvider(); + + MOZ_ASSERT(!aCompositable->AsWebRenderImageHost()); + if (aCompositable->AsWebRenderImageHost()) { + gfxCriticalNote << "Use WebRenderImageHost at LayerTransactionParent."; + } + if (!layer->SetCompositableHost(aCompositable)) { + // not all layer types accept a compositable, see bug 967824 + return false; + } + aCompositable->Attach(aLayer, provider, + aIsAsync ? CompositableHost::ALLOW_REATTACH | + CompositableHost::KEEP_ATTACHED + : CompositableHost::NO_FLAGS); + return true; +} + +mozilla::ipc::IPCResult 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 IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvScheduleComposite() { + mCompositorBridge->ScheduleComposite(this); + return IPC_OK(); +} + +void LayerTransactionParent::ActorDestroy(ActorDestroyReason why) { Destroy(); } + +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); +} + +bool LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem) { + if (!mIPCOpen || mDestroyed) { + return false; + } + return PLayerTransactionParent::DeallocShmem(aShmem); +} + +bool LayerTransactionParent::IsSameProcess() const { + return OtherPid() == base::GetCurrentProcId(); +} + +void LayerTransactionParent::SetPendingTransactionId( + TransactionId aId, const VsyncId& aVsyncId, + const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, const TimeStamp& aTxnEndTime, + bool aContainsSVG, const nsCString& aURL, const TimeStamp& aFwdTime) { + mPendingTransactions.AppendElement(PendingTransaction{ + aId, aVsyncId, aVsyncStartTime, aRefreshStartTime, aTxnStartTime, + aTxnEndTime, aFwdTime, aURL, aContainsSVG}); +} + +void LayerTransactionParent::FlushPendingTransactions( + const VsyncId& aCompositeId, TimeStamp& aCompositeEnd, + nsTArray& aOutTransactions) { + for (auto& transaction : mPendingTransactions) { + aOutTransactions.AppendElement(transaction.mId); + if (mId.IsValid() && transaction.mId.IsValid() && !mVsyncRate.IsZero()) { + RecordContentFrameTime( + transaction.mTxnVsyncId, transaction.mVsyncStartTime, + transaction.mTxnStartTime, aCompositeId, aCompositeEnd, + transaction.mTxnEndTime - transaction.mTxnStartTime, mVsyncRate, + transaction.mContainsSVG, false); + } + +#if defined(ENABLE_FRAME_LATENCY_LOG) + if (transaction.mId.IsValid()) { + if (transaction.mRefreshStartTime) { + int32_t latencyMs = lround( + (aCompositeEnd - transaction.mRefreshStartTime).ToMilliseconds()); + printf_stderr( + "From transaction start to end of generate frame latencyMs %d this " + "%p\n", + latencyMs, this); + } + if (transaction.mFwdTime) { + int32_t latencyMs = + lround((aCompositeEnd - transaction.mFwdTime).ToMilliseconds()); + printf_stderr( + "From forwarding transaction to end of generate frame latencyMs %d " + "this %p\n", + latencyMs, this); + } + } +#endif + } + + mPendingTransactions.Clear(); +} + +void LayerTransactionParent::SendAsyncMessage( + const nsTArray& 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"); +} + +bool LayerTransactionParent::BindLayerToHandle(RefPtr aLayer, + const LayerHandle& aHandle) { + if (!aHandle || !aLayer) { + return false; + } + return mLayerMap.WithEntryHandle(aHandle.Value(), [&](auto&& entry) { + if (entry) { + return false; + } + entry.Insert(std::move(aLayer)); + return true; + }); +} + +Layer* LayerTransactionParent::AsLayer(const LayerHandle& aHandle) { + if (!aHandle) { + return nullptr; + } + return mLayerMap.GetWeak(aHandle.Value()); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvNewCompositable( + const CompositableHandle& aHandle, const TextureInfo& aInfo) { + if (!AddCompositable(aHandle, aInfo, /* aUseWebRender */ false)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvReleaseLayer( + const LayerHandle& aHandle) { + RefPtr layer; + if (!aHandle || !mLayerMap.Remove(aHandle.Value(), getter_AddRefs(layer))) { + return IPC_FAIL_NO_REASON(this); + } + if (mAnimStorage && layer->GetCompositorAnimationsId()) { + mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); + layer->ClearCompositorAnimations(); + } + layer->Disconnect(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvReleaseCompositable( + const CompositableHandle& aHandle) { + ReleaseCompositable(aHandle); + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvRecordPaintTimes( + const PaintTiming& aTiming) { + // Currently we only add paint timings for remote layers. In the future + // we could be smarter and use paint timings from the UI process, either + // as a separate overlay or if no remote layers are attached. + if (mLayerManager && mCompositorBridge->IsRemote()) { + mLayerManager->RecordPaintTimes(aTiming); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult LayerTransactionParent::RecvGetTextureFactoryIdentifier( + TextureFactoryIdentifier* aIdentifier) { + if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { + // Default constructor sets mParentBackend to LAYERS_NONE. + return IPC_OK(); + } + + *aIdentifier = mLayerManager->GetTextureFactoryIdentifier(); + return IPC_OK(); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h new file mode 100644 index 0000000000000..417236729ae37 --- /dev/null +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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/. */ + +#ifndef MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H +#define MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H + +#include // for size_t +#include // for uint64_t, uint32_t +#include "CompositableTransactionParent.h" +#include "mozilla/Attributes.h" // for override +#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc +#include "mozilla/layers/PLayerTransactionParent.h" +#include "nsRefPtrHashtable.h" +#include "nsTArrayForwardDeclare.h" // for nsTArray + +namespace mozilla { + +namespace ipc { +class Shmem; +} // namespace ipc + +namespace layers { + +class Layer; +class HostLayerManager; +class ShadowLayerParent; +class CompositableParent; +class CompositorAnimationStorage; +class CompositorBridgeParentBase; + +class LayerTransactionParent final : public PLayerTransactionParent, + public CompositableParentManager, + public mozilla::ipc::IShmemAllocator { + typedef nsTArray EditArray; + typedef nsTArray OpDestroyArray; + + friend class PLayerTransactionParent; + + public: + LayerTransactionParent(HostLayerManager* aManager, + CompositorBridgeParentBase* aBridge, + CompositorAnimationStorage* aAnimStorage, LayersId aId, + TimeDuration aVsyncRate); + + protected: + virtual ~LayerTransactionParent(); + + public: + void Destroy(); + + void SetLayerManager(HostLayerManager* aLayerManager, + CompositorAnimationStorage* aAnimStorage); + + LayersId GetId() const { return mId; } + Layer* GetRoot() const { return mRoot; } + + LayersObserverEpoch GetChildEpoch() const { return mChildEpoch; } + bool ShouldParentObserveEpoch(); + + IShmemAllocator* AsShmemAllocator() override { return this; } + + bool AllocShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) override; + + bool AllocUnsafeShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) override; + + bool DeallocShmem(ipc::Shmem& aShmem) override; + + bool IsSameProcess() const override; + + void SetPendingTransactionId(TransactionId aId, const VsyncId& aVsyncId, + const TimeStamp& aVsyncStartTime, + const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, + const TimeStamp& aTxnEndTime, bool aContainsSVG, + const nsCString& aURL, + const TimeStamp& aFwdTime); + void FlushPendingTransactions(const VsyncId& aId, TimeStamp& aCompositeEnd, + nsTArray& aOutTransactions); + + // CompositableParentManager + void SendAsyncMessage( + const nsTArray& aMessage) override; + + void SendPendingAsyncMessages() override; + + void SetAboutToSendAsyncMessages() override; + + void NotifyNotUsed(PTextureParent* aTexture, + uint64_t aTransactionId) override; + + base::ProcessId GetChildProcessId() override { return OtherPid(); } + + protected: + mozilla::ipc::IPCResult RecvShutdown(); + mozilla::ipc::IPCResult RecvShutdownSync(); + + mozilla::ipc::IPCResult RecvPaintTime(const TransactionId& aTransactionId, + const TimeDuration& aPaintTime); + + mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo); + + mozilla::ipc::IPCResult RecvSetLayersObserverEpoch( + const LayersObserverEpoch& aChildEpoch); + mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle, + const TextureInfo& aInfo); + mozilla::ipc::IPCResult RecvReleaseLayer(const LayerHandle& aHandle); + mozilla::ipc::IPCResult RecvReleaseCompositable( + const CompositableHandle& aHandle); + + mozilla::ipc::IPCResult RecvClearCachedResources(); + mozilla::ipc::IPCResult RecvScheduleComposite(); + mozilla::ipc::IPCResult RecvSetTestSampleTime(const TimeStamp& aTime); + mozilla::ipc::IPCResult RecvLeaveTestMode(); + mozilla::ipc::IPCResult RecvGetAnimationValue( + const uint64_t& aCompositorAnimationsId, OMTAValue* aValue); + mozilla::ipc::IPCResult RecvGetTransform(const LayerHandle& aHandle, + Maybe* aTransform); + mozilla::ipc::IPCResult RecvSetAsyncScrollOffset( + const ScrollableLayerGuid::ViewID& aId, const float& aX, const float& aY); + mozilla::ipc::IPCResult RecvSetAsyncZoom( + const ScrollableLayerGuid::ViewID& aId, const float& aValue); + mozilla::ipc::IPCResult RecvFlushApzRepaints(); + mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* aOutData); + mozilla::ipc::IPCResult RecvGetFrameUniformity(FrameUniformityData* aOutData); + mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, + float* aValue); + mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC( + const uint64_t& aBlockId, nsTArray&& aTargets); + mozilla::ipc::IPCResult RecvRecordPaintTimes(const PaintTiming& aTiming); + mozilla::ipc::IPCResult RecvGetTextureFactoryIdentifier( + TextureFactoryIdentifier* aIdentifier); + + bool SetLayerAttributes(const OpSetLayerAttributes& aOp); + + void ActorDestroy(ActorDestroyReason why) override; + + template + bool BindLayer(const RefPtr& aLayer, const T& aCreateOp) { + return BindLayerToHandle(aLayer, aCreateOp.layer()); + } + + bool BindLayerToHandle(RefPtr aLayer, const LayerHandle& aHandle); + + Layer* AsLayer(const LayerHandle& aLayer); + + bool Attach(Layer* aLayer, CompositableHost* aCompositable, + bool aIsAsyncVideo); + + void AddIPDLReference() { + MOZ_ASSERT(mIPCOpen == false); + mIPCOpen = true; + AddRef(); + } + void ReleaseIPDLReference() { + MOZ_ASSERT(mIPCOpen == true); + mIPCOpen = false; + Release(); + } + friend class CompositorBridgeParent; + friend class ContentCompositorBridgeParent; + + private: + // This is a function so we can log or breakpoint on why hit + // testing tree changes are made. + void UpdateHitTestingTree(Layer* aLayer, const char* aWhy) { + mUpdateHitTestingTree = true; + } + + private: + RefPtr mLayerManager; + CompositorBridgeParentBase* mCompositorBridge; + RefPtr mAnimStorage; + + // Hold the root because it might be grafted under various + // containers in the "real" layer tree + RefPtr mRoot; + + // Mapping from LayerHandles to Layers. + nsRefPtrHashtable mLayerMap; + + LayersId mId; + + // These fields keep track of the latest epoch values in the child and the + // parent. mChildEpoch is the latest epoch value received from the child. + // mParentEpoch is the latest epoch value that we have told BrowserParent + // about (via ObserveLayerUpdate). + LayersObserverEpoch mChildEpoch; + LayersObserverEpoch mParentEpoch; + + TimeDuration mVsyncRate; + + struct PendingTransaction { + TransactionId mId; + VsyncId mTxnVsyncId; + TimeStamp mVsyncStartTime; + TimeStamp mRefreshStartTime; + TimeStamp mTxnStartTime; + TimeStamp mTxnEndTime; + TimeStamp mFwdTime; + nsCString mTxnURL; + bool mContainsSVG; + }; + AutoTArray mPendingTransactions; + + // When the widget/frame/browser stuff in this process begins its + // destruction process, we need to Disconnect() all the currently + // live shadow layers, because some of them might be orphaned from + // the layer tree. This happens in Destroy() above. After we + // Destroy() ourself, there's a window in which that information + // hasn't yet propagated back to the child side and it might still + // send us layer transactions. We want to ignore those transactions + // because they refer to "zombie layers" on this side. So, we track + // that state with |mDestroyed|. This is similar to, but separate + // from, |mLayerManager->IsDestroyed()|; we might have had Destroy() + // called on us but the mLayerManager might not be destroyed, or + // vice versa. In both cases though, we want to ignore shadow-layer + // transactions posted by the child. + + bool mDestroyed; + bool mIPCOpen; + + // This is set during RecvUpdate to track whether we'll need to update + // APZ's hit test regions. + bool mUpdateHitTestingTree; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index d58a05658671f..01a8c3a3f3483 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -15,6 +15,7 @@ include protocol PBrowser; include protocol PCanvas; include protocol PCompositorManager; include protocol PCompositorWidget; +include protocol PLayerTransaction; include protocol PTexture; include protocol PWebGL; include protocol PWebRenderBridge; @@ -98,6 +99,7 @@ struct FrameStats { manages PAPZ; manages PAPZCTreeManager; // A Compositor manages a single Layer Manager (PLayerTransaction) + manages PLayerTransaction; manages PTexture; manages PCompositorWidget; manages PWebRenderBridge; @@ -207,6 +209,11 @@ parent: sync StopFrameTimeRecording(uint32_t startIndex) returns (float[] intervals); + // layersBackendHints is an ordered list of preffered backends where + // layersBackendHints[0] is the best backend. If any hints are LayersBackend::LAYERS_NONE + // that hint is ignored. + async PLayerTransaction(LayersBackend[] layersBackendHints, LayersId id); + // Notify the compositor that a region of the screen has been invalidated. async NotifyRegionInvalidated(nsIntRegion region); diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl new file mode 100644 index 0000000000000..ddc50216e5c38 --- /dev/null +++ b/gfx/layers/ipc/PLayerTransaction.ipdl @@ -0,0 +1,130 @@ +/* -*- 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 LayersSurfaces; +include LayersMessages; +include protocol PCompositorBridge; +include protocol PTexture; + +include "mozilla/GfxMessageUtils.h"; +include "mozilla/layers/LayersMessageUtils.h"; + +using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h"; +using struct mozilla::void_t from "mozilla/ipc/IPCCore.h"; +using struct mozilla::null_t from "mozilla/ipc/IPCCore.h"; +using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h"; +using mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h"; +using mozilla::layers::ScrollableLayerGuid from "mozilla/layers/ScrollableLayerGuid.h"; +using mozilla::layers::ScrollableLayerGuid::ViewID from "mozilla/layers/ScrollableLayerGuid.h"; +using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h"; +using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h"; +using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h"; +using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; +using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h"; +using mozilla::layers::TransactionId from "mozilla/layers/LayersTypes.h"; + +/** + * The layers protocol is spoken between thread contexts that manage + * layer (sub)trees. The protocol comprises atomically publishing + * layer subtrees to a "shadow" thread context (which grafts the + * subtree into its own tree), and atomically updating a published + * subtree. ("Atomic" in this sense is wrt painting.) + */ + +namespace mozilla { +namespace layers { + +/** + * The PLayerTransaction protocol manages the layer tree for a single "browser". + * The "browser" can be a top-level browser window, in which case the PLayer- + * TransactionChild exists in the UI process. The "browser" can also be a content + * tab, in which case the PLayerTransactionChild exists in the content process. + * In either case, the PLayerTransactionParent exists in the GPU process (if + * there is one) or the UI process otherwise. + */ +sync protocol PLayerTransaction { + manager PCompositorBridge; + +parent: + // The isFirstPaint flag can be used to indicate that this is the first update + // for a particular document. + async Update(TransactionInfo txn); + + async PaintTime(TransactionId id, TimeDuration paintTime); + + async SetLayersObserverEpoch(LayersObserverEpoch aChildEpoch); + + // Create a new Compositable. + async NewCompositable(CompositableHandle handle, TextureInfo info); + + // Release an object that is no longer in use. + async ReleaseLayer(LayerHandle layer); + async ReleaseCompositable(CompositableHandle compositable); + + // Tell the compositor to notify APZ that a layer has been confirmed for an + // input event. + async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets); + + // Testing APIs + + // Enter test mode, set the sample time to sampleTime, and resample + // animations. sampleTime must not be null. + sync SetTestSampleTime(TimeStamp sampleTime); + // Leave test mode and resume normal compositing + sync LeaveTestMode(); + + // Returns |OMTAValue| applied to the layer. + sync GetAnimationValue(uint64_t aCompositorAnimationId) returns (OMTAValue value); + + // Returns the value of the transform applied to the layer by animation and + // APZC. + sync GetTransform(LayerHandle layer) returns (Matrix4x4? transform); + + // The next time the layer tree is composited, add this async scroll offset in + // CSS pixels for the given ViewID. + // Useful for testing rendering of async scrolling. + sync SetAsyncScrollOffset(ViewID id, float x, float y); + + // The next time the layer tree is composited, include this async zoom in + // for the given ViewID. + // Useful for testing rendering of async zooming. + sync SetAsyncZoom(ViewID id, float zoom); + + // Flush any pending APZ repaints to the main thread. + async FlushApzRepaints(); + + // Drop any front buffers that might be retained on the compositor + // side. + async ClearCachedResources(); + + // Schedule a composite if one isn't already scheduled. + async ScheduleComposite(); + + // Get a copy of the compositor-side APZ test data instance for this + // layers id. + sync GetAPZTestData() returns (APZTestData data); + + // Child requests frame uniformity measurements + sync GetFrameUniformity() returns (FrameUniformityData data); + + // Query a named property from the last frame + sync RequestProperty(nsString property) returns (float value); + + // Return the TextureFactoryIdentifier for this compositor. + sync GetTextureFactoryIdentifier() returns (TextureFactoryIdentifier aIdentifier); + + async RecordPaintTimes(PaintTiming timing); + + async Shutdown(); + sync ShutdownSync(); + +child: + async __delete__(); +}; + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/PTexture.ipdl b/gfx/layers/ipc/PTexture.ipdl index 18eeb84c897ea..b82a757bbcead 100644 --- a/gfx/layers/ipc/PTexture.ipdl +++ b/gfx/layers/ipc/PTexture.ipdl @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include LayersSurfaces; +include protocol PLayerTransaction; include protocol PCompositorBridge; include protocol PImageBridge; include protocol PVideoBridge; diff --git a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp index b095e5c2e9005..891b16e8a2cf8 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/gfx/Point.h" +#include "mozilla/layers/PLayerTransaction.h" +#include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/CompositorTypes.h" @@ -16,6 +18,9 @@ using namespace mozilla::gl; namespace mozilla { namespace layers { +/*static*/ +void ShadowLayerForwarder::PlatformSyncBeforeUpdate() {} + /*static*/ void LayerManagerComposite::PlatformSyncBeforeReplyUpdate() {} diff --git a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp index 24ca1d5ceb4af..25f6ceba21f38 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp @@ -24,6 +24,7 @@ #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/LayersMessageUtils.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc #include "mozilla/mozalloc.h" // for operator new #include "gfxEnv.h" #include "nsCOMPtr.h" // for already_AddRefed @@ -102,6 +103,17 @@ already_AddRefed SurfaceDescriptorX11::OpenForeign() const { return surf->CairoStatus() ? nullptr : surf.forget(); } +/*static*/ +void ShadowLayerForwarder::PlatformSyncBeforeUpdate() { + if (UsingXCompositing()) { + // If we're using X surfaces, then we need to finish all pending + // operations on the back buffers before handing them to the + // parent, otherwise the surface might be used by the parent's + // Display in between two operations queued by our Display. + FinishX(DefaultXDisplay()); + } +} + /*static*/ void LayerManagerComposite::PlatformSyncBeforeReplyUpdate() { if (UsingXCompositing()) { diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp new file mode 100644 index 0000000000000..d149a6d2891bd --- /dev/null +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -0,0 +1,972 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "ShadowLayers.h" + +#include // for _Rb_tree_const_iterator, etc +#include // for vector + +#include "IPDLActor.h" +#include "ISurfaceAllocator.h" // for IsSurfaceDescriptorValid +#include "Layers.h" // for Layer +#include "RenderTrace.h" // for RenderTraceScope +#include "gfx2DGlue.h" // for Moz2D transition helpers +#include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform +#include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/layers/CompositableClient.h" // for CompositableClient, etc +#include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/layers/ContentClient.h" +#include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/layers/LayerTransactionChild.h" +#include "mozilla/layers/LayersMessages.h" // for Edit, etc +#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG +#include "mozilla/layers/PTextureChild.h" +#include "mozilla/layers/SyncObject.h" +#ifdef XP_DARWIN +# include "mozilla/layers/TextureSync.h" +#endif +#include "ShadowLayerUtils.h" +#include "mozilla/ProfilerLabels.h" +#include "mozilla/ReentrantMonitor.h" +#include "mozilla/StaticPrefs_layers.h" +#include "mozilla/layers/TextureClient.h" // for TextureClient +#include "mozilla/mozalloc.h" // for operator new, etc +#include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart +#include "nsTArray.h" // for AutoTArray, nsTArray, etc +#include "nsTHashSet.h" +#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc + +namespace mozilla { +namespace ipc { +class Shmem; +} // namespace ipc + +namespace layers { + +using namespace mozilla::gfx; +using namespace mozilla::gl; +using namespace mozilla::ipc; + +class ClientTiledLayerBuffer; + +typedef nsTArray BufferArray; +typedef nsTArray EditVector; +typedef nsTHashSet ShadowableLayerSet; +typedef nsTArray OpDestroyVector; + +class Transaction { + public: + Transaction() + : mTargetRotation(ROTATION_0), + mTargetOrientation(hal::eScreenOrientation_None), + mOpen(false), + mRotationChanged(false) {} + + void Begin(const gfx::IntRect& aTargetBounds, ScreenRotation aRotation, + hal::ScreenOrientation aOrientation) { + mOpen = true; + mTargetBounds = aTargetBounds; + if (aRotation != mTargetRotation) { + // the first time this is called, mRotationChanged will be false if + // aRotation is 0, but we should be OK because for the first transaction + // we should only compose if it is non-empty. See the caller(s) of + // RotationChanged. + mRotationChanged = true; + } + mTargetRotation = aRotation; + mTargetOrientation = aOrientation; + } + void AddEdit(const Edit& aEdit) { + MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); + mCset.AppendElement(aEdit); + } + void AddEdit(const CompositableOperation& aEdit) { AddEdit(Edit(aEdit)); } + + void AddNoSwapPaint(const CompositableOperation& aPaint) { + MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); + mPaints.AppendElement(Edit(aPaint)); + } + void AddMutant(ShadowableLayer* aLayer) { + MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); + mMutants.Insert(aLayer); + } + void AddSimpleMutant(ShadowableLayer* aLayer) { + MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); + mSimpleMutants.Insert(aLayer); + } + void End() { + mCset.Clear(); + mPaints.Clear(); + mMutants.Clear(); + mSimpleMutants.Clear(); + mDestroyedActors.Clear(); + mOpen = false; + mRotationChanged = false; + } + + bool Empty() const { + return mCset.IsEmpty() && mPaints.IsEmpty() && mMutants.IsEmpty() && + mSimpleMutants.IsEmpty() && mDestroyedActors.IsEmpty(); + } + bool RotationChanged() const { return mRotationChanged; } + bool Finished() const { return !mOpen && Empty(); } + + bool Opened() const { return mOpen; } + + EditVector mCset; + nsTArray mPaints; + OpDestroyVector mDestroyedActors; + ShadowableLayerSet mMutants; + ShadowableLayerSet mSimpleMutants; + gfx::IntRect mTargetBounds; + ScreenRotation mTargetRotation; + hal::ScreenOrientation mTargetOrientation; + + private: + bool mOpen; + bool mRotationChanged; + + // disabled + Transaction(const Transaction&); + Transaction& operator=(const Transaction&); +}; +struct AutoTxnEnd final { + explicit AutoTxnEnd(Transaction* aTxn) : mTxn(aTxn) {} + ~AutoTxnEnd() { mTxn->End(); } + Transaction* mTxn; +}; + +void KnowsCompositor::IdentifyTextureHost( + const TextureFactoryIdentifier& aIdentifier) { + auto lock = mData.Lock(); + lock.ref().mTextureFactoryIdentifier = aIdentifier; + + lock.ref().mSyncObject = + SyncObjectClient::CreateSyncObjectClientForContentDevice( + aIdentifier.mSyncHandle); +} + +KnowsCompositor::KnowsCompositor() + : mData("KnowsCompositorMutex"), mSerial(++sSerialCounter) {} + +KnowsCompositor::~KnowsCompositor() = default; + +KnowsCompositorMediaProxy::KnowsCompositorMediaProxy( + const TextureFactoryIdentifier& aIdentifier) { + auto lock = mData.Lock(); + lock.ref().mTextureFactoryIdentifier = aIdentifier; + // overwrite mSerial's value set by the parent class because we use the same + // serial as the KnowsCompositor we are proxying. + mThreadSafeAllocator = ImageBridgeChild::GetSingleton(); + lock.ref().mSyncObject = mThreadSafeAllocator->GetSyncObject(); +} + +KnowsCompositorMediaProxy::~KnowsCompositorMediaProxy() = default; + +TextureForwarder* KnowsCompositorMediaProxy::GetTextureForwarder() { + return mThreadSafeAllocator->GetTextureForwarder(); +} + +LayersIPCActor* KnowsCompositorMediaProxy::GetLayersIPCActor() { + return mThreadSafeAllocator->GetLayersIPCActor(); +} + +ActiveResourceTracker* KnowsCompositorMediaProxy::GetActiveResourceTracker() { + return mThreadSafeAllocator->GetActiveResourceTracker(); +} + +void KnowsCompositorMediaProxy::SyncWithCompositor() { + mThreadSafeAllocator->SyncWithCompositor(); +} + +RefPtr ShadowLayerForwarder::GetForMedia() { + return MakeAndAddRef( + GetTextureFactoryIdentifier()); +} + +ShadowLayerForwarder::ShadowLayerForwarder( + ClientLayerManager* aClientLayerManager) + : mClientLayerManager(aClientLayerManager), + mThread(NS_GetCurrentThread()), + mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC), + mIsFirstPaint(false), + mNextLayerHandle(1) { + mTxn = new Transaction(); + mEventTarget = GetMainThreadSerialEventTarget(); + + MOZ_ASSERT(mEventTarget || !XRE_IsContentProcess()); + mActiveResourceTracker = MakeUnique( + 1000, "CompositableForwarder", mEventTarget); +} + +template +struct ReleaseOnMainThreadTask : public Runnable { + UniquePtr mObj; + + explicit ReleaseOnMainThreadTask(UniquePtr& aObj) + : Runnable("layers::ReleaseOnMainThreadTask"), mObj(std::move(aObj)) {} + + NS_IMETHOD Run() override { + mObj = nullptr; + return NS_OK; + } +}; + +ShadowLayerForwarder::~ShadowLayerForwarder() { + MOZ_ASSERT(mTxn->Finished(), "unfinished transaction?"); + delete mTxn; + if (mShadowManager) { + mShadowManager->SetForwarder(nullptr); + if (NS_IsMainThread()) { + mShadowManager->Destroy(); + } else { + if (mEventTarget) { + mEventTarget->Dispatch( + NewRunnableMethod("LayerTransactionChild::Destroy", mShadowManager, + &LayerTransactionChild::Destroy), + nsIEventTarget::DISPATCH_NORMAL); + } else { + NS_DispatchToMainThread( + NewRunnableMethod("layers::LayerTransactionChild::Destroy", + mShadowManager, &LayerTransactionChild::Destroy)); + } + } + } + + if (!NS_IsMainThread()) { + RefPtr> event = + new ReleaseOnMainThreadTask( + mActiveResourceTracker); + if (mEventTarget) { + mEventTarget->Dispatch(event.forget(), nsIEventTarget::DISPATCH_NORMAL); + } else { + NS_DispatchToMainThread(event); + } + } +} + +void ShadowLayerForwarder::BeginTransaction( + const gfx::IntRect& aTargetBounds, ScreenRotation aRotation, + hal::ScreenOrientation aOrientation) { + MOZ_ASSERT(IPCOpen(), "no manager to forward to"); + MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); + UpdateFwdTransactionId(); + mTxn->Begin(aTargetBounds, aRotation, aOrientation); +} + +static const LayerHandle& Shadow(ShadowableLayer* aLayer) { + return aLayer->GetShadow(); +} + +template +static void CreatedLayer(Transaction* aTxn, ShadowableLayer* aLayer) { + aTxn->AddEdit(OpCreateT(Shadow(aLayer))); +} + +void ShadowLayerForwarder::CreatedPaintedLayer(ShadowableLayer* aThebes) { + CreatedLayer(mTxn, aThebes); +} +void ShadowLayerForwarder::CreatedContainerLayer(ShadowableLayer* aContainer) { + CreatedLayer(mTxn, aContainer); +} +void ShadowLayerForwarder::CreatedImageLayer(ShadowableLayer* aImage) { + CreatedLayer(mTxn, aImage); +} +void ShadowLayerForwarder::CreatedColorLayer(ShadowableLayer* aColor) { + CreatedLayer(mTxn, aColor); +} +void ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas) { + CreatedLayer(mTxn, aCanvas); +} +void ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef) { + CreatedLayer(mTxn, aRef); +} + +void ShadowLayerForwarder::Mutated(ShadowableLayer* aMutant) { + mTxn->AddMutant(aMutant); +} + +void ShadowLayerForwarder::MutatedSimple(ShadowableLayer* aMutant) { + mTxn->AddSimpleMutant(aMutant); +} + +void ShadowLayerForwarder::SetRoot(ShadowableLayer* aRoot) { + mTxn->AddEdit(OpSetRoot(Shadow(aRoot))); +} +void ShadowLayerForwarder::InsertAfter(ShadowableLayer* aContainer, + ShadowableLayer* aChild, + ShadowableLayer* aAfter) { + if (!aChild->HasShadow()) { + return; + } + + while (aAfter && !aAfter->HasShadow()) { + aAfter = aAfter->AsLayer()->GetPrevSibling() + ? aAfter->AsLayer()->GetPrevSibling()->AsShadowableLayer() + : nullptr; + } + + if (aAfter) { + mTxn->AddEdit( + OpInsertAfter(Shadow(aContainer), Shadow(aChild), Shadow(aAfter))); + } else { + mTxn->AddEdit(OpPrependChild(Shadow(aContainer), Shadow(aChild))); + } +} +void ShadowLayerForwarder::RemoveChild(ShadowableLayer* aContainer, + ShadowableLayer* aChild) { + MOZ_LAYERS_LOG(("[LayersForwarder] OpRemoveChild container=%p child=%p\n", + aContainer->AsLayer(), aChild->AsLayer())); + + if (!aChild->HasShadow()) { + return; + } + + mTxn->AddEdit(OpRemoveChild(Shadow(aContainer), Shadow(aChild))); +} +void ShadowLayerForwarder::RepositionChild(ShadowableLayer* aContainer, + ShadowableLayer* aChild, + ShadowableLayer* aAfter) { + if (!aChild->HasShadow()) { + return; + } + + while (aAfter && !aAfter->HasShadow()) { + aAfter = aAfter->AsLayer()->GetPrevSibling() + ? aAfter->AsLayer()->GetPrevSibling()->AsShadowableLayer() + : nullptr; + } + + if (aAfter) { + MOZ_LAYERS_LOG( + ("[LayersForwarder] OpRepositionChild container=%p child=%p after=%p", + aContainer->AsLayer(), aChild->AsLayer(), aAfter->AsLayer())); + mTxn->AddEdit( + OpRepositionChild(Shadow(aContainer), Shadow(aChild), Shadow(aAfter))); + } else { + MOZ_LAYERS_LOG(("[LayersForwarder] OpRaiseToTopChild container=%p child=%p", + aContainer->AsLayer(), aChild->AsLayer())); + mTxn->AddEdit(OpRaiseToTopChild(Shadow(aContainer), Shadow(aChild))); + } +} + +#ifdef DEBUG +void ShadowLayerForwarder::CheckSurfaceDescriptor( + const SurfaceDescriptor* aDescriptor) const { + if (!aDescriptor) { + return; + } + + if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer && + aDescriptor->get_SurfaceDescriptorBuffer().data().type() == + MemoryOrShmem::TShmem) { + const Shmem& shmem = + aDescriptor->get_SurfaceDescriptorBuffer().data().get_Shmem(); + shmem.AssertInvariants(); + MOZ_ASSERT(mShadowManager && + mShadowManager->IsTrackingSharedMemory(shmem.mSegment)); + } +} +#endif + +void ShadowLayerForwarder::UseTiledLayerBuffer( + CompositableClient* aCompositable, + const SurfaceDescriptorTiles& aTileLayerDescriptor) { + MOZ_ASSERT(aCompositable); + + if (!aCompositable->IsConnected()) { + return; + } + + mTxn->AddNoSwapPaint( + CompositableOperation(aCompositable->GetIPCHandle(), + OpUseTiledLayerBuffer(aTileLayerDescriptor))); +} + +void ShadowLayerForwarder::UpdateTextureRegion( + CompositableClient* aCompositable, + const ThebesBufferData& aThebesBufferData, + const nsIntRegion& aUpdatedRegion) { + MOZ_ASSERT(aCompositable); + + if (!aCompositable->IsConnected()) { + return; + } + + mTxn->AddNoSwapPaint(CompositableOperation( + aCompositable->GetIPCHandle(), + OpPaintTextureRegion(aThebesBufferData, aUpdatedRegion))); +} + +void ShadowLayerForwarder::UseTextures( + CompositableClient* aCompositable, + const nsTArray& aTextures) { + MOZ_ASSERT(aCompositable); +} + +void ShadowLayerForwarder::UseComponentAlphaTextures( + CompositableClient* aCompositable, TextureClient* aTextureOnBlack, + TextureClient* aTextureOnWhite) { + MOZ_ASSERT(aCompositable); + + return; +} + +static bool AddOpDestroy(Transaction* aTxn, const OpDestroy& op) { + if (!aTxn->Opened()) { + return false; + } + + aTxn->mDestroyedActors.AppendElement(op); + return true; +} + +bool ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture) { + return AddOpDestroy(mTxn, OpDestroy(aTexture)); +} + +bool ShadowLayerForwarder::DestroyInTransaction( + const CompositableHandle& aHandle) { + return AddOpDestroy(mTxn, OpDestroy(aHandle)); +} + +void ShadowLayerForwarder::RemoveTextureFromCompositable( + CompositableClient* aCompositable, TextureClient* aTexture) { + MOZ_ASSERT(aCompositable); + MOZ_ASSERT(aTexture); + MOZ_ASSERT(aTexture->GetIPDLActor()); + MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() == + mShadowManager->GetIPCChannel()); + if (!aCompositable->IsConnected() || !aTexture->GetIPDLActor()) { + // We don't have an actor anymore, don't try to use it! + return; + } + + mTxn->AddEdit(CompositableOperation( + aCompositable->GetIPCHandle(), + OpRemoveTexture(nullptr, aTexture->GetIPDLActor()))); +} + +bool ShadowLayerForwarder::InWorkerThread() { + return GetTextureForwarder()->GetThread()->IsOnCurrentThread(); +} + +void ShadowLayerForwarder::SendPaintTime(TransactionId aId, + TimeDuration aPaintTime) { + if (!IPCOpen() || !mShadowManager->SendPaintTime(aId, aPaintTime)) { + NS_WARNING("Could not send paint times over IPC"); + } +} + +bool ShadowLayerForwarder::EndTransaction( + const nsIntRegion& aRegionToClear, TransactionId aId, + bool aScheduleComposite, uint32_t aPaintSequenceNumber, + bool aIsRepeatTransaction, const mozilla::VsyncId& aVsyncId, + const mozilla::TimeStamp& aVsyncStart, + const mozilla::TimeStamp& aRefreshStart, + const mozilla::TimeStamp& aTransactionStart, bool aContainsSVG, + const nsCString& aURL, bool* aSent, + const nsTArray& aPayload) { + *aSent = false; + + TransactionInfo info; + + MOZ_ASSERT(IPCOpen(), "no manager to forward to"); + if (!IPCOpen()) { + return false; + } + + Maybe startTime; + if (StaticPrefs::layers_acceleration_draw_fps()) { + startTime = Some(TimeStamp::Now()); + } + + GetCompositorBridgeChild()->WillEndTransaction(); + + MOZ_ASSERT(aId.IsValid()); + + AUTO_PROFILER_LABEL("ShadowLayerForwarder::EndTransaction", GRAPHICS); + + RenderTraceScope rendertrace("Foward Transaction", "000091"); + MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); + + DiagnosticTypes diagnostics = + gfxPlatform::GetPlatform()->GetLayerDiagnosticTypes(); + if (mDiagnosticTypes != diagnostics) { + mDiagnosticTypes = diagnostics; + mTxn->AddEdit(OpSetDiagnosticTypes(diagnostics)); + } + + AutoTxnEnd _(mTxn); + + if (mTxn->Empty() && !mTxn->RotationChanged()) { + MOZ_LAYERS_LOG( + ("[LayersForwarder] 0-length cset (?) and no rotation event, skipping " + "Update()")); + return true; + } + + MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers...")); + + MOZ_LAYERS_LOG(("[LayersForwarder] building transaction...")); + + nsTArray setSimpleAttrs; + for (ShadowableLayer* shadow : mTxn->mSimpleMutants) { + if (!shadow->HasShadow()) { + continue; + } + + Layer* mutant = shadow->AsLayer(); + setSimpleAttrs.AppendElement(OpSetSimpleLayerAttributes( + Shadow(shadow), mutant->GetSimpleAttributes())); + } + + nsTArray setAttrs; + + // We purposely add attribute-change ops to the final changeset + // before we add paint ops. This allows layers to record the + // attribute changes before new pixels arrive, which can be useful + // for setting up back/front buffers. + RenderTraceScope rendertrace2("Foward Transaction", "000092"); + for (ShadowableLayer* shadow : mTxn->mMutants) { + if (!shadow->HasShadow()) { + continue; + } + Layer* mutant = shadow->AsLayer(); + MOZ_ASSERT(!!mutant, "unshadowable layer?"); + + OpSetLayerAttributes op; + op.layer() = Shadow(shadow); + + LayerAttributes& attrs = op.attrs(); + CommonLayerAttributes& common = attrs.common(); + common.visibleRegion() = mutant->GetVisibleRegion(); + common.eventRegions() = mutant->GetEventRegions(); + common.useClipRect() = !!mutant->GetClipRect(); + common.clipRect() = + (common.useClipRect() ? *mutant->GetClipRect() : ParentLayerIntRect()); + if (Layer* maskLayer = mutant->GetMaskLayer()) { + common.maskLayer() = Shadow(maskLayer->AsShadowableLayer()); + } else { + common.maskLayer() = LayerHandle(); + } + common.compositorAnimations().id() = mutant->GetCompositorAnimationsId(); + common.compositorAnimations().animations() = + mutant->GetAnimations().Clone(); + common.invalidRegion() = mutant->GetInvalidRegion().GetRegion(); + common.scrollMetadata() = mutant->GetAllScrollMetadata().Clone(); + for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) { + auto layer = + Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer()); + common.ancestorMaskLayers().AppendElement(layer); + } + nsCString log; + mutant->GetDisplayListLog(log); + common.displayListLog() = log; + + attrs.specific() = null_t(); + mutant->FillSpecificAttributes(attrs.specific()); + + MOZ_LAYERS_LOG(("[LayersForwarder] OpSetLayerAttributes(%p)\n", mutant)); + + setAttrs.AppendElement(op); + } + + if (mTxn->mCset.IsEmpty() && mTxn->mPaints.IsEmpty() && setAttrs.IsEmpty() && + !mTxn->RotationChanged()) { + return true; + } + + info.cset() = std::move(mTxn->mCset); + info.setSimpleAttrs() = std::move(setSimpleAttrs); + info.setAttrs() = std::move(setAttrs); + info.paints() = std::move(mTxn->mPaints); + info.toDestroy() = mTxn->mDestroyedActors.Clone(); + info.fwdTransactionId() = GetFwdTransactionId(); + info.id() = aId; + info.isFirstPaint() = mIsFirstPaint; + info.focusTarget() = mFocusTarget; + info.scheduleComposite() = aScheduleComposite; + info.paintSequenceNumber() = aPaintSequenceNumber; + info.isRepeatTransaction() = aIsRepeatTransaction; + info.vsyncId() = aVsyncId; + info.vsyncStart() = aVsyncStart; + info.refreshStart() = aRefreshStart; + info.transactionStart() = aTransactionStart; + info.url() = aURL; + info.containsSVG() = aContainsSVG; +#if defined(ENABLE_FRAME_LATENCY_LOG) + info.fwdTime() = TimeStamp::Now(); +#endif + info.payload() = aPayload.Clone(); + + TargetConfig targetConfig(mTxn->mTargetBounds, mTxn->mTargetRotation, + mTxn->mTargetOrientation, aRegionToClear); + info.targetConfig() = targetConfig; + + if (!GetTextureForwarder()->IsSameProcess()) { + MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send...")); + PlatformSyncBeforeUpdate(); + } + + if (startTime) { + mPaintTiming.serializeMs() = + (TimeStamp::Now() - startTime.value()).ToMilliseconds(); + startTime = Some(TimeStamp::Now()); + } + + MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction...")); + RenderTraceScope rendertrace3("Forward Transaction", "000093"); + if (!mShadowManager->SendUpdate(info)) { + MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!")); + return false; + } + + if (startTime) { + mPaintTiming.sendMs() = + (TimeStamp::Now() - startTime.value()).ToMilliseconds(); + mShadowManager->SendRecordPaintTimes(mPaintTiming); + } + + *aSent = true; + mIsFirstPaint = false; + mFocusTarget = FocusTarget(); + MOZ_LAYERS_LOG(("[LayersForwarder] ... done")); + return true; +} + +RefPtr ShadowLayerForwarder::FindCompositable( + const CompositableHandle& aHandle) { + CompositableClient* client = nullptr; + if (!mCompositables.Get(aHandle.Value(), &client)) { + return nullptr; + } + return client; +} + +void ShadowLayerForwarder::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) { + if (!IPCOpen()) { + return; + } + Unused << mShadowManager->SendSetLayersObserverEpoch(aEpoch); +} + +void ShadowLayerForwarder::UpdateTextureLocks() { +#ifdef XP_DARWIN + if (!IPCOpen()) { + return; + } + + auto compositorBridge = GetCompositorBridgeChild(); + if (compositorBridge) { + auto pid = compositorBridge->OtherPid(); + TextureSync::UpdateTextureLocks(pid); + } +#endif +} + +void ShadowLayerForwarder::SyncTextures(const nsTArray& aSerials) { +#ifdef XP_DARWIN + if (!IPCOpen()) { + return; + } + + auto compositorBridge = GetCompositorBridgeChild(); + if (compositorBridge) { + auto pid = compositorBridge->OtherPid(); + TextureSync::WaitForTextures(pid, aSerials); + } +#endif +} + +void ShadowLayerForwarder::ReleaseLayer(const LayerHandle& aHandle) { + if (!IPCOpen()) { + return; + } + Unused << mShadowManager->SendReleaseLayer(aHandle); +} + +bool ShadowLayerForwarder::IPCOpen() const { + return HasShadowManager() && mShadowManager->IPCOpen(); +} + +/** + * We bail out when we have no shadow manager. That can happen when the + * layer manager is created by the preallocated process. + * See bug 914843 for details. + */ +LayerHandle ShadowLayerForwarder::ConstructShadowFor(ShadowableLayer* aLayer) { + return LayerHandle(mNextLayerHandle++); +} + +#if !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS) + +/*static*/ +void ShadowLayerForwarder::PlatformSyncBeforeUpdate() {} + +#endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS) + +void ShadowLayerForwarder::Connect(CompositableClient* aCompositable, + ImageContainer* aImageContainer) { +#ifdef GFX_COMPOSITOR_LOGGING + printf("ShadowLayerForwarder::Connect(Compositable)\n"); +#endif + MOZ_ASSERT(aCompositable); + MOZ_ASSERT(mShadowManager); + if (!IPCOpen()) { + return; + } + + static uint64_t sNextID = 1; + uint64_t id = sNextID++; + + mCompositables.InsertOrUpdate(id, aCompositable); + + CompositableHandle handle(id); + aCompositable->InitIPDL(handle); + mShadowManager->SendNewCompositable(handle, aCompositable->GetTextureInfo()); +} + +void ShadowLayerForwarder::Attach(CompositableClient* aCompositable, + ShadowableLayer* aLayer) { + MOZ_ASSERT(aLayer); + MOZ_ASSERT(aCompositable); + mTxn->AddEdit( + OpAttachCompositable(Shadow(aLayer), aCompositable->GetIPCHandle())); +} + +void ShadowLayerForwarder::AttachAsyncCompositable( + const CompositableHandle& aHandle, ShadowableLayer* aLayer) { + MOZ_ASSERT(aLayer); + MOZ_ASSERT(aHandle); + mTxn->AddEdit(OpAttachAsyncCompositable(Shadow(aLayer), aHandle)); +} + +void ShadowLayerForwarder::SetShadowManager( + PLayerTransactionChild* aShadowManager) { + mShadowManager = static_cast(aShadowManager); + mShadowManager->SetForwarder(this); +} + +void ShadowLayerForwarder::StopReceiveAsyncParentMessge() { + if (!IPCOpen()) { + return; + } + mShadowManager->SetForwarder(nullptr); +} + +void ShadowLayerForwarder::ClearCachedResources() { + if (!IPCOpen()) { + return; + } + mShadowManager->SendClearCachedResources(); +} + +void ShadowLayerForwarder::ScheduleComposite() { + if (!IPCOpen()) { + return; + } + mShadowManager->SendScheduleComposite(); +} + +bool IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface) { + return aSurface.type() != SurfaceDescriptor::T__None && + aSurface.type() != SurfaceDescriptor::Tnull_t; +} + +uint8_t* GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor) { + MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor)); + MOZ_RELEASE_ASSERT( + aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer, + "GFX: surface descriptor is not the right type."); + + auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data(); + if (memOrShmem.type() == MemoryOrShmem::TShmem) { + return memOrShmem.get_Shmem().get(); + } else { + return reinterpret_cast(memOrShmem.get_uintptr_t()); + } +} + +already_AddRefed GetSurfaceForDescriptor( + const SurfaceDescriptor& aDescriptor) { + if (aDescriptor.type() != SurfaceDescriptor::TSurfaceDescriptorBuffer) { + return nullptr; + } + uint8_t* data = GetAddressFromDescriptor(aDescriptor); + auto rgb = + aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor(); + uint32_t stride = ImageDataSerializer::GetRGBStride(rgb); + return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(), + rgb.format()); +} + +already_AddRefed GetDrawTargetForDescriptor( + const SurfaceDescriptor& aDescriptor) { + uint8_t* data = GetAddressFromDescriptor(aDescriptor); + auto rgb = + aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor(); + uint32_t stride = ImageDataSerializer::GetRGBStride(rgb); + return gfx::Factory::CreateDrawTargetForData( + gfx::BackendType::SKIA, data, rgb.size(), stride, rgb.format()); +} + +void DestroySurfaceDescriptor(IShmemAllocator* aAllocator, + SurfaceDescriptor* aSurface) { + MOZ_ASSERT(aSurface); + + SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer(); + switch (desc.data().type()) { + case MemoryOrShmem::TShmem: { + aAllocator->DeallocShmem(desc.data().get_Shmem()); + break; + } + case MemoryOrShmem::Tuintptr_t: { + uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t(); + GfxMemoryImageReporter::WillFree(ptr); + delete[] ptr; + break; + } + default: + MOZ_CRASH("surface type not implemented!"); + } + *aSurface = SurfaceDescriptor(); +} + +bool ShadowLayerForwarder::AllocSurfaceDescriptor(const gfx::IntSize& aSize, + gfxContentType aContent, + SurfaceDescriptor* aBuffer) { + if (!IPCOpen()) { + return false; + } + return AllocSurfaceDescriptorWithCaps(aSize, aContent, DEFAULT_BUFFER_CAPS, + aBuffer); +} + +bool ShadowLayerForwarder::AllocSurfaceDescriptorWithCaps( + const gfx::IntSize& aSize, gfxContentType aContent, uint32_t aCaps, + SurfaceDescriptor* aBuffer) { + if (!IPCOpen()) { + return false; + } + gfx::SurfaceFormat format = + gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent); + size_t size = ImageDataSerializer::ComputeRGBBufferSize(aSize, format); + if (!size) { + return false; + } + + MemoryOrShmem bufferDesc; + if (GetTextureForwarder()->IsSameProcess()) { + uint8_t* data = new (std::nothrow) uint8_t[size]; + if (!data) { + return false; + } + GfxMemoryImageReporter::DidAlloc(data); + memset(data, 0, size); + bufferDesc = reinterpret_cast(data); + } else { + mozilla::ipc::Shmem shmem; + if (!GetTextureForwarder()->AllocUnsafeShmem(size, OptimalShmemType(), + &shmem)) { + return false; + } + + bufferDesc = std::move(shmem); + } + + // Use an intermediate buffer by default. Skipping the intermediate buffer is + // only possible in certain configurations so let's keep it simple here for + // now. + const bool hasIntermediateBuffer = true; + *aBuffer = SurfaceDescriptorBuffer( + RGBDescriptor(aSize, format, hasIntermediateBuffer), bufferDesc); + + return true; +} + +/* static */ +bool ShadowLayerForwarder::IsShmem(SurfaceDescriptor* aSurface) { + return aSurface && + (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer) && + (aSurface->get_SurfaceDescriptorBuffer().data().type() == + MemoryOrShmem::TShmem); +} + +void ShadowLayerForwarder::DestroySurfaceDescriptor( + SurfaceDescriptor* aSurface) { + MOZ_ASSERT(aSurface); + MOZ_ASSERT(IPCOpen()); + if (!IPCOpen() || !aSurface) { + return; + } + + ::mozilla::layers::DestroySurfaceDescriptor(GetTextureForwarder(), aSurface); +} + +void ShadowLayerForwarder::UpdateFwdTransactionId() { + auto compositorBridge = GetCompositorBridgeChild(); + if (compositorBridge) { + compositorBridge->UpdateFwdTransactionId(); + } +} + +uint64_t ShadowLayerForwarder::GetFwdTransactionId() { + auto compositorBridge = GetCompositorBridgeChild(); + MOZ_DIAGNOSTIC_ASSERT(compositorBridge); + return compositorBridge ? compositorBridge->GetFwdTransactionId() : 0; +} + +CompositorBridgeChild* ShadowLayerForwarder::GetCompositorBridgeChild() { + if (mCompositorBridgeChild) { + return mCompositorBridgeChild; + } + if (!mShadowManager) { + return nullptr; + } + mCompositorBridgeChild = + static_cast(mShadowManager->Manager()); + return mCompositorBridgeChild; +} + +void ShadowLayerForwarder::SyncWithCompositor() { + auto compositorBridge = GetCompositorBridgeChild(); + if (compositorBridge && compositorBridge->IPCOpen()) { + compositorBridge->SendSyncWithCompositor(); + } +} + +void ShadowLayerForwarder::ReleaseCompositable( + const CompositableHandle& aHandle) { + AssertInForwarderThread(); + if (!DestroyInTransaction(aHandle)) { + if (!IPCOpen()) { + return; + } + mShadowManager->SendReleaseCompositable(aHandle); + } + mCompositables.Remove(aHandle.Value()); +} + +void ShadowLayerForwarder::SynchronouslyShutdown() { + if (IPCOpen()) { + mShadowManager->SendShutdownSync(); + mShadowManager->MarkDestroyed(); + } +} + +ShadowableLayer::~ShadowableLayer() { + if (mShadow) { + mForwarder->ReleaseLayer(GetShadow()); + } +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h new file mode 100644 index 0000000000000..d3b29d7c1ec08 --- /dev/null +++ b/gfx/layers/ipc/ShadowLayers.h @@ -0,0 +1,473 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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/. */ + +#ifndef mozilla_layers_ShadowLayers_h +#define mozilla_layers_ShadowLayers_h 1 + +#include // for size_t +#include // for uint64_t +#include "gfxTypes.h" +#include "mozilla/Attributes.h" // for override +#include "mozilla/gfx/Rect.h" +#include "mozilla/WidgetUtils.h" // for ScreenRotation +#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc +#include "mozilla/HalScreenConfiguration.h" // for ScreenOrientation +#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/FocusTarget.h" +#include "mozilla/layers/LayersTypes.h" +#include "mozilla/layers/TextureForwarder.h" +#include "mozilla/layers/CompositorTypes.h" // for OpenMode, etc +#include "mozilla/layers/CompositorBridgeChild.h" +#include "nsCOMPtr.h" // for already_AddRefed +#include "nsRegion.h" // for nsIntRegion +#include "nsTArrayForwardDeclare.h" // for nsTArray +#include "nsTHashMap.h" +#include "nsIWidget.h" +#include + +namespace mozilla { +namespace layers { + +class ClientLayerManager; +class CompositorBridgeChild; +class FixedSizeSmallShmemSectionAllocator; +class ImageContainer; +class Layer; +class PLayerTransactionChild; +class LayerTransactionChild; +class ShadowableLayer; +class SurfaceDescriptor; +class TextureClient; +class ThebesBuffer; +class ThebesBufferData; +class Transaction; + +/** + * We want to share layer trees across thread contexts and address + * spaces for several reasons; chief among them + * + * - a parent process can paint a child process's layer tree while + * the child process is blocked, say on content script. This is + * important on mobile devices where UI responsiveness is key. + * + * - a dedicated "compositor" process can asynchronously (wrt the + * browser process) composite and animate layer trees, allowing a + * form of pipeline parallelism between compositor/browser/content + * + * - a dedicated "compositor" process can take all responsibility for + * accessing the GPU, which is desirable on systems with + * buggy/leaky drivers because the compositor process can die while + * browser and content live on (and failover mechanisms can be + * installed to quickly bring up a replacement compositor) + * + * The Layers model has a crisply defined API, which makes it easy to + * safely "share" layer trees. The ShadowLayers API extends Layers to + * allow a remote, parent process to access a child process's layer + * tree. + * + * ShadowLayerForwarder publishes a child context's layer tree to a + * parent context. This comprises recording layer-tree modifications + * into atomic transactions and pushing them over IPC. + * + * LayerManagerComposite grafts layer subtrees published by child-context + * ShadowLayerForwarder(s) into a parent-context layer tree. + * + * (Advanced note: because our process tree may have a height >2, a + * non-leaf subprocess may both receive updates from child processes + * and publish them to parent processes. Put another way, + * LayerManagers may be both LayerManagerComposites and + * ShadowLayerForwarders.) + * + * There are only shadow types for layers that have different shadow + * vs. not-shadow behavior. ColorLayers and ContainerLayers behave + * the same way in both regimes (so far). + * + * + * The mecanism to shadow the layer tree on the compositor through IPC works as + * follows: + * The layer tree is managed on the content thread, and shadowed in the + * compositor thread. The shadow layer tree is only kept in sync with whatever + * happens in the content thread. To do this we use IPDL protocols. IPDL is a + * domain specific language that describes how two processes or thread should + * communicate. C++ code is generated from .ipdl files to implement the message + * passing, synchronization and serialization logic. To use the generated code + * we implement classes that inherit the generated IPDL actor. the ipdl actors + * of a protocol PX are PXChild or PXParent (the generated class), and we + * conventionally implement XChild and XParent. The Parent side of the protocol + * is the one that lives on the compositor thread. Think of IPDL actors as + * endpoints of communication. they are useful to send messages and also to + * dispatch the message to the right actor on the other side. One nice property + * of an IPDL actor is that when an actor, say PXChild is sent in a message, the + * PXParent comes out in the other side. we use this property a lot to dispatch + * messages to the right layers and compositable, each of which have their own + * ipdl actor on both side. + * + * Most of the synchronization logic happens in layer transactions and + * compositable transactions. + * A transaction is a set of changes to the layers and/or the compositables + * that are sent and applied together to the compositor thread to keep the + * LayerComposite in a coherent state. + * Layer transactions maintain the shape of the shadow layer tree, and + * synchronize the texture data held by compositables. Layer transactions + * are always between the content thread and the compositor thread. + * Compositable transactions are subset of a layer transaction with which only + * compositables and textures can be manipulated, and does not always originate + * from the content thread. (See CompositableForwarder.h and ImageBridgeChild.h) + */ + +class ShadowLayerForwarder final : public LayersIPCActor, + public CompositableForwarder, + public LegacySurfaceDescriptorAllocator { + friend class ClientLayerManager; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ShadowLayerForwarder, override); + + /** + * Setup the IPDL actor for aCompositable to be part of layers + * transactions. + */ + void Connect(CompositableClient* aCompositable, + ImageContainer* aImageContainer) override; + + /** + * Adds an edit in the layers transaction in order to attach + * the corresponding compositable and layer on the compositor side. + * Connect must have been called on aCompositable beforehand. + */ + void Attach(CompositableClient* aCompositable, ShadowableLayer* aLayer); + + /** + * Adds an edit in the transaction in order to attach a Compositable that + * is not managed by this ShadowLayerForwarder (for example, by ImageBridge + * in the case of async-video). + * Since the compositable is not managed by this forwarder, we can't use + * the compositable or it's IPDL actor here, so we use an ID instead, that + * is matched on the compositor side. + */ + void AttachAsyncCompositable(const CompositableHandle& aHandle, + ShadowableLayer* aLayer); + + /** + * Begin recording a transaction to be forwarded atomically to a + * LayerManagerComposite. + */ + void BeginTransaction(const gfx::IntRect& aTargetBounds, + ScreenRotation aRotation, + hal::ScreenOrientation aOrientation); + + /** + * The following methods may only be called after BeginTransaction() + * but before EndTransaction(). They mirror the LayerManager + * interface in Layers.h. + */ + + /** + * Notify the shadow manager that a new, "real" layer has been + * created, and a corresponding shadow layer should be created in + * the compositing process. + */ + void CreatedPaintedLayer(ShadowableLayer* aThebes); + void CreatedContainerLayer(ShadowableLayer* aContainer); + void CreatedImageLayer(ShadowableLayer* aImage); + void CreatedColorLayer(ShadowableLayer* aColor); + void CreatedCanvasLayer(ShadowableLayer* aCanvas); + void CreatedRefLayer(ShadowableLayer* aRef); + + /** + * At least one attribute of |aMutant| has changed, and |aMutant| + * needs to sync to its shadow layer. This initial implementation + * forwards all attributes when any of the appropriate attribute + * set is mutated. + */ + void Mutated(ShadowableLayer* aMutant); + void MutatedSimple(ShadowableLayer* aMutant); + + void SetRoot(ShadowableLayer* aRoot); + /** + * Insert |aChild| after |aAfter| in |aContainer|. |aAfter| can be + * nullptr to indicated that |aChild| should be appended to the end of + * |aContainer|'s child list. + */ + void InsertAfter(ShadowableLayer* aContainer, ShadowableLayer* aChild, + ShadowableLayer* aAfter = nullptr); + void RemoveChild(ShadowableLayer* aContainer, ShadowableLayer* aChild); + void RepositionChild(ShadowableLayer* aContainer, ShadowableLayer* aChild, + ShadowableLayer* aAfter = nullptr); + + /** + * Set aMaskLayer as the mask on aLayer. + * Note that only image layers are properly supported + * LayerTransactionParent::UpdateMask and accompanying ipdl + * will need changing to update properties for other kinds + * of mask layer. + */ + void SetMask(ShadowableLayer* aLayer, ShadowableLayer* aMaskLayer); + + /** + * See CompositableForwarder::UseTiledLayerBuffer + */ + void UseTiledLayerBuffer( + CompositableClient* aCompositable, + const SurfaceDescriptorTiles& aTileLayerDescriptor) override; + + void ReleaseCompositable(const CompositableHandle& aHandle) override; + bool DestroyInTransaction(PTextureChild* aTexture) override; + bool DestroyInTransaction(const CompositableHandle& aHandle); + + void RemoveTextureFromCompositable(CompositableClient* aCompositable, + TextureClient* aTexture) override; + + /** + * Communicate to the compositor that aRegion in the texture identified by + * aLayer and aIdentifier has been updated to aThebesBuffer. + */ + void UpdateTextureRegion(CompositableClient* aCompositable, + const ThebesBufferData& aThebesBufferData, + const nsIntRegion& aUpdatedRegion) override; + + /** + * See CompositableForwarder::UseTextures + */ + void UseTextures(CompositableClient* aCompositable, + const nsTArray& aTextures) override; + void UseComponentAlphaTextures(CompositableClient* aCompositable, + TextureClient* aClientOnBlack, + TextureClient* aClientOnWhite) override; + + /** + * Used for debugging to tell the compositor how long this frame took to + * paint. + */ + void SendPaintTime(TransactionId aId, TimeDuration aPaintTime); + + /** + * End the current transaction and forward it to LayerManagerComposite. + * |aReplies| are directions from the LayerManagerComposite to the + * caller of EndTransaction(). + */ + bool EndTransaction(const nsIntRegion& aRegionToClear, TransactionId aId, + bool aScheduleComposite, uint32_t aPaintSequenceNumber, + bool aIsRepeatTransaction, + const mozilla::VsyncId& aVsyncId, + const mozilla::TimeStamp& aVsyncTime, + const mozilla::TimeStamp& aRefreshStart, + const mozilla::TimeStamp& aTransactionStart, + bool aContainsSVG, const nsCString& aURL, bool* aSent, + const nsTArray& aPayload = + nsTArray()); + + /** + * Set an actor through which layer updates will be pushed. + */ + void SetShadowManager(PLayerTransactionChild* aShadowManager); + + void StopReceiveAsyncParentMessge(); + + void ClearCachedResources(); + + void ScheduleComposite(); + + /** + * True if this is forwarding to a LayerManagerComposite. + */ + bool HasShadowManager() const { return !!mShadowManager; } + LayerTransactionChild* GetShadowManager() const { + return mShadowManager.get(); + } + + // Send a synchronous message asking the LayerTransactionParent in the + // compositor to shutdown. + void SynchronouslyShutdown(); + + /** + * The following Alloc/Open/Destroy interfaces abstract over the + * details of working with surfaces that are shared across + * processes. They provide the glue between C++ Layers and the + * LayerComposite IPC system. + * + * The basic lifecycle is + * + * - a Layer needs a buffer. Its ShadowableLayer subclass calls + * AllocBuffer(), then calls one of the Created*Buffer() methods + * above to transfer the (temporary) front buffer to its + * LayerComposite in the other process. The Layer needs a + * gfxASurface to paint, so the ShadowableLayer uses + * OpenDescriptor(backBuffer) to get that surface, and hands it + * out to the Layer. + * + * - a Layer has painted new pixels. Its ShadowableLayer calls one + * of the Painted*Buffer() methods above with the back buffer + * descriptor. This notification is forwarded to the LayerComposite, + * which uses OpenDescriptor() to access the newly-painted pixels. + * The LayerComposite then updates its front buffer in a Layer- and + * platform-dependent way, and sends a surface descriptor back to + * the ShadowableLayer that becomes its new back back buffer. + * + * - a Layer wants to destroy its buffers. Its ShadowableLayer + * calls Destroyed*Buffer(), which gives up control of the back + * buffer descriptor. The actual back buffer surface is then + * destroyed using DestroySharedSurface() just before notifying + * the parent process. When the parent process is notified, the + * LayerComposite also calls DestroySharedSurface() on its front + * buffer, and the double-buffer pair is gone. + */ + + bool IPCOpen() const override; + + /** + * Construct a shadow of |aLayer| on the "other side", at the + * LayerManagerComposite. + */ + LayerHandle ConstructShadowFor(ShadowableLayer* aLayer); + + /** + * Flag the next paint as the first for a document. + */ + void SetIsFirstPaint() { mIsFirstPaint = true; } + bool GetIsFirstPaint() const { return mIsFirstPaint; } + + /** + * Set the current focus target to be sent with the next paint. + */ + void SetFocusTarget(const FocusTarget& aFocusTarget) { + mFocusTarget = aFocusTarget; + } + + void SetLayersObserverEpoch(LayersObserverEpoch aEpoch); + + static void PlatformSyncBeforeUpdate(); + + bool AllocSurfaceDescriptor(const gfx::IntSize& aSize, + gfxContentType aContent, + SurfaceDescriptor* aBuffer) override; + + bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize, + gfxContentType aContent, uint32_t aCaps, + SurfaceDescriptor* aBuffer) override; + + void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) override; + + void UpdateFwdTransactionId() override; + uint64_t GetFwdTransactionId() override; + + void UpdateTextureLocks(); + void SyncTextures(const nsTArray& aSerials); + + void ReleaseLayer(const LayerHandle& aHandle); + + bool InForwarderThread() override { return NS_IsMainThread(); } + + PaintTiming& GetPaintTiming() { return mPaintTiming; } + + ShadowLayerForwarder* AsLayerForwarder() override { return this; } + + // Returns true if aSurface wraps a Shmem. + static bool IsShmem(SurfaceDescriptor* aSurface); + + void SyncWithCompositor() override; + + TextureForwarder* GetTextureForwarder() override { + return GetCompositorBridgeChild(); + } + LayersIPCActor* GetLayersIPCActor() override { return this; } + + ActiveResourceTracker* GetActiveResourceTracker() override { + return mActiveResourceTracker.get(); + } + + CompositorBridgeChild* GetCompositorBridgeChild(); + + nsISerialEventTarget* GetEventTarget() { return mEventTarget; }; + + bool IsThreadSafe() const override { return false; } + + RefPtr GetForMedia() override; + + protected: + virtual ~ShadowLayerForwarder(); + + explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager); + +#ifdef DEBUG + void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const; +#else + void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {} +#endif + + RefPtr FindCompositable( + const CompositableHandle& aHandle); + + bool InWorkerThread(); + + RefPtr mShadowManager; + RefPtr mCompositorBridgeChild; + + private: + ClientLayerManager* mClientLayerManager; + Transaction* mTxn; + nsCOMPtr mThread; + DiagnosticTypes mDiagnosticTypes; + bool mIsFirstPaint; + FocusTarget mFocusTarget; + UniquePtr mActiveResourceTracker; + uint64_t mNextLayerHandle; + nsTHashMap mCompositables; + PaintTiming mPaintTiming; + /** + * ShadowLayerForwarder might dispatch tasks to main while puppet widget and + * browserChild don't exist anymore; therefore we hold the event target since + * its lifecycle is independent of these objects. + */ + nsCOMPtr mEventTarget; +}; + +class CompositableClient; + +/** + * A ShadowableLayer is a Layer can be shared with a parent context + * through a ShadowLayerForwarder. A ShadowableLayer maps to a + * Shadow*Layer in a parent context. + * + * Note that ShadowLayers can themselves be ShadowableLayers. + */ +class ShadowableLayer { + public: + virtual ~ShadowableLayer(); + + virtual Layer* AsLayer() = 0; + + /** + * True if this layer has a shadow in a parent process. + */ + bool HasShadow() { return mShadow.IsValid(); } + + /** + * Return the IPC handle to a Shadow*Layer referring to this if one + * exists, nullptr if not. + */ + const LayerHandle& GetShadow() { return mShadow; } + + void SetShadow(ShadowLayerForwarder* aForwarder, const LayerHandle& aShadow) { + MOZ_ASSERT(!mShadow, "can't have two shadows (yet)"); + mForwarder = aForwarder; + mShadow = aShadow; + } + + virtual CompositableClient* GetCompositableClient() { return nullptr; } + + protected: + ShadowableLayer() = default; + + private: + RefPtr mForwarder; + LayerHandle mShadow; +}; + +} // namespace layers +} // namespace mozilla + +#endif // ifndef mozilla_layers_ShadowLayers_h diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 5656597ae801d..33501fbc768b6 100755 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -186,9 +186,12 @@ EXPORTS.mozilla.layers += [ "ipc/KnowsCompositor.h", "ipc/LayerAnimationUtils.h", "ipc/LayersMessageUtils.h", + "ipc/LayerTransactionChild.h", + "ipc/LayerTransactionParent.h", "ipc/LayerTreeOwnerTracker.h", "ipc/RefCountedShmem.h", "ipc/RemoteContentController.h", + "ipc/ShadowLayers.h", "ipc/SharedPlanarYCbCrImage.h", "ipc/SharedRGBImage.h", "ipc/SharedSurfacesChild.h", @@ -439,11 +442,13 @@ UNIFIED_SOURCES += [ "ipc/ImageBridgeChild.cpp", "ipc/ImageBridgeParent.cpp", "ipc/ISurfaceAllocator.cpp", - "ipc/KnowsCompositor.cpp", "ipc/LayerAnimationUtils.cpp", + "ipc/LayerTransactionChild.cpp", + "ipc/LayerTransactionParent.cpp", "ipc/LayerTreeOwnerTracker.cpp", "ipc/RefCountedShmem.cpp", "ipc/RemoteContentController.cpp", + "ipc/ShadowLayers.cpp", "ipc/SharedPlanarYCbCrImage.cpp", "ipc/SharedRGBImage.cpp", "ipc/SharedSurfacesChild.cpp", @@ -533,6 +538,7 @@ IPDL_SOURCES += [ "ipc/PCompositorBridgeTypes.ipdlh", "ipc/PCompositorManager.ipdl", "ipc/PImageBridge.ipdl", + "ipc/PLayerTransaction.ipdl", "ipc/PTexture.ipdl", "ipc/PUiCompositorController.ipdl", "ipc/PVideoBridge.ipdl", diff --git a/ipc/ipdl/message-metadata.ini b/ipc/ipdl/message-metadata.ini index 50ad642537962..88c471502626d 100644 --- a/ipc/ipdl/message-metadata.ini +++ b/ipc/ipdl/message-metadata.ini @@ -8,6 +8,8 @@ segment_capacity = 16384 [PContent::AccumulateChildHistograms] segment_capacity = 16384 +[PLayerTransaction::Update] +segment_capacity = 8192 [PContent::StoreAndBroadcastBlobURLRegistration] segment_capacity = 8192 [PHttpChannel::Redirect1Begin] diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 662a33d09b904..c55d6131f8c58 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -85,6 +85,7 @@ #include "mozilla/layers/APZPublicUtils.h" #include "mozilla/layers/AxisPhysicsModel.h" #include "mozilla/layers/AxisPhysicsMSDModel.h" +#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/ScrollLinkedEffectDetector.h" #include "mozilla/Unused.h" #include "MobileViewportManager.h" diff --git a/layout/ipc/RemoteLayerTreeOwner.cpp b/layout/ipc/RemoteLayerTreeOwner.cpp index f860921f50cea..feb442cb1cbb2 100644 --- a/layout/ipc/RemoteLayerTreeOwner.cpp +++ b/layout/ipc/RemoteLayerTreeOwner.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/BrowserParent.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/LayerTransactionParent.h" #include "nsFrameLoader.h" #include "nsStyleStructInlines.h" #include "nsSubDocumentFrame.h" diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index cfe04b1ff9721..0c1216dc19385 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -27,6 +27,7 @@ #include "mozilla/dom/SVGElement.h" #include "mozilla/dom/TouchEvent.h" #include "mozilla/gfx/2D.h" +#include "mozilla/layers/PLayerTransaction.h" #include "mozilla/PresShell.h" #include "mozilla/ShapeUtils.h" #include "mozilla/StaticPrefs_apz.h" diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 4be2be01055c3..05227999749dd 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -14,6 +14,7 @@ #include "mozilla/Hal.h" #include "mozilla/IMEStateManager.h" #include "mozilla/layers/APZChild.h" +#include "mozilla/layers/PLayerTransactionChild.h" #include "mozilla/layers/WebRenderLayerManager.h" #include "mozilla/Preferences.h" #include "mozilla/PresShell.h" diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 430e8e890f18d..a8032e851ea5c 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -123,6 +123,7 @@ using mozilla::java::GeckoSession; #include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/CompositorSession.h" +#include "mozilla/layers/LayerTransactionParent.h" #include "mozilla/layers/UiCompositorControllerChild.h" #include "nsThreadUtils.h" diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 1c1d468a60d0a..8598fe46e9a3f 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -52,6 +52,7 @@ #include "mozilla/layers/IAPZCTreeManager.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/InputAPZContext.h" +#include "mozilla/layers/PLayerTransactionChild.h" #include "mozilla/layers/WebRenderLayerManager.h" #include "mozilla/webrender/WebRenderTypes.h" #include "nsAppDirectoryServiceDefs.h" diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 51bb037316629..fbe9c390277e7 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -81,6 +81,7 @@ class CompositorBridgeChild; struct FrameMetrics; class LayerManager; class LayerManagerComposite; +class PLayerTransactionChild; class WebRenderBridgeChild; } // namespace layers namespace gfx { @@ -380,6 +381,7 @@ class nsIWidget : public nsISupports { typedef mozilla::layers::LayerManagerComposite LayerManagerComposite; typedef mozilla::layers::LayersBackend LayersBackend; typedef mozilla::layers::LayersId LayersId; + typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild; typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; typedef mozilla::layers::ZoomConstraints ZoomConstraints; typedef mozilla::widget::IMEEnabled IMEEnabled;