michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=2 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "CompositorChild.h" michael@0: #include // for size_t michael@0: #include "ClientLayerManager.h" // for ClientLayerManager michael@0: #include "base/message_loop.h" // for MessageLoop michael@0: #include "base/process_util.h" // for OpenProcessHandle michael@0: #include "base/task.h" // for NewRunnableMethod, etc michael@0: #include "base/tracked.h" // for FROM_HERE michael@0: #include "mozilla/layers/LayerTransactionChild.h" michael@0: #include "mozilla/layers/PLayerTransactionChild.h" michael@0: #include "mozilla/mozalloc.h" // for operator new, etc michael@0: #include "nsDebug.h" // for NS_RUNTIMEABORT michael@0: #include "nsIObserver.h" // for nsIObserver michael@0: #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc michael@0: #include "nsTArray.h" // for nsTArray, nsTArray_Impl michael@0: #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop, etc michael@0: #include "FrameLayerBuilder.h" michael@0: #include "mozilla/dom/TabChild.h" michael@0: michael@0: using mozilla::layers::LayerTransactionChild; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: /*static*/ CompositorChild* CompositorChild::sCompositor; michael@0: michael@0: Atomic CompositableForwarder::sSerialCounter(0); michael@0: michael@0: CompositorChild::CompositorChild(ClientLayerManager *aLayerManager) michael@0: : mLayerManager(aLayerManager) michael@0: { michael@0: MOZ_COUNT_CTOR(CompositorChild); michael@0: } michael@0: michael@0: CompositorChild::~CompositorChild() michael@0: { michael@0: MOZ_COUNT_DTOR(CompositorChild); michael@0: } michael@0: michael@0: void michael@0: CompositorChild::Destroy() michael@0: { michael@0: mLayerManager->Destroy(); michael@0: mLayerManager = nullptr; michael@0: while (size_t len = ManagedPLayerTransactionChild().Length()) { michael@0: LayerTransactionChild* layers = michael@0: static_cast(ManagedPLayerTransactionChild()[len - 1]); michael@0: layers->Destroy(); michael@0: } michael@0: SendStop(); michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, michael@0: FrameMetrics& aFrame) michael@0: { michael@0: SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); michael@0: if (data) { michael@0: data->CopyFrameMetrics(&aFrame); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /*static*/ PCompositorChild* michael@0: CompositorChild::Create(Transport* aTransport, ProcessId aOtherProcess) michael@0: { michael@0: // There's only one compositor per child process. michael@0: MOZ_ASSERT(!sCompositor); michael@0: michael@0: nsRefPtr child(new CompositorChild(nullptr)); michael@0: ProcessHandle handle; michael@0: if (!base::OpenProcessHandle(aOtherProcess, &handle)) { michael@0: // We can't go on without a compositor. michael@0: NS_RUNTIMEABORT("Couldn't OpenProcessHandle() to parent process."); michael@0: return nullptr; michael@0: } michael@0: if (!child->Open(aTransport, handle, XRE_GetIOMessageLoop(), ipc::ChildSide)) { michael@0: NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); michael@0: return nullptr; michael@0: } michael@0: // We release this ref in ActorDestroy(). michael@0: return sCompositor = child.forget().take(); michael@0: } michael@0: michael@0: /*static*/ CompositorChild* michael@0: CompositorChild::Get() michael@0: { michael@0: // This is only expected to be used in child processes. michael@0: MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default); michael@0: return sCompositor; michael@0: } michael@0: michael@0: PLayerTransactionChild* michael@0: CompositorChild::AllocPLayerTransactionChild(const nsTArray& aBackendHints, michael@0: const uint64_t& aId, michael@0: TextureFactoryIdentifier*, michael@0: bool*) michael@0: { michael@0: LayerTransactionChild* c = new LayerTransactionChild(); michael@0: c->AddIPDLReference(); michael@0: return c; michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor) michael@0: { michael@0: static_cast(actor)->ReleaseIPDLReference(); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::RecvInvalidateAll() michael@0: { michael@0: FrameLayerBuilder::InvalidateAllLayers(mLayerManager); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::RecvDidComposite(const uint64_t& aId) michael@0: { michael@0: if (mLayerManager) { michael@0: MOZ_ASSERT(aId == 0); michael@0: mLayerManager->DidComposite(); michael@0: } else if (aId != 0) { michael@0: dom::TabChild *child = dom::TabChild::GetFrom(aId); michael@0: if (child) { michael@0: child->DidComposite(); michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CompositorChild::ActorDestroy(ActorDestroyReason aWhy) michael@0: { michael@0: MOZ_ASSERT(sCompositor == this); michael@0: michael@0: #ifdef MOZ_B2G michael@0: // Due to poor lifetime management of gralloc (and possibly shmems) we will michael@0: // crash at some point in the future when we get destroyed due to abnormal michael@0: // shutdown. Its better just to crash here. On desktop though, we have a chance michael@0: // of recovering. michael@0: if (aWhy == AbnormalShutdown) { michael@0: NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at CompositorChild"); michael@0: } michael@0: #endif michael@0: if (sCompositor) { michael@0: sCompositor->Release(); michael@0: sCompositor = nullptr; michael@0: } michael@0: // We don't want to release the ref to sCompositor here, during michael@0: // cleanup, because that will cause it to be deleted while it's michael@0: // still being used. So defer the deletion to after it's not in michael@0: // use. michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &CompositorChild::Release)); michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::RecvSharedCompositorFrameMetrics( michael@0: const mozilla::ipc::SharedMemoryBasic::Handle& metrics, michael@0: const CrossProcessMutexHandle& handle, michael@0: const uint32_t& aAPZCId) michael@0: { michael@0: SharedFrameMetricsData* data = new SharedFrameMetricsData(metrics, handle, aAPZCId); michael@0: mFrameMetricsTable.Put(data->GetViewID(), data); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CompositorChild::RecvReleaseSharedCompositorFrameMetrics( michael@0: const ViewID& aId, michael@0: const uint32_t& aAPZCId) michael@0: { michael@0: SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); michael@0: // The SharedFrameMetricsData may have been removed previously if michael@0: // a SharedFrameMetricsData with the same ViewID but later APZCId had michael@0: // been store and over wrote it. michael@0: if (data && (data->GetAPZCId() == aAPZCId)) { michael@0: mFrameMetricsTable.Remove(aId); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: CompositorChild::SharedFrameMetricsData::SharedFrameMetricsData( michael@0: const ipc::SharedMemoryBasic::Handle& metrics, michael@0: const CrossProcessMutexHandle& handle, michael@0: const uint32_t& aAPZCId) : michael@0: mBuffer(nullptr), michael@0: mMutex(nullptr), michael@0: mAPZCId(aAPZCId) michael@0: { michael@0: mBuffer = new ipc::SharedMemoryBasic(metrics); michael@0: mBuffer->Map(sizeof(FrameMetrics)); michael@0: mMutex = new CrossProcessMutex(handle); michael@0: MOZ_COUNT_CTOR(SharedFrameMetricsData); michael@0: } michael@0: michael@0: CompositorChild::SharedFrameMetricsData::~SharedFrameMetricsData() michael@0: { michael@0: // When the hash table deletes the class, delete michael@0: // the shared memory and mutex. michael@0: delete mMutex; michael@0: delete mBuffer; michael@0: MOZ_COUNT_DTOR(SharedFrameMetricsData); michael@0: } michael@0: michael@0: void michael@0: CompositorChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame) michael@0: { michael@0: FrameMetrics* frame = static_cast(mBuffer->memory()); michael@0: MOZ_ASSERT(frame); michael@0: mMutex->Lock(); michael@0: *aFrame = *frame; michael@0: mMutex->Unlock(); michael@0: } michael@0: michael@0: FrameMetrics::ViewID michael@0: CompositorChild::SharedFrameMetricsData::GetViewID() michael@0: { michael@0: FrameMetrics* frame = static_cast(mBuffer->memory()); michael@0: MOZ_ASSERT(frame); michael@0: // Not locking to read of mScrollId since it should not change after being michael@0: // initially set. michael@0: return frame->GetScrollId(); michael@0: } michael@0: michael@0: uint32_t michael@0: CompositorChild::SharedFrameMetricsData::GetAPZCId() michael@0: { michael@0: return mAPZCId; michael@0: } michael@0: michael@0: } // namespace layers michael@0: } // namespace mozilla michael@0: