diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/ipc/ShadowLayers.cpp | 1074 |
1 files changed, 1074 insertions, 0 deletions
diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp new file mode 100644 index 0000000000..571a05d491 --- /dev/null +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -0,0 +1,1074 @@ +/* -*- 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 <set> // for _Rb_tree_const_iterator, etc +#include <vector> // for vector + +#include "ClientLayerManager.h" // for ClientLayerManager +#include "GeckoProfiler.h" // for AUTO_PROFILER_LABEL +#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/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 "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<SurfaceDescriptor> BufferArray; +typedef nsTArray<Edit> EditVector; +typedef nsTHashtable<nsPtrHashKey<ShadowableLayer>> ShadowableLayerSet; +typedef nsTArray<OpDestroy> 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.PutEntry(aLayer); + } + void AddSimpleMutant(ShadowableLayer* aLayer) { + MOZ_ASSERT(!Finished(), "forgot BeginTransaction?"); + mSimpleMutants.PutEntry(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<CompositableOperation> 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<KnowsCompositor> ShadowLayerForwarder::GetForMedia() { + return MakeAndAddRef<KnowsCompositorMediaProxy>( + 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<ActiveResourceTracker>( + 1000, "CompositableForwarder", mEventTarget); +} + +template <typename T> +struct ReleaseOnMainThreadTask : public Runnable { + UniquePtr<T> mObj; + + explicit ReleaseOnMainThreadTask(UniquePtr<T>& 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<ReleaseOnMainThreadTask<ActiveResourceTracker>> event = + new ReleaseOnMainThreadTask<ActiveResourceTracker>( + 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 <typename OpCreateT> +static void CreatedLayer(Transaction* aTxn, ShadowableLayer* aLayer) { + aTxn->AddEdit(OpCreateT(Shadow(aLayer))); +} + +void ShadowLayerForwarder::CreatedPaintedLayer(ShadowableLayer* aThebes) { + CreatedLayer<OpCreatePaintedLayer>(mTxn, aThebes); +} +void ShadowLayerForwarder::CreatedContainerLayer(ShadowableLayer* aContainer) { + CreatedLayer<OpCreateContainerLayer>(mTxn, aContainer); +} +void ShadowLayerForwarder::CreatedImageLayer(ShadowableLayer* aImage) { + CreatedLayer<OpCreateImageLayer>(mTxn, aImage); +} +void ShadowLayerForwarder::CreatedColorLayer(ShadowableLayer* aColor) { + CreatedLayer<OpCreateColorLayer>(mTxn, aColor); +} +void ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas) { + CreatedLayer<OpCreateCanvasLayer>(mTxn, aCanvas); +} +void ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef) { + CreatedLayer<OpCreateRefLayer>(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<TimedTextureClient>& aTextures) { + MOZ_ASSERT(aCompositable); + + if (!aCompositable->IsConnected()) { + return; + } + + AutoTArray<TimedTexture, 4> textures; + + for (auto& t : aTextures) { + MOZ_ASSERT(t.mTextureClient); + MOZ_ASSERT(t.mTextureClient->GetIPDLActor()); + MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == + mShadowManager->GetIPCChannel()); + bool readLocked = t.mTextureClient->OnForwardedToHost(); + textures.AppendElement( + TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), t.mTimeStamp, + t.mPictureRect, t.mFrameID, t.mProducerID, readLocked)); + mClientLayerManager->GetCompositorBridgeChild() + ->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient); + + auto fenceFd = t.mTextureClient->GetInternalData()->GetAcquireFence(); + if (fenceFd.IsValid()) { + mTxn->AddEdit(CompositableOperation( + aCompositable->GetIPCHandle(), + OpDeliverAcquireFence(nullptr, t.mTextureClient->GetIPDLActor(), + fenceFd))); + } + } + mTxn->AddEdit(CompositableOperation(aCompositable->GetIPCHandle(), + OpUseTexture(textures))); +} + +void ShadowLayerForwarder::UseComponentAlphaTextures( + CompositableClient* aCompositable, TextureClient* aTextureOnBlack, + TextureClient* aTextureOnWhite) { + MOZ_ASSERT(aCompositable); + + if (!aCompositable->IsConnected()) { + return; + } + + MOZ_ASSERT(aTextureOnWhite); + MOZ_ASSERT(aTextureOnBlack); + MOZ_ASSERT(aCompositable->GetIPCHandle()); + MOZ_ASSERT(aTextureOnBlack->GetIPDLActor()); + MOZ_ASSERT(aTextureOnWhite->GetIPDLActor()); + MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize()); + MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() == + mShadowManager->GetIPCChannel()); + MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() == + mShadowManager->GetIPCChannel()); + + bool readLockedB = aTextureOnBlack->OnForwardedToHost(); + bool readLockedW = aTextureOnWhite->OnForwardedToHost(); + + mClientLayerManager->GetCompositorBridgeChild() + ->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack); + mClientLayerManager->GetCompositorBridgeChild() + ->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite); + + auto fenceFdB = aTextureOnBlack->GetInternalData()->GetAcquireFence(); + if (fenceFdB.IsValid()) { + mTxn->AddEdit(CompositableOperation( + aCompositable->GetIPCHandle(), + OpDeliverAcquireFence(nullptr, aTextureOnBlack->GetIPDLActor(), + fenceFdB))); + } + + auto fenceFdW = aTextureOnWhite->GetInternalData()->GetAcquireFence(); + if (fenceFdW.IsValid()) { + mTxn->AddEdit(CompositableOperation( + aCompositable->GetIPCHandle(), + OpDeliverAcquireFence(nullptr, aTextureOnWhite->GetIPDLActor(), + fenceFdW))); + } + + mTxn->AddEdit(CompositableOperation( + aCompositable->GetIPCHandle(), + OpUseComponentAlphaTextures(nullptr, aTextureOnBlack->GetIPDLActor(), + nullptr, aTextureOnWhite->GetIPDLActor(), + readLockedB, readLockedW))); +} + +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::StorePluginWidgetConfigurations( + const nsTArray<nsIWidget::Configuration>& aConfigurations) { + // Cache new plugin widget configs here until we call update, at which + // point this data will get shipped over to chrome. + mPluginWindowData.Clear(); + for (uint32_t idx = 0; idx < aConfigurations.Length(); idx++) { + const nsIWidget::Configuration& configuration = aConfigurations[idx]; + mPluginWindowData.AppendElement( + PluginWindowData(configuration.mWindowID, configuration.mClipRegion, + configuration.mBounds, configuration.mVisible)); + } +} + +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<CompositionPayload>& aPayload) { + *aSent = false; + + TransactionInfo info; + + MOZ_ASSERT(IPCOpen(), "no manager to forward to"); + if (!IPCOpen()) { + return false; + } + + Maybe<TimeStamp> 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; + } + + if (!mTxn->mPaints.IsEmpty()) { + // With some platforms, telling the drawing backend that there will be no + // more drawing for this frame helps with preventing command queues from + // spanning across multiple frames. + gfxPlatform::GetPlatform()->FlushContentDrawing(); + } + + MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers...")); + + MOZ_LAYERS_LOG(("[LayersForwarder] building transaction...")); + + nsTArray<OpSetSimpleLayerAttributes> setSimpleAttrs; + for (ShadowableLayerSet::Iterator it(&mTxn->mSimpleMutants); !it.Done(); + it.Next()) { + ShadowableLayer* shadow = it.Get()->GetKey(); + if (!shadow->HasShadow()) { + continue; + } + + Layer* mutant = shadow->AsLayer(); + setSimpleAttrs.AppendElement(OpSetSimpleLayerAttributes( + Shadow(shadow), mutant->GetSimpleAttributes())); + } + + nsTArray<OpSetLayerAttributes> 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 (ShadowableLayerSet::Iterator it(&mTxn->mMutants); !it.Done(); + it.Next()) { + ShadowableLayer* shadow = it.Get()->GetKey(); + + 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.plugins() = mPluginWindowData.Clone(); + 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()); + } + + // We delay at the last possible minute, to give the paint thread a chance to + // finish. If it does we don't have to delay messages at all. + GetCompositorBridgeChild()->PostponeMessagesIfAsyncPainting(); + + 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<CompositableClient> 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<uint64_t>& 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.Put(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<LayerTransactionChild*>(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<uint8_t>(); + } else { + return reinterpret_cast<uint8_t*>(memOrShmem.get_uintptr_t()); + } +} + +already_AddRefed<gfx::DataSourceSurface> 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<gfx::DrawTarget> GetDrawTargetForDescriptor( + const SurfaceDescriptor& aDescriptor, gfx::BackendType aBackend) { + 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::CAIRO, 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<uintptr_t>(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<CompositorBridgeChild*>(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 |