Mypal/gfx/layers/ipc/CrossProcessCompositorBridg...

576 lines
19 KiB
C++

/* -*- 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/CrossProcessCompositorBridgeParent.h"
#include <stdio.h> // for fprintf, stdout
#include <stdint.h> // for uint64_t
#include <map> // for _Rb_tree_iterator, etc
#include <utility> // for pair
#include "LayerTransactionParent.h" // for LayerTransactionParent
#include "RenderTrace.h" // for RenderTraceLayers
#include "base/message_loop.h" // for MessageLoop
#include "base/process.h" // for ProcessId
#include "base/task.h" // for CancelableTask, etc
#include "base/thread.h" // for Thread
#include "gfxContext.h" // for gfxContext
#include "gfxPlatform.h" // for gfxPlatform
#include "TreeTraversal.h" // for ForEachNode
#ifdef MOZ_WIDGET_GTK
#include "gfxPlatformGtk.h" // for gfxPlatform
#endif
#include "gfxPrefs.h" // for gfxPrefs
#include "mozilla/AutoRestore.h" // for AutoRestore
#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
#include "mozilla/DebugOnly.h" // for DebugOnly
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Rect.h" // for IntSize
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
#include "mozilla/layers/APZThreadUtils.h" // for APZCTreeManager
#include "mozilla/layers/AsyncCompositionManager.h"
#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/FrameUniformityData.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/RemoteContentController.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Telemetry.h"
#ifdef MOZ_WIDGET_GTK
#include "basic/X11BasicCompositor.h" // for X11BasicCompositor
#endif
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ASSERTION, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsIWidget.h" // for nsIWidget
#include "nsTArray.h" // for nsTArray
#include "nsThreadUtils.h" // for NS_IsMainThread
#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
#ifdef XP_WIN
#include "mozilla/layers/CompositorD3D11.h"
#include "mozilla/layers/CompositorD3D9.h"
#endif
#include "GeckoProfiler.h"
#include "mozilla/ipc/ProtocolTypes.h"
#include "mozilla/Unused.h"
#include "mozilla/Hal.h"
#include "mozilla/HalTypes.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/VsyncDispatcher.h"
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
#include "VsyncSource.h"
#endif
#include "mozilla/widget/CompositorWidget.h"
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
# include "mozilla/widget/CompositorWidgetParent.h"
#endif
#include "LayerScope.h"
namespace mozilla {
namespace layers {
using namespace std;
// defined in CompositorBridgeParent.cpp
typedef map<uint64_t, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
extern LayerTreeMap sIndirectLayerTrees;
extern StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
bool
CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint()
{
mNotifyAfterRemotePaint = true;
return true;
}
void
CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
{
// We must keep this object alive untill the code handling message
// reception is finished on this thread.
MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy));
}
PLayerTransactionParent*
CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent(
const nsTArray<LayersBackend>&,
const uint64_t& aId,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
bool *aSuccess)
{
MOZ_ASSERT(aId != 0);
// Check to see if this child process has access to this layer tree.
if (!LayerTreeOwnerTracker::Get()->IsMapped(aId, OtherPid())) {
NS_ERROR("Unexpected layers id in AllocPLayerTransactionParent; dropping message...");
return nullptr;
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState* state = nullptr;
LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId);
if (sIndirectLayerTrees.end() != itr) {
state = &itr->second;
}
if (state && state->mLayerManager) {
state->mCrossProcessParent = this;
LayerManagerComposite* lm = state->mLayerManager;
*aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier();
*aSuccess = true;
LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId);
p->AddIPDLReference();
sIndirectLayerTrees[aId].mLayerTree = p;
p->SetPendingCompositorUpdates(state->mPendingCompositorUpdates);
return p;
}
NS_WARNING("Created child without a matching parent?");
*aSuccess = false;
LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId);
p->AddIPDLReference();
return p;
}
bool
CrossProcessCompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
{
LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers);
EraseLayerState(slp->GetId());
static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference();
return true;
}
bool
CrossProcessCompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
{
// Check to see if this child process has access to this layer tree.
if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
NS_ERROR("Unexpected layers id in RecvAsyncPanZoomEnabled; dropping message...");
return false;
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
*aHasAPZ = state.mParent ? state.mParent->AsyncPanZoomEnabled() : false;
return true;
}
PAPZCTreeManagerParent*
CrossProcessCompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
{
// Check to see if this child process has access to this layer tree.
if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
NS_ERROR("Unexpected layers id in AllocPAPZCTreeManagerParent; dropping message...");
return nullptr;
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
MOZ_ASSERT(state.mParent);
MOZ_ASSERT(!state.mApzcTreeManagerParent);
state.mApzcTreeManagerParent = new APZCTreeManagerParent(aLayersId, state.mParent->GetAPZCTreeManager());
return state.mApzcTreeManagerParent;
}
bool
CrossProcessCompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
{
APZCTreeManagerParent* parent = static_cast<APZCTreeManagerParent*>(aActor);
MonitorAutoLock lock(*sIndirectLayerTreesLock);
auto iter = sIndirectLayerTrees.find(parent->LayersId());
if (iter != sIndirectLayerTrees.end()) {
CompositorBridgeParent::LayerTreeState& state = iter->second;
MOZ_ASSERT(state.mApzcTreeManagerParent == parent);
state.mApzcTreeManagerParent = nullptr;
}
delete parent;
return true;
}
PAPZParent*
CrossProcessCompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
{
// Check to see if this child process has access to this layer tree.
if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
NS_ERROR("Unexpected layers id in AllocPAPZParent; dropping message...");
return nullptr;
}
RemoteContentController* controller = new RemoteContentController();
// Increment the controller's refcount before we return it. This will keep the
// controller alive until it is released by IPDL in DeallocPAPZParent.
controller->AddRef();
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
MOZ_ASSERT(!state.mController);
state.mController = controller;
return controller;
}
bool
CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
{
RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
controller->Release();
return true;
}
bool
CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
it != sIndirectLayerTrees.end(); it++) {
CompositorBridgeParent::LayerTreeState* lts = &it->second;
if (lts->mParent && lts->mCrossProcessParent == this) {
lts->mParent->NotifyChildCreated(child);
return true;
}
}
return false;
}
void
CrossProcessCompositorBridgeParent::ShadowLayersUpdated(
LayerTransactionParent* aLayerTree,
const uint64_t& aTransactionId,
const TargetConfig& aTargetConfig,
const InfallibleTArray<PluginWindowData>& aPlugins,
bool aIsFirstPaint,
bool aScheduleComposite,
uint32_t aPaintSequenceNumber,
bool aIsRepeatTransaction,
int32_t /*aPaintSyncId: unused*/,
bool aHitTestUpdate)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
MOZ_ASSERT(state->mParent);
state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
Layer* shadowRoot = aLayerTree->GetRoot();
if (shadowRoot) {
CompositorBridgeParent::SetShadowProperties(shadowRoot);
}
UpdateIndirectTree(id, shadowRoot, aTargetConfig);
// Cache the plugin data for this remote layer tree
state->mPluginData = aPlugins;
state->mUpdatedPluginDataAvailable = true;
state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,
aPaintSequenceNumber, aIsRepeatTransaction, aHitTestUpdate);
// Send the 'remote paint ready' message to the content thread if it has already asked.
if(mNotifyAfterRemotePaint) {
Unused << SendRemotePaintIsReady();
mNotifyAfterRemotePaint = false;
}
if (aLayerTree->ShouldParentObserveEpoch()) {
// Note that we send this through the window compositor, since this needs
// to reach the widget owning the tab.
Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), true);
}
aLayerTree->SetPendingTransactionId(aTransactionId);
}
void
CrossProcessCompositorBridgeParent::DidComposite(
uint64_t aId,
TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd)
{
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
layerTree->SetPendingTransactionId(0);
}
}
void
CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorBridgeParent* parent;
{ // scope lock
MonitorAutoLock lock(*sIndirectLayerTreesLock);
parent = sIndirectLayerTrees[id].mParent;
}
if (parent) {
parent->ForceComposite(aLayerTree);
}
}
void
CrossProcessCompositorBridgeParent::NotifyClearCachedResources(LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (state && state->mParent) {
// Note that we send this through the window compositor, since this needs
// to reach the widget owning the tab.
Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), false);
}
}
bool
CrossProcessCompositorBridgeParent::SetTestSampleTime(
LayerTransactionParent* aLayerTree, const TimeStamp& aTime)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return false;
}
MOZ_ASSERT(state->mParent);
return state->mParent->SetTestSampleTime(aLayerTree, aTime);
}
void
CrossProcessCompositorBridgeParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
MOZ_ASSERT(state->mParent);
state->mParent->LeaveTestMode(aLayerTree);
}
void
CrossProcessCompositorBridgeParent::ApplyAsyncProperties(
LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
MOZ_ASSERT(state->mParent);
state->mParent->ApplyAsyncProperties(aLayerTree);
}
void
CrossProcessCompositorBridgeParent::FlushApzRepaints(const LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
MOZ_ASSERT(state->mParent);
state->mParent->FlushApzRepaints(aLayerTree);
}
void
CrossProcessCompositorBridgeParent::GetAPZTestData(
const LayerTransactionParent* aLayerTree,
APZTestData* aOutData)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
MonitorAutoLock lock(*sIndirectLayerTreesLock);
*aOutData = sIndirectLayerTrees[id].mApzTestData;
}
void
CrossProcessCompositorBridgeParent::SetConfirmedTargetAPZC(
const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state || !state->mParent) {
return;
}
state->mParent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets);
}
AsyncCompositionManager*
CrossProcessCompositorBridgeParent::GetCompositionManager(LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
const CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state) {
return nullptr;
}
MOZ_ASSERT(state->mParent);
return state->mParent->GetCompositionManager(aLayerTree);
}
bool
CrossProcessCompositorBridgeParent::RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId)
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
if (LayerTransactionParent* ltp = state.mLayerTree) {
ltp->AcknowledgeCompositorUpdate();
}
MOZ_ASSERT(state.mPendingCompositorUpdates > 0);
state.mPendingCompositorUpdates--;
return true;
}
void
CrossProcessCompositorBridgeParent::DeferredDestroy()
{
mCompositorThreadHolder = nullptr;
mSelfRef = nullptr;
}
CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent()
{
MOZ_ASSERT(XRE_GetIOMessageLoop());
MOZ_ASSERT(IToplevelProtocol::GetTransport());
}
PTextureParent*
CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
const LayersBackend& aLayersBackend,
const TextureFlags& aFlags,
const uint64_t& aId,
const uint64_t& aSerial)
{
CompositorBridgeParent::LayerTreeState* state = nullptr;
LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId);
if (sIndirectLayerTrees.end() != itr) {
state = &itr->second;
}
TextureFlags flags = aFlags;
if (!state || state->mPendingCompositorUpdates) {
// The compositor was recreated, and we're receiving layers updates for a
// a layer manager that will soon be discarded or invalidated. We can't
// return null because this will mess up deserialization later and we'll
// kill the content process. Instead, we signal that the underlying
// TextureHost should not attempt to access the compositor.
flags |= TextureFlags::INVALID_COMPOSITOR;
} else if (state->mLayerManager && state->mLayerManager->GetCompositor() &&
aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) {
gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong";
}
return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
}
bool
CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
{
return TextureHost::DestroyIPDLActor(actor);
}
bool
CrossProcessCompositorBridgeParent::IsSameProcess() const
{
return OtherPid() == base::GetCurrentProcId();
}
bool
CrossProcessCompositorBridgeParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
const uint32_t& aPresShellId)
{
CompositorBridgeParent* parent;
{ // scope lock
MonitorAutoLock lock(*sIndirectLayerTreesLock);
parent = sIndirectLayerTrees[aLayersId].mParent;
}
if (parent) {
parent->ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId));
}
return true;
}
bool
CrossProcessCompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion)
{
CompositorBridgeParent* parent;
{ // scope lock
MonitorAutoLock lock(*sIndirectLayerTreesLock);
parent = sIndirectLayerTrees[aGuid.mLayersId].mParent;
}
if (parent) {
return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion);
}
return true;
}
void
CrossProcessCompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state || !state->mParent) {
return;
}
state->mParent->UpdatePaintTime(aLayerTree, aPaintTime);
}
} // namespace layers
} // namespace mozilla