gfx/layers/ipc/UiCompositorControllerChild.cpp
author Randall Barker <rbarker@mozilla.com>
Thu, 05 Jan 2017 11:04:38 -0800
changeset 377727 7ceb7d18b5e090f6283fbe7062bfd194f5863783
child 378486 16153c4e477e2fbb872e57f24d11e973f7ee7ff0
child 392937 7c8cbd22d82a2029e0c6ac08206a057d8d88c1d4
permissions -rw-r--r--
Bug 1328752 - part 1, Add UiCompositorController r=dvander

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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 "UiCompositorControllerChild.h"
#include "UiCompositorControllerParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/StaticPtr.h"
#include "nsThreadUtils.h"

namespace mozilla {
namespace layers {

static bool sInitialized = false;
static StaticRefPtr<UiCompositorControllerChild> sChild;
static StaticRefPtr<UiCompositorControllerParent> sParent;

UiCompositorControllerChild::UiCompositorControllerChild(RefPtr<nsThread> aThread, const uint64_t& aProcessToken)
 : mUiThread(aThread),
   mProcessToken(aProcessToken)
{
}

UiCompositorControllerChild::~UiCompositorControllerChild()
{
}

/* static */ UiCompositorControllerChild*
UiCompositorControllerChild::Get()
{
  return sChild;
}

/* static */ bool
UiCompositorControllerChild::IsInitialized()
{
  return sInitialized;
}

/* static */ void
UiCompositorControllerChild::Shutdown()
{
  RefPtr<UiCompositorControllerChild> child = sChild;
  if (child) {
    child->Close();
    sInitialized = false;
  }
}

/* static */ void
UiCompositorControllerChild::InitSameProcess(RefPtr<nsThread> aThread)
{
  MOZ_ASSERT(!sChild);
  MOZ_ASSERT(!sParent);
  MOZ_ASSERT(aThread);
  MOZ_ASSERT(!sInitialized);

  sInitialized = true;
  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(aThread, 0);
  sParent = new UiCompositorControllerParent();
  aThread->Dispatch(NewRunnableMethod(child, &UiCompositorControllerChild::OpenForSameProcess), nsIThread::DISPATCH_NORMAL);
}

/* static */ void
UiCompositorControllerChild::InitWithGPUProcess(RefPtr<nsThread> aThread,
                                                const uint64_t& aProcessToken,
                                                Endpoint<PUiCompositorControllerChild>&& aEndpoint)
{
  MOZ_ASSERT(!sChild);
  MOZ_ASSERT(!sParent);
  MOZ_ASSERT(aThread);
  MOZ_ASSERT(!sInitialized);

  sInitialized = true;
  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(aThread, aProcessToken);

  RefPtr<nsIRunnable> task = NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>(
    child, &UiCompositorControllerChild::OpenForGPUProcess, Move(aEndpoint));

  aThread->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
}

void
UiCompositorControllerChild::OpenForSameProcess()
{
  MOZ_ASSERT(sParent);
  MOZ_ASSERT(!sChild);
  MOZ_ASSERT(IsOnUiThread());

  if (!Open(sParent->GetIPCChannel(),
           mozilla::layers::CompositorThreadHolder::Loop(),
           mozilla::ipc::ChildSide)) {
    sParent = nullptr;
    return;
  }

  AddRef();
  sChild = this;
}

void
UiCompositorControllerChild::OpenForGPUProcess(Endpoint<PUiCompositorControllerChild>&& aEndpoint)
{
  MOZ_ASSERT(!sChild);
  MOZ_ASSERT(IsOnUiThread());

  if (!aEndpoint.Bind(this)) {
    // The GPU Process Manager might be gone if we receive ActorDestroy very
    // late in shutdown.
    if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
      gpm->NotifyRemoteActorDestroyed(mProcessToken);
    }
    return;
  }

  AddRef();
  sChild = this;
}

void
UiCompositorControllerChild::Close()
{
  if (!IsOnUiThread()) {
    mUiThread->Dispatch(NewRunnableMethod(this, &UiCompositorControllerChild::Close), nsIThread::DISPATCH_NORMAL);
    return;
  }

  // We clear mProcessToken when the channel is closed.
  if (!mProcessToken) {
    return;
  }

  // Clear the process token so we don't notify the GPUProcessManager. It already
  // knows we're closed since it manually called Close, and in fact the GPM could
  // have already been destroyed during shutdown.
  mProcessToken = 0;
  if (this == sChild) {
    sChild = nullptr;
  }

  // Close the underlying IPC channel.
  PUiCompositorControllerChild::Close();
}

void
UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy)
{
  if (mProcessToken) {
    GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    mProcessToken = 0;
    sParent = nullptr;
  }
}

void
UiCompositorControllerChild::DeallocPUiCompositorControllerChild()
{
  Release();
  sInitialized = false;
}

void
UiCompositorControllerChild::ProcessingError(Result aCode, const char* aReason)
{
  MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in UiCompositorControllerChild");
}

void
UiCompositorControllerChild::HandleFatalError(const char* aName, const char* aMsg) const
{
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
}

bool
UiCompositorControllerChild::IsOnUiThread() const
{
  return NS_GetCurrentThread() == mUiThread;
}

} // namespace layers
} // namespace mozilla