/* -*- 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 "CompositorParent.h" #include "LayerManagerOGL.h" #include "mozilla/layers/ShadowLayersChild.h" #include "nsIObserverService.h" #include "mozilla/Services.h" using mozilla::layers::ShadowLayersChild; namespace mozilla { namespace layers { // Observer for the memory-pressure notification, to trigger // flushing of stale/low res content. class MemoryPressureObserver MOZ_FINAL : public nsIObserver, public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER explicit MemoryPressureObserver(CompositorChild* cc) : mCC(cc) {} private: CompositorChild* mCC; }; NS_IMPL_ISUPPORTS2(MemoryPressureObserver, nsIObserver, nsISupportsWeakReference) NS_IMETHODIMP MemoryPressureObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) { if (strcmp(aTopic, "memory-pressure") == 0) { mCC->SendMemoryPressure(); } return NS_OK; } /*static*/ CompositorChild* CompositorChild::sCompositor; CompositorChild::CompositorChild(LayerManager *aLayerManager) : mLayerManager(aLayerManager) { MOZ_COUNT_CTOR(CompositorChild); nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { mMemoryPressureObserver = new MemoryPressureObserver(this); obs->AddObserver(mMemoryPressureObserver, "memory-pressure", false); } } CompositorChild::~CompositorChild() { nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->RemoveObserver(mMemoryPressureObserver, "memory-pressure"); } MOZ_COUNT_DTOR(CompositorChild); } void CompositorChild::Destroy() { mLayerManager = NULL; while (size_t len = ManagedPLayersChild().Length()) { ShadowLayersChild* layers = static_cast(ManagedPLayersChild()[len - 1]); layers->Destroy(); } SendStop(); } /*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(), AsyncChannel::Child)) { NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); return nullptr; } // We release this ref in ActorDestroy(). return sCompositor = child.forget().get(); } /*static*/ PCompositorChild* CompositorChild::Get() { // This is only expected to be used in child processes. MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default); return sCompositor; } PLayersChild* CompositorChild::AllocPLayers(const LayersBackend& aBackendHint, const uint64_t& aId, LayersBackend* aBackend, int* aMaxTextureSize) { return new ShadowLayersChild(); } bool CompositorChild::DeallocPLayers(PLayersChild* actor) { delete actor; return true; } void CompositorChild::ActorDestroy(ActorDestroyReason aWhy) { MOZ_ASSERT(sCompositor == this); sCompositor = NULL; // 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)); } } // namespace layers } // namespace mozilla