/* -*- 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 "CompositorChild.h" #include // for size_t #include "ClientLayerManager.h" // for ClientLayerManager #include "base/message_loop.h" // for MessageLoop #include "base/process_util.h" // for OpenProcessHandle #include "base/task.h" // for NewRunnableMethod, etc #include "base/tracked.h" // for FROM_HERE #include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/PLayerTransactionChild.h" #include "mozilla/mozalloc.h" // for operator new, etc #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" using mozilla::layers::LayerTransactionChild; namespace mozilla { namespace layers { /*static*/ CompositorChild* CompositorChild::sCompositor; Atomic CompositableForwarder::sSerialCounter(0); CompositorChild::CompositorChild(ClientLayerManager *aLayerManager) : mLayerManager(aLayerManager) { MOZ_COUNT_CTOR(CompositorChild); } CompositorChild::~CompositorChild() { MOZ_COUNT_DTOR(CompositorChild); } void CompositorChild::Destroy() { mLayerManager->Destroy(); mLayerManager = nullptr; while (size_t len = ManagedPLayerTransactionChild().Length()) { LayerTransactionChild* layers = static_cast(ManagedPLayerTransactionChild()[len - 1]); layers->Destroy(); } SendStop(); } bool CompositorChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, FrameMetrics& aFrame) { SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); if (data) { data->CopyFrameMetrics(&aFrame); return true; } return false; } /*static*/ PCompositorChild* CompositorChild::Create(Transport* aTransport, ProcessId aOtherProcess) { // There's only one compositor per child process. MOZ_ASSERT(!sCompositor); nsRefPtr child(new CompositorChild(nullptr)); ProcessHandle handle; if (!base::OpenProcessHandle(aOtherProcess, &handle)) { // We can't go on without a compositor. NS_RUNTIMEABORT("Couldn't OpenProcessHandle() to parent process."); return nullptr; } if (!child->Open(aTransport, handle, XRE_GetIOMessageLoop(), ipc::ChildSide)) { NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); return nullptr; } // We release this ref in ActorDestroy(). return sCompositor = child.forget().take(); } /*static*/ CompositorChild* CompositorChild::Get() { // This is only expected to be used in child processes. MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default); return sCompositor; } PLayerTransactionChild* CompositorChild::AllocPLayerTransactionChild(const nsTArray& aBackendHints, const uint64_t& aId, TextureFactoryIdentifier*, bool*) { LayerTransactionChild* c = new LayerTransactionChild(); c->AddIPDLReference(); return c; } bool CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor) { static_cast(actor)->ReleaseIPDLReference(); return true; } bool CompositorChild::RecvInvalidateAll() { if (mLayerManager) { FrameLayerBuilder::InvalidateAllLayers(mLayerManager); } return true; } bool CompositorChild::RecvDidComposite(const uint64_t& aId) { if (mLayerManager) { MOZ_ASSERT(aId == 0); mLayerManager->DidComposite(); } else if (aId != 0) { dom::TabChild *child = dom::TabChild::GetFrom(aId); if (child) { child->DidComposite(); } } return true; } void CompositorChild::ActorDestroy(ActorDestroyReason aWhy) { MOZ_ASSERT(sCompositor == this); #ifdef MOZ_B2G // Due to poor lifetime management of gralloc (and possibly shmems) we will // crash at some point in the future when we get destroyed due to abnormal // shutdown. Its better just to crash here. On desktop though, we have a chance // of recovering. if (aWhy == AbnormalShutdown) { NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at CompositorChild"); } #endif sCompositor = nullptr; // We don't want to release the ref to sCompositor here, during // cleanup, because that will cause it to be deleted while it's // still being used. So defer the deletion to after it's not in // use. MessageLoop::current()->PostTask( FROM_HERE, NewRunnableMethod(this, &CompositorChild::Release)); } bool CompositorChild::RecvSharedCompositorFrameMetrics( const mozilla::ipc::SharedMemoryBasic::Handle& metrics, const CrossProcessMutexHandle& handle, const uint32_t& aAPZCId) { SharedFrameMetricsData* data = new SharedFrameMetricsData(metrics, handle, aAPZCId); mFrameMetricsTable.Put(data->GetViewID(), data); return true; } bool CompositorChild::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; } CompositorChild::SharedFrameMetricsData::SharedFrameMetricsData( const ipc::SharedMemoryBasic::Handle& metrics, const CrossProcessMutexHandle& handle, const uint32_t& aAPZCId) : mBuffer(nullptr), mMutex(nullptr), mAPZCId(aAPZCId) { mBuffer = new ipc::SharedMemoryBasic(metrics); mBuffer->Map(sizeof(FrameMetrics)); mMutex = new CrossProcessMutex(handle); MOZ_COUNT_CTOR(SharedFrameMetricsData); } CompositorChild::SharedFrameMetricsData::~SharedFrameMetricsData() { // When the hash table deletes the class, delete // the shared memory and mutex. delete mMutex; delete mBuffer; MOZ_COUNT_DTOR(SharedFrameMetricsData); } void CompositorChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame) { FrameMetrics* frame = static_cast(mBuffer->memory()); MOZ_ASSERT(frame); mMutex->Lock(); *aFrame = *frame; mMutex->Unlock(); } FrameMetrics::ViewID CompositorChild::SharedFrameMetricsData::GetViewID() { FrameMetrics* frame = static_cast(mBuffer->memory()); MOZ_ASSERT(frame); // Not locking to read of mScrollId since it should not change after being // initially set. return frame->GetScrollId(); } uint32_t CompositorChild::SharedFrameMetricsData::GetAPZCId() { return mAPZCId; } } // namespace layers } // namespace mozilla