From 8dd046d72cfa0517e9fb2fbee09b79be8e3d82d5 Mon Sep 17 00:00:00 2001 From: Iulian Moraru Date: Wed, 25 Aug 2021 18:17:37 +0300 Subject: [PATCH] Backed out changeset caf7cc8417e8 (bug 1727488) for causing bp-hybrid bustages. CLOSED TREE --- gfx/layers/CompositorTypes.h | 1 + gfx/layers/LayerManager.h | 2 + gfx/layers/Layers.cpp | 23 +- gfx/layers/Layers.h | 7 + gfx/layers/LayersTypes.h | 7 +- gfx/layers/PersistentBufferProvider.cpp | 2 +- gfx/layers/RotatedBuffer.cpp | 1 + gfx/layers/client/ContentClient.cpp | 5 +- gfx/layers/client/ImageClient.cpp | 28 + gfx/layers/client/ImageClient.h | 18 + gfx/layers/client/TextureClient.cpp | 16 +- gfx/layers/composite/CompositableHost.cpp | 3 + gfx/layers/ipc/CompositableForwarder.h | 3 + gfx/layers/ipc/ImageBridgeChild.cpp | 5 + gfx/layers/ipc/KnowsCompositor.cpp | 122 --- gfx/layers/ipc/LayerTransactionChild.cpp | 5 +- gfx/layers/ipc/ShadowLayerUtilsMac.cpp | 4 + gfx/layers/ipc/ShadowLayerUtilsX11.cpp | 12 + gfx/layers/ipc/ShadowLayers.cpp | 972 ++++++++++++++++++++++ gfx/layers/ipc/ShadowLayers.h | 473 +++++++++++ gfx/layers/moz.build | 3 +- 21 files changed, 1582 insertions(+), 130 deletions(-) delete mode 100644 gfx/layers/ipc/KnowsCompositor.cpp create mode 100644 gfx/layers/ipc/ShadowLayers.cpp create mode 100644 gfx/layers/ipc/ShadowLayers.h diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index e882460612a0..b20770774d16 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 97b82b6c549e..0c7e4d8bad5a 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 edce6fc97ee9..1451769a8fb4 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 6b7495f1b0cb..8440406df30b 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 f6523e33212f..c9a63fcc5ced 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 e214489351f7..0c64c6a75608 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/RotatedBuffer.cpp b/gfx/layers/RotatedBuffer.cpp index 45d55221d567..a37b15feb5dd 100644 --- a/gfx/layers/RotatedBuffer.cpp +++ b/gfx/layers/RotatedBuffer.cpp @@ -26,6 +26,7 @@ #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/gfx/Rect.h" // for Rect, IntRect #include "mozilla/gfx/Types.h" // for ExtendMode::ExtendMode::CLAMP, etc +#include "mozilla/layers/ShadowLayers.h" // for ShadowableLayer #include "mozilla/layers/TextureClient.h" // for TextureClient #include "nsLayoutUtils.h" // for invalidation debugging diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 0dbefe38c24d..833da262c078 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -11,6 +11,7 @@ #include "gfxPoint.h" // for IntSize, gfxPoint #include "gfxUtils.h" // for gfxUtils +#include "ipc/ShadowLayers.h" // for ShadowLayerForwarder #include "mozilla/ArrayUtils.h" // for ArrayLength #include "mozilla/gfx/2D.h" // for DrawTarget, Factory #include "mozilla/gfx/BasePoint.h" // for BasePoint @@ -376,7 +377,9 @@ ContentClient::BufferDecision ContentClient::CalculateBufferForPaint( mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; #else if (!aLayer->GetParent() || - !aLayer->GetParent()->SupportsComponentAlphaChildren()) { + !aLayer->GetParent()->SupportsComponentAlphaChildren() || + !aLayer->AsShadowableLayer() || + !aLayer->AsShadowableLayer()->HasShadow()) { mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; } else { contentType = gfxContentType::COLOR; diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index e239859e0869..d5ad5c26e48d 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -24,6 +24,7 @@ #include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc #include "mozilla/layers/ISurfaceAllocator.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 @@ -47,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; @@ -273,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 77f3e57c5d9d..19b169c13296 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 f1cff13f4b91..fe7c75ebebc8 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 d229ca791869..056f26de04a2 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 45c8bdac2c6f..412af3e859e6 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/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 92bad5111f8c..0c3024426fa4 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 bcb8aa45f48d..000000000000 --- a/gfx/layers/ipc/KnowsCompositor.cpp +++ /dev/null @@ -1,122 +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" - -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 index 4e937e702dbe..4dbd40e08990 100644 --- a/gfx/layers/ipc/LayerTransactionChild.cpp +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -6,8 +6,9 @@ #include "LayerTransactionChild.h" #include "mozilla/gfx/Logging.h" -#include "mozilla/mozalloc.h" // for operator delete, etc -#include "nsTArray.h" // for nsTArray +#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 { diff --git a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp index c95e15483897..891b16e8a2cf 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp @@ -6,6 +6,7 @@ #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" @@ -17,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 24ca1d5ceb4a..25f6ceba21f3 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 000000000000..d149a6d2891b --- /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 000000000000..d3b29d7c1ec0 --- /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 a117f5a5a544..ddb3fe143420 100755 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -191,6 +191,7 @@ EXPORTS.mozilla.layers += [ "ipc/LayerTreeOwnerTracker.h", "ipc/RefCountedShmem.h", "ipc/RemoteContentController.h", + "ipc/ShadowLayers.h", "ipc/SharedPlanarYCbCrImage.h", "ipc/SharedRGBImage.h", "ipc/SharedSurfacesChild.h", @@ -444,13 +445,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",