diff options
Diffstat (limited to 'gfx/layers/ipc/CompositorBridgeChild.cpp')
-rw-r--r-- | gfx/layers/ipc/CompositorBridgeChild.cpp | 1150 |
1 files changed, 1150 insertions, 0 deletions
diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp new file mode 100644 index 000000000..f623b10b8 --- /dev/null +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -0,0 +1,1150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=2 et 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 "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" +#include <stddef.h> // for size_t +#include "ClientLayerManager.h" // for ClientLayerManager +#include "base/message_loop.h" // for MessageLoop +#include "base/task.h" // for NewRunnableMethod, etc +#include "gfxPrefs.h" +#include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/layers/APZChild.h" +#include "mozilla/layers/IAPZCTreeManager.h" +#include "mozilla/layers/APZCTreeManagerChild.h" +#include "mozilla/layers/LayerTransactionChild.h" +#include "mozilla/layers/PLayerTransactionChild.h" +#include "mozilla/layers/TextureClient.h"// for TextureClient +#include "mozilla/layers/TextureClientPool.h"// for TextureClientPool +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/gfx/GPUProcessManager.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/mozalloc.h" // for operator new, etc +#include "nsAutoPtr.h" +#include "nsDebug.h" // for NS_RUNTIMEABORT +#include "nsIObserver.h" // for nsIObserver +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc +#include "nsTArray.h" // for nsTArray, nsTArray_Impl +#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop, etc +#include "FrameLayerBuilder.h" +#include "mozilla/dom/TabChild.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/Unused.h" +#include "mozilla/DebugOnly.h" +#if defined(XP_WIN) +#include "WinUtils.h" +#endif +#include "mozilla/widget/CompositorWidget.h" +#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING +# include "mozilla/widget/CompositorWidgetChild.h" +#endif +#include "VsyncSource.h" + +using mozilla::layers::LayerTransactionChild; +using mozilla::dom::TabChildBase; +using mozilla::Unused; +using mozilla::gfx::GPUProcessManager; + +namespace mozilla { +namespace layers { + +static int sShmemCreationCounter = 0; + +static void ResetShmemCounter() +{ + sShmemCreationCounter = 0; +} + +static void ShmemAllocated(CompositorBridgeChild* aProtocol) +{ + sShmemCreationCounter++; + if (sShmemCreationCounter > 256) { + aProtocol->SendSyncWithCompositor(); + ResetShmemCounter(); + MOZ_PERFORMANCE_WARNING("gfx", "The number of shmem allocations is too damn high!"); + } +} + +static StaticRefPtr<CompositorBridgeChild> sCompositorBridge; + +Atomic<int32_t> KnowsCompositor::sSerialCounter(0); + +CompositorBridgeChild::CompositorBridgeChild(LayerManager *aLayerManager) + : mLayerManager(aLayerManager) + , mCanSend(false) + , mFwdTransactionId(0) + , mMessageLoop(MessageLoop::current()) + , mSectionAllocator(nullptr) +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +CompositorBridgeChild::~CompositorBridgeChild() +{ + if (mCanSend) { + gfxCriticalError() << "CompositorBridgeChild was not deinitialized"; + } +} + +bool +CompositorBridgeChild::IsSameProcess() const +{ + return OtherPid() == base::GetCurrentProcId(); +} + +static void DeferredDestroyCompositor(RefPtr<CompositorBridgeParent> aCompositorBridgeParent, + RefPtr<CompositorBridgeChild> aCompositorBridgeChild) +{ + aCompositorBridgeChild->Close(); + + if (sCompositorBridge == aCompositorBridgeChild) { + sCompositorBridge = nullptr; + } +} + +void +CompositorBridgeChild::Destroy() +{ + // This must not be called from the destructor! + mTexturesWaitingRecycled.Clear(); + + if (!mCanSend) { + return; + } + + for (size_t i = 0; i < mTexturePools.Length(); i++) { + mTexturePools[i]->Destroy(); + } + + if (mSectionAllocator) { + delete mSectionAllocator; + mSectionAllocator = nullptr; + } + + // Destroying the layer manager may cause all sorts of things to happen, so + // let's make sure there is still a reference to keep this alive whatever + // happens. + RefPtr<CompositorBridgeChild> selfRef = this; + + if (mLayerManager) { + mLayerManager->Destroy(); + mLayerManager = nullptr; + } + + AutoTArray<PLayerTransactionChild*, 16> transactions; + ManagedPLayerTransactionChild(transactions); + for (int i = transactions.Length() - 1; i >= 0; --i) { + RefPtr<LayerTransactionChild> layers = + static_cast<LayerTransactionChild*>(transactions[i]); + layers->Destroy(); + } + + const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild(); + for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) { + RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); + + if (texture) { + texture->Destroy(); + } + } + + SendWillClose(); + mCanSend = false; + + // We no longer care about unexpected shutdowns, in the remote process case. + mProcessToken = 0; + + // The call just made to SendWillClose can result in IPC from the + // CompositorBridgeParent to the CompositorBridgeChild (e.g. caused by the destruction + // of shared memory). We need to ensure this gets processed by the + // CompositorBridgeChild before it gets destroyed. It suffices to ensure that + // events already in the MessageLoop get processed before the + // CompositorBridgeChild is destroyed, so we add a task to the MessageLoop to + // handle compositor desctruction. + + // From now on we can't send any message message. + MessageLoop::current()->PostTask( + NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef)); +} + +// static +void +CompositorBridgeChild::ShutDown() +{ + if (sCompositorBridge) { + sCompositorBridge->Destroy(); + do { + NS_ProcessNextEvent(nullptr, true); + } while (sCompositorBridge); + } +} + +bool +CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, + FrameMetrics& aFrame) +{ + SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); + if (data) { + data->CopyFrameMetrics(&aFrame); + return true; + } + return false; +} + +/* static */ bool +CompositorBridgeChild::InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint) +{ + // There's only one compositor per child process. + MOZ_ASSERT(!sCompositorBridge); + + RefPtr<CompositorBridgeChild> child(new CompositorBridgeChild(nullptr)); + if (!aEndpoint.Bind(child)) { + NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); + return false; + } + child->InitIPDL(); + + // We release this ref in DeferredDestroyCompositor. + sCompositorBridge = child; + return true; +} + +/* static */ bool +CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (RefPtr<CompositorBridgeChild> old = sCompositorBridge.forget()) { + // Note that at this point, ActorDestroy may not have been called yet, + // meaning mCanSend is still true. In this case we will try to send a + // synchronous WillClose message to the parent, and will certainly get + // a false result and a MsgDropped processing error. This is okay. + old->Destroy(); + } + + return InitForContent(Move(aEndpoint)); +} + +CompositorBridgeParent* +CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget, + const uint64_t& aLayerTreeId, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurface, + const gfx::IntSize& aSurfaceSize) +{ + TimeDuration vsyncRate = + gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate(); + + mCompositorBridgeParent = + new CompositorBridgeParent(aScale, vsyncRate, aUseExternalSurface, aSurfaceSize); + + bool ok = Open(mCompositorBridgeParent->GetIPCChannel(), + CompositorThreadHolder::Loop(), + ipc::ChildSide); + MOZ_RELEASE_ASSERT(ok); + + InitIPDL(); + mCompositorBridgeParent->InitSameProcess(aWidget, aLayerTreeId, aUseAPZ); + return mCompositorBridgeParent; +} + +/* static */ RefPtr<CompositorBridgeChild> +CompositorBridgeChild::CreateRemote(const uint64_t& aProcessToken, + LayerManager* aLayerManager, + Endpoint<PCompositorBridgeChild>&& aEndpoint) +{ + RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager); + if (!aEndpoint.Bind(child)) { + return nullptr; + } + child->InitIPDL(); + child->mProcessToken = aProcessToken; + return child; +} + +void +CompositorBridgeChild::InitIPDL() +{ + mCanSend = true; + AddRef(); +} + +void +CompositorBridgeChild::DeallocPCompositorBridgeChild() +{ + Release(); +} + +/*static*/ CompositorBridgeChild* +CompositorBridgeChild::Get() +{ + // This is only expected to be used in child processes. + MOZ_ASSERT(!XRE_IsParentProcess()); + return sCompositorBridge; +} + +// static +bool +CompositorBridgeChild::ChildProcessHasCompositorBridge() +{ + return sCompositorBridge != nullptr; +} + +PLayerTransactionChild* +CompositorBridgeChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints, + const uint64_t& aId, + TextureFactoryIdentifier*, + bool*) +{ + LayerTransactionChild* c = new LayerTransactionChild(aId); + c->AddIPDLReference(); + return c; +} + +bool +CompositorBridgeChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor) +{ + uint64_t childId = static_cast<LayerTransactionChild*>(actor)->GetId(); + + for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) { + nsAutoPtr<SharedFrameMetricsData>& data = iter.Data(); + if (data->GetLayersId() == childId) { + iter.Remove(); + } + } + static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference(); + return true; +} + +bool +CompositorBridgeChild::RecvInvalidateLayers(const uint64_t& aLayersId) +{ + if (mLayerManager) { + MOZ_ASSERT(aLayersId == 0); + FrameLayerBuilder::InvalidateAllLayers(mLayerManager); + } else if (aLayersId != 0) { + if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) { + child->InvalidateLayers(); + } + } + return true; +} + +bool +CompositorBridgeChild::RecvCompositorUpdated(const uint64_t& aLayersId, + const TextureFactoryIdentifier& aNewIdentifier) +{ + if (mLayerManager) { + // This case is handled directly by nsBaseWidget. + MOZ_ASSERT(aLayersId == 0); + } else if (aLayersId != 0) { + if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) { + child->CompositorUpdated(aNewIdentifier); + + // If we still get device reset here, something must wrong when creating + // d3d11 devices. + if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { + gfxCriticalError() << "Unexpected reset device processing when \ + updating compositor."; + } + } + if (!mCanSend) { + return true; + } + SendAcknowledgeCompositorUpdate(aLayersId); + } + return true; +} + +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds, + const nsTArray<LayoutDeviceIntRect>& aPluginClipRects, + const LayoutDeviceIntPoint& aContentOffset, + const LayoutDeviceIntRegion& aParentLayerVisibleRegion, + nsTArray<LayoutDeviceIntRect>& aResult, + LayoutDeviceIntRect& aVisibleBounds, + bool& aPluginIsVisible) +{ + aPluginIsVisible = true; + LayoutDeviceIntRegion contentVisibleRegion; + // aPluginClipRects (plugin widget origin) - contains *visible* rects + for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) { + LayoutDeviceIntRect rect = aPluginClipRects[idx]; + // shift to content origin + rect.MoveBy(aBounds.x, aBounds.y); + // accumulate visible rects + contentVisibleRegion.OrWith(rect); + } + // apply layers clip (window origin) + LayoutDeviceIntRegion region = aParentLayerVisibleRegion; + region.MoveBy(-aContentOffset.x, -aContentOffset.y); + contentVisibleRegion.AndWith(region); + if (contentVisibleRegion.IsEmpty()) { + aPluginIsVisible = false; + return; + } + // shift to plugin widget origin + contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y); + for (auto iter = contentVisibleRegion.RectIter(); !iter.Done(); iter.Next()) { + const LayoutDeviceIntRect& rect = iter.Get(); + aResult.AppendElement(rect); + aVisibleBounds.UnionRect(aVisibleBounds, rect); + } +} +#endif + +bool +CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset, + const LayoutDeviceIntRegion& aParentLayerVisibleRegion, + nsTArray<PluginWindowData>&& aPlugins) +{ +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) + NS_NOTREACHED("CompositorBridgeChild::RecvUpdatePluginConfigurations calls " + "unexpected on this platform."); + return false; +#else + // Now that we are on the main thread, update plugin widget config. + // This should happen a little before we paint to the screen assuming + // the main thread is running freely. + DebugOnly<nsresult> rv; + MOZ_ASSERT(NS_IsMainThread()); + + // Tracks visible plugins we update, so we can hide any plugins we don't. + nsTArray<uintptr_t> visiblePluginIds; + nsIWidget* parent = nullptr; + for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) { + nsIWidget* widget = + nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId()); + if (!widget) { + NS_WARNING("Unexpected, plugin id not found!"); + continue; + } + if (!parent) { + parent = widget->GetParent(); + } + bool isVisible = aPlugins[pluginsIdx].visible(); + if (widget && !widget->Destroyed()) { + LayoutDeviceIntRect bounds; + LayoutDeviceIntRect visibleBounds; + // If the plugin is visible update it's geometry. + if (isVisible) { + // Set bounds (content origin) + bounds = aPlugins[pluginsIdx].bounds(); + nsTArray<LayoutDeviceIntRect> rectsOut; + // This call may change the value of isVisible + CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(), + aContentOffset, + aParentLayerVisibleRegion, + rectsOut, visibleBounds, isVisible); + // content clipping region (widget origin) + rv = widget->SetWindowClipRegion(rectsOut, false); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); + // This will trigger a browser window paint event for areas uncovered + // by a child window move, and will call invalidate on the plugin + // parent window which the browser owns. The latter gets picked up in + // our OnPaint handler and forwarded over to the plugin process async. + rv = widget->Resize(aContentOffset.x + bounds.x, + aContentOffset.y + bounds.y, + bounds.width, bounds.height, true); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); + } + + rv = widget->Enable(isVisible); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); + + // visible state - updated after clipping, prior to invalidating + rv = widget->Show(isVisible); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); + + // Handle invalidation, this can be costly, avoid if it is not needed. + if (isVisible) { + // invalidate region (widget origin) +#if defined(XP_WIN) + // Work around for flash's crummy sandbox. See bug 762948. This call + // digs down into the window hirearchy, invalidating regions on + // windows owned by other processes. + mozilla::widget::WinUtils::InvalidatePluginAsWorkaround( + widget, visibleBounds); +#else + rv = widget->Invalidate(visibleBounds); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); +#endif + visiblePluginIds.AppendElement(aPlugins[pluginsIdx].windowId()); + } + } + } + // Any plugins we didn't update need to be hidden, as they are + // not associated with visible content. + nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds); + if (!mCanSend) { + return true; + } + SendRemotePluginsReady(); + return true; +#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) +} + +#if defined(XP_WIN) +static void +ScheduleSendAllPluginsCaptured(CompositorBridgeChild* aThis, MessageLoop* aLoop) +{ + aLoop->PostTask(NewNonOwningRunnableMethod( + aThis, &CompositorBridgeChild::SendAllPluginsCaptured)); +} +#endif + +bool +CompositorBridgeChild::RecvCaptureAllPlugins(const uintptr_t& aParentWidget) +{ +#if defined(XP_WIN) + MOZ_ASSERT(NS_IsMainThread()); + nsIWidget::CaptureRegisteredPlugins(aParentWidget); + + // Bounce the call to SendAllPluginsCaptured off the ImageBridgeChild loop, + // to make sure that the image updates on that thread have been processed. + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( + NewRunnableFunction(&ScheduleSendAllPluginsCaptured, this, + MessageLoop::current())); + return true; +#else + MOZ_ASSERT_UNREACHABLE( + "CompositorBridgeChild::RecvCaptureAllPlugins calls unexpected."); + return false; +#endif +} + +bool +CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget) +{ +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) + NS_NOTREACHED("CompositorBridgeChild::RecvHideAllPlugins calls " + "unexpected on this platform."); + return false; +#else + MOZ_ASSERT(NS_IsMainThread()); + nsTArray<uintptr_t> list; + nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list); + if (!mCanSend) { + return true; + } + SendRemotePluginsReady(); + return true; +#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) +} + +bool +CompositorBridgeChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId, + const TimeStamp& aCompositeStart, + const TimeStamp& aCompositeEnd) +{ + // Hold a reference to keep texture pools alive. See bug 1387799 + AutoTArray<RefPtr<TextureClientPool>,2> texturePools = mTexturePools; + + if (mLayerManager) { + MOZ_ASSERT(aId == 0); + RefPtr<ClientLayerManager> m = mLayerManager->AsClientLayerManager(); + MOZ_ASSERT(m); + m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); + } else if (aId != 0) { + RefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId); + if (child) { + child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); + } + } + + for (size_t i = 0; i < texturePools.Length(); i++) { + texturePools[i]->ReturnDeferredClients(); + } + + return true; +} + +bool +CompositorBridgeChild::RecvOverfill(const uint32_t &aOverfill) +{ + for (size_t i = 0; i < mOverfillObservers.Length(); i++) { + mOverfillObservers[i]->RunOverfillCallback(aOverfill); + } + mOverfillObservers.Clear(); + return true; +} + +void +CompositorBridgeChild::AddOverfillObserver(ClientLayerManager* aLayerManager) +{ + MOZ_ASSERT(aLayerManager); + mOverfillObservers.AppendElement(aLayerManager); +} + +bool +CompositorBridgeChild::RecvClearCachedResources(const uint64_t& aId) +{ + dom::TabChild* child = dom::TabChild::GetFrom(aId); + if (child) { + child->ClearCachedResources(); + } + return true; +} + +void +CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (aWhy == AbnormalShutdown) { + // If the parent side runs into a problem then the actor will be destroyed. + // There is nothing we can do in the child side, here sets mCanSend as false. + gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown"; + } + + mCanSend = false; + + if (mProcessToken && XRE_IsParentProcess()) { + GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); + } +} + +bool +CompositorBridgeChild::RecvSharedCompositorFrameMetrics( + const mozilla::ipc::SharedMemoryBasic::Handle& metrics, + const CrossProcessMutexHandle& handle, + const uint64_t& aLayersId, + const uint32_t& aAPZCId) +{ + SharedFrameMetricsData* data = new SharedFrameMetricsData( + metrics, handle, aLayersId, aAPZCId); + mFrameMetricsTable.Put(data->GetViewID(), data); + return true; +} + +bool +CompositorBridgeChild::RecvReleaseSharedCompositorFrameMetrics( + const ViewID& aId, + const uint32_t& aAPZCId) +{ + SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); + // The SharedFrameMetricsData may have been removed previously if + // a SharedFrameMetricsData with the same ViewID but later APZCId had + // been store and over wrote it. + if (data && (data->GetAPZCId() == aAPZCId)) { + mFrameMetricsTable.Remove(aId); + } + return true; +} + +CompositorBridgeChild::SharedFrameMetricsData::SharedFrameMetricsData( + const ipc::SharedMemoryBasic::Handle& metrics, + const CrossProcessMutexHandle& handle, + const uint64_t& aLayersId, + const uint32_t& aAPZCId) + : mMutex(nullptr) + , mLayersId(aLayersId) + , mAPZCId(aAPZCId) +{ + mBuffer = new ipc::SharedMemoryBasic; + mBuffer->SetHandle(metrics); + mBuffer->Map(sizeof(FrameMetrics)); + mMutex = new CrossProcessMutex(handle); + MOZ_COUNT_CTOR(SharedFrameMetricsData); +} + +CompositorBridgeChild::SharedFrameMetricsData::~SharedFrameMetricsData() +{ + // When the hash table deletes the class, delete + // the shared memory and mutex. + delete mMutex; + mBuffer = nullptr; + MOZ_COUNT_DTOR(SharedFrameMetricsData); +} + +void +CompositorBridgeChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame) +{ + FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory()); + MOZ_ASSERT(frame); + mMutex->Lock(); + *aFrame = *frame; + mMutex->Unlock(); +} + +FrameMetrics::ViewID +CompositorBridgeChild::SharedFrameMetricsData::GetViewID() +{ + FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory()); + MOZ_ASSERT(frame); + // Not locking to read of mScrollId since it should not change after being + // initially set. + return frame->GetScrollId(); +} + +uint64_t +CompositorBridgeChild::SharedFrameMetricsData::GetLayersId() const +{ + return mLayersId; +} + +uint32_t +CompositorBridgeChild::SharedFrameMetricsData::GetAPZCId() +{ + return mAPZCId; +} + + +bool +CompositorBridgeChild::RecvRemotePaintIsReady() +{ + // Used on the content thread, this bounces the message to the + // TabParent (via the TabChild) if the notification was previously requested. + // XPCOM gives a soup of compiler errors when trying to do_QueryReference + // so I'm using static_cast<> + MOZ_LAYERS_LOG(("[RemoteGfx] CompositorBridgeChild received RemotePaintIsReady")); + RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild)); + if (!iTabChildBase) { + MOZ_LAYERS_LOG(("[RemoteGfx] Note: TabChild was released before RemotePaintIsReady. " + "MozAfterRemotePaint will not be sent to listener.")); + return true; + } + TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get()); + TabChild* tabChild = static_cast<TabChild*>(tabChildBase); + MOZ_ASSERT(tabChild); + Unused << tabChild->SendRemotePaintIsReady(); + mWeakTabChild = nullptr; + return true; +} + + +void +CompositorBridgeChild::RequestNotifyAfterRemotePaint(TabChild* aTabChild) +{ + MOZ_ASSERT(aTabChild, "NULL TabChild not allowed in CompositorBridgeChild::RequestNotifyAfterRemotePaint"); + mWeakTabChild = do_GetWeakReference( static_cast<dom::TabChildBase*>(aTabChild) ); + if (!mCanSend) { + return; + } + Unused << SendRequestNotifyAfterRemotePaint(); +} + +void +CompositorBridgeChild::CancelNotifyAfterRemotePaint(TabChild* aTabChild) +{ + RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild)); + if (!iTabChildBase) { + return; + } + TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get()); + TabChild* tabChild = static_cast<TabChild*>(tabChildBase); + if (tabChild == aTabChild) { + mWeakTabChild = nullptr; + } +} + +bool +CompositorBridgeChild::SendWillClose() +{ + MOZ_RELEASE_ASSERT(mCanSend); + return PCompositorBridgeChild::SendWillClose(); +} + +bool +CompositorBridgeChild::SendPause() +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendPause(); +} + +bool +CompositorBridgeChild::SendResume() +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendResume(); +} + +bool +CompositorBridgeChild::SendNotifyChildCreated(const uint64_t& id) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendNotifyChildCreated(id); +} + +bool +CompositorBridgeChild::SendAdoptChild(const uint64_t& id) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendAdoptChild(id); +} + +bool +CompositorBridgeChild::SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendMakeSnapshot(inSnapshot, dirtyRect); +} + +bool +CompositorBridgeChild::SendFlushRendering() +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendFlushRendering(); +} + +bool +CompositorBridgeChild::SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendStartFrameTimeRecording(bufferSize, startIndex); +} + +bool +CompositorBridgeChild::SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendStopFrameTimeRecording(startIndex, intervals); +} + +bool +CompositorBridgeChild::SendNotifyRegionInvalidated(const nsIntRegion& region) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendNotifyRegionInvalidated(region); +} + +bool +CompositorBridgeChild::SendRequestNotifyAfterRemotePaint() +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendRequestNotifyAfterRemotePaint(); +} + +bool +CompositorBridgeChild::SendClearApproximatelyVisibleRegions(uint64_t aLayersId, + uint32_t aPresShellId) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendClearApproximatelyVisibleRegions(aLayersId, + aPresShellId); +} + +bool +CompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion); +} + +bool +CompositorBridgeChild::SendAllPluginsCaptured() +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::SendAllPluginsCaptured(); +} + +PTextureChild* +CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, + const LayersBackend&, + const TextureFlags&, + const uint64_t&, + const uint64_t& aSerial) +{ + return TextureClient::CreateIPDLActor(); +} + +bool +CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor) +{ + return TextureClient::DestroyIPDLActor(actor); +} + +bool +CompositorBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) +{ + for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) { + const AsyncParentMessageData& message = aMessages[i]; + + switch (message.type()) { + case AsyncParentMessageData::TOpNotifyNotUsed: { + const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed(); + NotifyNotUsed(op.TextureId(), op.fwdTransactionId()); + break; + } + default: + NS_ERROR("unknown AsyncParentMessageData type"); + return false; + } + } + return true; +} + +bool +CompositorBridgeChild::RecvObserveLayerUpdate(const uint64_t& aLayersId, + const uint64_t& aEpoch, + const bool& aActive) +{ + // This message is sent via the window compositor, not the tab compositor - + // however it still has a layers id. + MOZ_ASSERT(aLayersId); + MOZ_ASSERT(XRE_IsParentProcess()); + + if (RefPtr<dom::TabParent> tab = dom::TabParent::GetTabParentFromLayersId(aLayersId)) { + tab->LayerTreeUpdate(aEpoch, aActive); + } + return true; +} + +void +CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient) +{ + if (!aClient) { + return; + } + + if (!(aClient->GetFlags() & TextureFlags::RECYCLE)) { + return; + } + + aClient->SetLastFwdTransactionId(GetFwdTransactionId()); + mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient); +} + +void +CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId) +{ + RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId); + if (!client) { + return; + } + if (aFwdTransactionId < client->GetLastFwdTransactionId()) { + // Released on host side, but client already requested newer use texture. + return; + } + mTexturesWaitingRecycled.Remove(aTextureId); +} + +void +CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId) +{ + RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId); + if (!client) { + return; + } + mTexturesWaitingRecycled.Remove(aTextureId); +} + +TextureClientPool* +CompositorBridgeChild::GetTexturePool(KnowsCompositor* aAllocator, + SurfaceFormat aFormat, + TextureFlags aFlags) +{ + for (size_t i = 0; i < mTexturePools.Length(); i++) { + if (mTexturePools[i]->GetBackend() == aAllocator->GetCompositorBackendType() && + mTexturePools[i]->GetMaxTextureSize() == aAllocator->GetMaxTextureSize() && + mTexturePools[i]->GetFormat() == aFormat && + mTexturePools[i]->GetFlags() == aFlags) { + return mTexturePools[i]; + } + } + + mTexturePools.AppendElement( + new TextureClientPool(aAllocator->GetCompositorBackendType(), + aAllocator->GetMaxTextureSize(), + aFormat, + gfx::gfxVars::TileSize(), + aFlags, + gfxPrefs::LayersTilePoolShrinkTimeout(), + gfxPrefs::LayersTilePoolClearTimeout(), + gfxPrefs::LayersTileInitialPoolSize(), + gfxPrefs::LayersTilePoolUnusedSize(), + this)); + + return mTexturePools.LastElement(); +} + +void +CompositorBridgeChild::HandleMemoryPressure() +{ + for (size_t i = 0; i < mTexturePools.Length(); i++) { + mTexturePools[i]->Clear(); + } +} + +void +CompositorBridgeChild::ClearTexturePool() +{ + for (size_t i = 0; i < mTexturePools.Length(); i++) { + mTexturePools[i]->Clear(); + } +} + +FixedSizeSmallShmemSectionAllocator* +CompositorBridgeChild::GetTileLockAllocator() +{ + MOZ_ASSERT(IPCOpen()); + if (!IPCOpen()) { + return nullptr; + } + + if (!mSectionAllocator) { + mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this); + } + return mSectionAllocator; +} + + +PTextureChild* +CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, + LayersBackend aLayersBackend, + TextureFlags aFlags, + uint64_t aSerial) +{ + return PCompositorBridgeChild::SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial); +} + +bool +CompositorBridgeChild::AllocUnsafeShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + ShmemAllocated(this); + return PCompositorBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem); +} + +bool +CompositorBridgeChild::AllocShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + ShmemAllocated(this); + return PCompositorBridgeChild::AllocShmem(aSize, aType, aShmem); +} + +bool +CompositorBridgeChild::DeallocShmem(ipc::Shmem& aShmem) +{ + if (!mCanSend) { + return false; + } + return PCompositorBridgeChild::DeallocShmem(aShmem); +} + +widget::PCompositorWidgetChild* +CompositorBridgeChild::AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData) +{ + // We send the constructor manually. + MOZ_CRASH("Should not be called"); + return nullptr; +} + +bool +CompositorBridgeChild::DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor) +{ +#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING + delete aActor; + return true; +#else + return false; +#endif +} + +RefPtr<IAPZCTreeManager> +CompositorBridgeChild::GetAPZCTreeManager(uint64_t aLayerTreeId) +{ + bool apzEnabled = false; + Unused << SendAsyncPanZoomEnabled(aLayerTreeId, &apzEnabled); + + if (!apzEnabled) { + return nullptr; + } + + PAPZCTreeManagerChild* child = SendPAPZCTreeManagerConstructor(aLayerTreeId); + if (!child) { + return nullptr; + } + APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(child); + + return RefPtr<IAPZCTreeManager>(parent); +} + +PAPZCTreeManagerChild* +CompositorBridgeChild::AllocPAPZCTreeManagerChild(const uint64_t& aLayersId) +{ + APZCTreeManagerChild* child = new APZCTreeManagerChild(); + child->AddRef(); + return child; +} + +PAPZChild* +CompositorBridgeChild::AllocPAPZChild(const uint64_t& aLayersId) +{ + // We send the constructor manually. + MOZ_CRASH("Should not be called"); + return nullptr; +} + +bool +CompositorBridgeChild::DeallocPAPZChild(PAPZChild* aActor) +{ + delete aActor; + return true; +} + +bool +CompositorBridgeChild::DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor) +{ + APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(aActor); + parent->Release(); + return true; +} + +void +CompositorBridgeChild::ProcessingError(Result aCode, const char* aReason) +{ + if (aCode != MsgDropped) { + gfxDevCrash(gfx::LogReason::ProcessingError) << "Processing error in CompositorBridgeChild: " << int(aCode); + } +} + +void +CompositorBridgeChild::WillEndTransaction() +{ + ResetShmemCounter(); +} + +void +CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const +{ + dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid()); +} + +} // namespace layers +} // namespace mozilla + |