/* -*- 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 "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 BufferArray; typedef nsTArray EditVector; typedef nsTHashtable> 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.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 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); if (!aCompositable->IsConnected()) { return; } AutoTArray 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& 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& 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; } 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 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 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 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.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(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, 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(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