fune/gfx/layers/client/ClientLayerManager.cpp
Margareta Eliza Balazs b1e7992b82 Backed out 8 changesets (bug 1265824) for bustage in /builds/worker/workspace/build/src/gfx/layers/opengl/CompositorOGL.cpp on a CLOSED TREE
Backed out changeset 1099d6f15f9f (bug 1265824)
Backed out changeset b5ba15b1a70f (bug 1265824)
Backed out changeset 51795de4adaf (bug 1265824)
Backed out changeset be68741ff4ce (bug 1265824)
Backed out changeset 4731dc56702d (bug 1265824)
Backed out changeset 984133e9614b (bug 1265824)
Backed out changeset efce316a4425 (bug 1265824)
Backed out changeset 367abce30668 (bug 1265824)
2018-07-19 09:33:28 +03:00

968 lines
29 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "ClientLayerManager.h"
#include "GeckoProfiler.h" // for AUTO_PROFILER_LABEL
#include "gfxEnv.h" // for gfxEnv
#include "gfxPrefs.h" // for gfxPrefs::LayersTile...
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Hal.h"
#include "mozilla/dom/ScreenOrientation.h" // for ScreenOrientation
#include "mozilla/dom/TabChild.h" // for TabChild
#include "mozilla/dom/TabGroup.h" // for TabGroup
#include "mozilla/hal_sandbox/PHal.h" // for ScreenConfiguration
#include "mozilla/layers/CompositableClient.h"
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
#include "mozilla/layers/FrameUniformityData.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/PersistentBufferProvider.h"
#include "mozilla/layers/SyncObject.h"
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
#include "nsAString.h"
#include "nsDisplayList.h"
#include "nsIWidgetListener.h"
#include "nsTArray.h" // for AutoTArray
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "TiledLayerBuffer.h"
#include "FrameLayerBuilder.h" // for FrameLayerbuilder
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h"
#include "LayerMetricsWrapper.h"
#endif
#ifdef XP_WIN
#include "mozilla/gfx/DeviceManagerDx.h"
#include "gfxDWriteFonts.h"
#endif
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
void
ClientLayerManager::MemoryPressureObserver::Destroy()
{
UnregisterMemoryPressureEvent();
mClientLayerManager = nullptr;
}
NS_IMETHODIMP
ClientLayerManager::MemoryPressureObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aSomeData)
{
if (!mClientLayerManager || strcmp(aTopic, "memory-pressure")) {
return NS_OK;
}
mClientLayerManager->HandleMemoryPressure();
return NS_OK;
}
void
ClientLayerManager::MemoryPressureObserver::RegisterMemoryPressureEvent()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
MOZ_ASSERT(observerService);
if (observerService) {
observerService->AddObserver(this, "memory-pressure", false);
}
}
void
ClientLayerManager::MemoryPressureObserver::UnregisterMemoryPressureEvent()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "memory-pressure");
}
}
NS_IMPL_ISUPPORTS(ClientLayerManager::MemoryPressureObserver, nsIObserver)
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
: mPhase(PHASE_NONE)
, mWidget(aWidget)
, mLatestTransactionId{0}
, mLastPaintTime(TimeDuration::Forever())
, mTargetRotation(ROTATION_0)
, mRepeatTransaction(false)
, mIsRepeatTransaction(false)
, mTransactionIncomplete(false)
, mCompositorMightResample(false)
, mNeedsComposite(false)
, mQueuedAsyncPaints(false)
, mPaintSequenceNumber(0)
, mForwarder(new ShadowLayerForwarder(this))
{
MOZ_COUNT_CTOR(ClientLayerManager);
mMemoryPressureObserver = new MemoryPressureObserver(this);
}
ClientLayerManager::~ClientLayerManager()
{
mMemoryPressureObserver->Destroy();
ClearCachedResources();
// Stop receiveing AsyncParentMessage at Forwarder.
// After the call, the message is directly handled by LayerTransactionChild.
// Basically this function should be called in ShadowLayerForwarder's
// destructor. But when the destructor is triggered by
// CompositorBridgeChild::Destroy(), the destructor can not handle it correctly.
// See Bug 1000525.
mForwarder->StopReceiveAsyncParentMessge();
mRoot = nullptr;
MOZ_COUNT_DTOR(ClientLayerManager);
}
void
ClientLayerManager::Destroy()
{
// It's important to call ClearCachedResource before Destroy because the
// former will early-return if the later has already run.
ClearCachedResources();
LayerManager::Destroy();
if (mTransactionIdAllocator) {
// Make sure to notify the refresh driver just in case it's waiting on a
// pending transaction. Do this at the top of the event loop so we don't
// cause a paint to occur during compositor shutdown.
RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
TransactionId id = mLatestTransactionId;
RefPtr<Runnable> task = NS_NewRunnableFunction(
"TransactionIdAllocator::NotifyTransactionCompleted",
[allocator, id] () -> void {
allocator->NotifyTransactionCompleted(id);
});
NS_DispatchToMainThread(task.forget());
}
// Forget the widget pointer in case we outlive our owning widget.
mWidget = nullptr;
}
TabGroup*
ClientLayerManager::GetTabGroup()
{
if (mWidget) {
if (TabChild* tabChild = mWidget->GetOwningTabChild()) {
return tabChild->TabGroup();
}
}
return nullptr;
}
int32_t
ClientLayerManager::GetMaxTextureSize() const
{
return mForwarder->GetMaxTextureSize();
}
void
ClientLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering,
ScreenRotation aRotation)
{
mTargetRotation = aRotation;
}
void
ClientLayerManager::SetRoot(Layer* aLayer)
{
if (mRoot != aLayer) {
// Have to hold the old root and its children in order to
// maintain the same view of the layer tree in this process as
// the parent sees. Otherwise layers can be destroyed
// mid-transaction and bad things can happen (v. bug 612573)
if (mRoot) {
Hold(mRoot);
}
mForwarder->SetRoot(Hold(aLayer));
NS_ASSERTION(aLayer, "Root can't be null");
NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
mRoot = aLayer;
}
}
void
ClientLayerManager::Mutated(Layer* aLayer)
{
LayerManager::Mutated(aLayer);
NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
mForwarder->Mutated(Hold(aLayer));
}
void
ClientLayerManager::MutatedSimple(Layer* aLayer)
{
LayerManager::MutatedSimple(aLayer);
NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
mForwarder->MutatedSimple(Hold(aLayer));
}
already_AddRefed<ReadbackLayer>
ClientLayerManager::CreateReadbackLayer()
{
RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
return layer.forget();
}
bool
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
{
#ifdef MOZ_DUMP_PAINTING
// When we are dump painting, we expect to be able to read the contents of
// compositable clients from previous paints inside this layer transaction
// before we flush async paints in EndTransactionInternal.
// So to work around this flush async paints now.
if (gfxEnv::DumpPaint()) {
FlushAsyncPaints();
}
#endif
MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
if (!mForwarder->IPCOpen()) {
gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
return false;
}
mInTransaction = true;
mTransactionStart = TimeStamp::Now();
#ifdef MOZ_LAYERS_HAVE_LOG
MOZ_LAYERS_LOG(("[----- BeginTransaction"));
Log();
#endif
NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
mPhase = PHASE_CONSTRUCTION;
MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
// If the last transaction was incomplete (a failed DoEmptyTransaction),
// don't signal a new transaction to ShadowLayerForwarder. Carry on adding
// to the previous transaction.
dom::ScreenOrientationInternal orientation;
if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
orientation = window->GetOrientation();
} else {
hal::ScreenConfiguration currentConfig;
hal::GetCurrentScreenConfiguration(&currentConfig);
orientation = currentConfig.orientation();
}
LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds();
targetBounds.MoveTo(0, 0);
mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation,
orientation);
// If we're drawing on behalf of a context with async pan/zoom
// enabled, then the entire buffer of painted layers might be
// composited (including resampling) asynchronously before we get
// a chance to repaint, so we have to ensure that it's all valid
// and not rotated.
//
// Desktop does not support async zoom yet, so we ignore this for those
// platforms.
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
if (mWidget && mWidget->GetOwningTabChild()) {
mCompositorMightResample = AsyncPanZoomEnabled();
}
#endif
// If we have a non-default target, we need to let our shadow manager draw
// to it. This will happen at the end of the transaction.
if (aTarget && XRE_IsParentProcess()) {
mShadowTarget = aTarget;
} else {
NS_ASSERTION(!aTarget,
"Content-process ClientLayerManager::BeginTransactionWithTarget not supported");
}
// If this is a new paint, increment the paint sequence number.
if (!mIsRepeatTransaction) {
// Increment the paint sequence number even if test logging isn't
// enabled in this process; it may be enabled in the parent process,
// and the parent process expects unique sequence numbers.
++mPaintSequenceNumber;
if (gfxPrefs::APZTestLoggingEnabled()) {
mApzTestData.StartNewPaint(mPaintSequenceNumber);
}
}
return true;
}
bool
ClientLayerManager::BeginTransaction()
{
return BeginTransactionWithTarget(nullptr);
}
bool
ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags)
{
// Wait for any previous async paints to complete before starting to paint again.
// Do this outside the profiler and telemetry block so this doesn't count as time
// spent rasterizing.
{
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::FlushRasterization);
FlushAsyncPaints();
}
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
AUTO_PROFILER_TRACING("Paint", "Rasterize");
Maybe<TimeStamp> startTime;
if (gfxPrefs::LayersDrawFPS()) {
startTime = Some(TimeStamp::Now());
}
#ifdef WIN32
if (aCallbackData) {
// Content processes don't get OnPaint called. So update here whenever we
// may do Thebes drawing.
gfxDWriteFont::UpdateClearTypeUsage();
}
#endif
AUTO_PROFILER_LABEL("ClientLayerManager::EndTransactionInternal", GRAPHICS);
#ifdef MOZ_LAYERS_HAVE_LOG
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
Log();
#endif
NS_ASSERTION(InConstruction(), "Should be in construction phase");
mPhase = PHASE_DRAWING;
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
mTransactionIncomplete = false;
mQueuedAsyncPaints = false;
// Apply pending tree updates before recomputing effective
// properties.
GetRoot()->ApplyPendingUpdatesToSubtree();
mPaintedLayerCallback = aCallback;
mPaintedLayerCallbackData = aCallbackData;
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
// Skip the painting if the device is in device-reset status.
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
TimeStamp start = TimeStamp::Now();
root->RenderLayer();
mLastPaintTime = TimeStamp::Now() - start;
} else {
root->RenderLayer();
}
} else {
gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer().";
}
if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
GetRoot()->Mutated();
}
if (!mIsRepeatTransaction) {
mAnimationReadyTime = TimeStamp::Now();
GetRoot()->StartPendingAnimations(mAnimationReadyTime);
}
mPaintedLayerCallback = nullptr;
mPaintedLayerCallbackData = nullptr;
// Go back to the construction phase if the transaction isn't complete.
// Layout will update the layer tree and call EndTransaction().
mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
NS_ASSERTION(!aCallback || !mTransactionIncomplete,
"If callback is not null, transaction must be complete");
if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
FrameLayerBuilder::InvalidateAllLayers(this);
}
if (startTime) {
PaintTiming& pt = mForwarder->GetPaintTiming();
pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
}
return !mTransactionIncomplete;
}
void
ClientLayerManager::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>& aConfigurations)
{
if (mForwarder) {
mForwarder->StorePluginWidgetConfigurations(aConfigurations);
}
}
void
ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags)
{
if (!mForwarder->IPCOpen()) {
mInTransaction = false;
return;
}
if (mWidget) {
mWidget->PrepareWindowEffects();
}
EndTransactionInternal(aCallback, aCallbackData, aFlags);
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
if (mRepeatTransaction) {
mRepeatTransaction = false;
mIsRepeatTransaction = true;
// BeginTransaction will reset the transaction start time, but we
// would like to keep the original time for telemetry purposes.
TimeStamp transactionStart = mTransactionStart;
if (BeginTransaction()) {
mTransactionStart = transactionStart;
ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
}
mIsRepeatTransaction = false;
} else {
MakeSnapshotIfRequired();
}
mInTransaction = false;
mTransactionStart = TimeStamp();
}
bool
ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
{
mInTransaction = false;
if (!mRoot || !mForwarder->IPCOpen()) {
return false;
}
if (!EndTransactionInternal(nullptr, nullptr, aFlags)) {
// Return without calling ForwardTransaction. This leaves the
// ShadowLayerForwarder transaction open; the following
// EndTransaction will complete it.
if (PaintThread::Get() && mQueuedAsyncPaints) {
PaintThread::Get()->EndLayerTransaction(nullptr);
}
return false;
}
if (mWidget) {
mWidget->PrepareWindowEffects();
}
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
MakeSnapshotIfRequired();
return true;
}
CompositorBridgeChild *
ClientLayerManager::GetRemoteRenderer()
{
if (!mWidget) {
return nullptr;
}
return mWidget->GetRemoteRenderer();
}
CompositorBridgeChild*
ClientLayerManager::GetCompositorBridgeChild()
{
if (!XRE_IsParentProcess()) {
return CompositorBridgeChild::Get();
}
return GetRemoteRenderer();
}
void
ClientLayerManager::FlushAsyncPaints()
{
AUTO_PROFILER_LABEL("ClientLayerManager::FlushAsyncPaints", GRAPHICS);
CompositorBridgeChild* cbc = GetCompositorBridgeChild();
if (cbc) {
cbc->FlushAsyncPaints();
}
}
void
ClientLayerManager::ScheduleComposite()
{
mForwarder->ScheduleComposite();
}
void
ClientLayerManager::DidComposite(TransactionId aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd)
{
MOZ_ASSERT(mWidget);
// Notifying the observers may tick the refresh driver which can cause
// a lot of different things to happen that may affect the lifetime of
// this layer manager. So let's make sure this object stays alive until
// the end of the method invocation.
RefPtr<ClientLayerManager> selfRef = this;
// |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
// layers transaction.
if (aTransactionId.IsValid()) {
nsIWidgetListener *listener = mWidget->GetWidgetListener();
if (listener) {
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
}
listener = mWidget->GetAttachedWidgetListener();
if (listener) {
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
}
if (mTransactionIdAllocator) {
mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
}
}
// These observers fire whether or not we were in a transaction.
for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
mDidCompositeObservers[i]->DidComposite();
}
}
void
ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
{
if (mForwarder->HasShadowManager()) {
if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
}
}
}
void
ClientLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAllocator)
{
// When changing the refresh driver, the previous refresh driver may never
// receive updates of pending transactions it's waiting for. So clear the
// waiting state before assigning another refresh driver.
if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
mTransactionIdAllocator->ClearPendingTransactions();
// We should also reset the transaction id of the new allocator to previous
// allocator's last transaction id, so that completed transactions for
// previous allocator will be ignored and won't confuse the new allocator.
if (aAllocator) {
aAllocator->ResetInitialTransactionId(mTransactionIdAllocator->LastTransactionId());
}
}
mTransactionIdAllocator = aAllocator;
}
float
ClientLayerManager::RequestProperty(const nsAString& aProperty)
{
if (mForwarder->HasShadowManager()) {
float value;
if (!mForwarder->GetShadowManager()->SendRequestProperty(nsString(aProperty), &value)) {
NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
}
return value;
}
return -1;
}
void
ClientLayerManager::StartNewRepaintRequest(SequenceNumber aSequenceNumber)
{
if (gfxPrefs::APZTestLoggingEnabled()) {
mApzTestData.StartNewRepaintRequest(aSequenceNumber);
}
}
void
ClientLayerManager::GetFrameUniformity(FrameUniformityData* aOutData)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Frame Uniformity only supported in parent process");
if (HasShadowManager()) {
CompositorBridgeChild* child = GetRemoteRenderer();
child->SendGetFrameUniformity(aOutData);
return;
}
return LayerManager::GetFrameUniformity(aOutData);
}
void
ClientLayerManager::MakeSnapshotIfRequired()
{
if (!mShadowTarget) {
return;
}
if (mWidget) {
if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
// The compositor doesn't draw to a different sized surface
// when there's a rotation. Instead we rotate the result
// when drawing into dt
LayoutDeviceIntRect outerBounds = mWidget->GetBounds();
IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
if (mTargetRotation) {
bounds =
RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation);
}
SurfaceDescriptor inSnapshot;
if (!bounds.IsEmpty() &&
mForwarder->AllocSurfaceDescriptor(bounds.Size(),
gfxContentType::COLOR_ALPHA,
&inSnapshot)) {
// Make a copy of |inSnapshot| because the call to send it over IPC
// will call forget() on the Shmem inside, and zero it out.
SurfaceDescriptor outSnapshot = inSnapshot;
if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot);
DrawTarget* dt = mShadowTarget->GetDrawTarget();
Rect dstRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
Rect srcRect(0, 0, bounds.Width(), bounds.Height());
gfx::Matrix rotate =
ComputeTransformForUnRotation(outerBounds.ToUnknownRect(),
mTargetRotation);
gfx::Matrix oldMatrix = dt->GetTransform();
dt->SetTransform(rotate * oldMatrix);
dt->DrawSurface(surf, dstRect, srcRect,
DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER));
dt->SetTransform(oldMatrix);
}
mForwarder->DestroySurfaceDescriptor(&outSnapshot);
}
}
}
mShadowTarget = nullptr;
}
void
ClientLayerManager::FlushRendering()
{
if (mWidget) {
if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) {
remoteRenderer->SendFlushRendering();
} else {
remoteRenderer->SendFlushRenderingAsync();
}
}
}
}
void
ClientLayerManager::WaitOnTransactionProcessed()
{
CompositorBridgeChild* remoteRenderer = GetCompositorBridgeChild();
if (remoteRenderer) {
remoteRenderer->SendWaitOnTransactionProcessed();
}
}
void
ClientLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier)
{
mForwarder->IdentifyTextureHost(aNewIdentifier);
}
void
ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
{
if (mWidget) {
if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
remoteRenderer->SendNotifyRegionInvalidated(aRegion);
}
}
}
uint32_t
ClientLayerManager::StartFrameTimeRecording(int32_t aBufferSize)
{
CompositorBridgeChild* renderer = GetRemoteRenderer();
if (renderer) {
uint32_t startIndex;
renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
return startIndex;
}
return -1;
}
void
ClientLayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
nsTArray<float>& aFrameIntervals)
{
CompositorBridgeChild* renderer = GetRemoteRenderer();
if (renderer) {
renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
}
}
void
ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
{
AUTO_PROFILER_TRACING("Paint", "ForwardTransaction");
TimeStamp start = TimeStamp::Now();
// Skip the synchronization for buffer since we also skip the painting during
// device-reset status. With OMTP, we have to wait for async paints
// before we synchronize and it's done on the paint thread.
RefPtr<SyncObjectClient> syncObject = nullptr;
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
if (mForwarder->GetSyncObject() &&
mForwarder->GetSyncObject()->IsSyncObjectValid()) {
syncObject = mForwarder->GetSyncObject();
}
}
// If there were async paints queued, then we need to notify the paint thread
// that we finished queuing async paints so it can schedule a runnable after
// all async painting is finished to do a texture sync and unblock the main
// thread if it is waiting before doing a new layer transaction.
if (mQueuedAsyncPaints) {
MOZ_ASSERT(PaintThread::Get());
PaintThread::Get()->EndLayerTransaction(syncObject);
} else if (syncObject) {
syncObject->Synchronize();
}
mPhase = PHASE_FORWARD;
mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction);
TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime);
}
// forward this transaction's changeset to our LayerManagerComposite
bool sent = false;
bool ok = mForwarder->EndTransaction(
mRegionToClear, mLatestTransactionId, aScheduleComposite,
mPaintSequenceNumber, mIsRepeatTransaction,
refreshStart, mTransactionStart,
&sent);
if (ok) {
if (sent) {
mNeedsComposite = false;
}
} else if (HasShadowManager()) {
NS_WARNING("failed to forward Layers transaction");
}
if (!sent) {
// Clear the transaction id so that it doesn't get returned
// unless we forwarded to somewhere that doesn't actually
// have a compositor.
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
}
mPhase = PHASE_NONE;
// this may result in Layers being deleted, which results in
// PLayer::Send__delete__() and DeallocShmem()
mKeepAlive.Clear();
TabChild* window = mWidget ? mWidget->GetOwningTabChild() : nullptr;
if (window) {
TimeStamp end = TimeStamp::Now();
window->DidRequestComposite(start, end);
}
}
ShadowableLayer*
ClientLayerManager::Hold(Layer* aLayer)
{
MOZ_ASSERT(HasShadowManager(),
"top-level tree, no shadow tree to remote to");
ShadowableLayer* shadowable = ClientLayer::ToClientLayer(aLayer);
MOZ_ASSERT(shadowable, "trying to remote an unshadowable layer");
mKeepAlive.AppendElement(aLayer);
return shadowable;
}
bool
ClientLayerManager::IsCompositingCheap()
{
// Whether compositing is cheap depends on the parent backend.
return mForwarder->mShadowManager &&
LayerManager::IsCompositingCheap(mForwarder->GetCompositorBackendType());
}
bool
ClientLayerManager::AreComponentAlphaLayersEnabled()
{
return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC &&
AsShadowForwarder()->SupportsComponentAlpha() &&
LayerManager::AreComponentAlphaLayersEnabled();
}
void
ClientLayerManager::SetIsFirstPaint()
{
mForwarder->SetIsFirstPaint();
}
void
ClientLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget)
{
mForwarder->SetFocusTarget(aFocusTarget);
}
void
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
{
if (mDestroyed) {
// ClearCachedResource was already called by ClientLayerManager::Destroy
return;
}
MOZ_ASSERT(!HasShadowManager() || !aSubtree);
mForwarder->ClearCachedResources();
if (aSubtree) {
ClearLayer(aSubtree);
} else if (mRoot) {
ClearLayer(mRoot);
}
}
void
ClientLayerManager::HandleMemoryPressure()
{
if (mRoot) {
HandleMemoryPressureLayer(mRoot);
}
if (GetCompositorBridgeChild()) {
GetCompositorBridgeChild()->HandleMemoryPressure();
}
}
void
ClientLayerManager::ClearLayer(Layer* aLayer)
{
aLayer->ClearCachedResources();
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
ClearLayer(child);
}
}
void
ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer)
{
ClientLayer::ToClientLayer(aLayer)->HandleMemoryPressure();
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
HandleMemoryPressureLayer(child);
}
}
void
ClientLayerManager::GetBackendName(nsAString& aName)
{
switch (mForwarder->GetCompositorBackendType()) {
case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return;
case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
case LayersBackend::LAYERS_D3D11: {
#ifdef XP_WIN
if (DeviceManagerDx::Get()->IsWARP()) {
aName.AssignLiteral("Direct3D 11 WARP");
} else {
aName.AssignLiteral("Direct3D 11");
}
#endif
return;
}
default: MOZ_CRASH("Invalid backend");
}
}
bool
ClientLayerManager::AsyncPanZoomEnabled() const
{
return mWidget && mWidget->AsyncPanZoomEnabled();
}
void
ClientLayerManager::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
{
mForwarder->SetLayerObserverEpoch(aLayerObserverEpoch);
}
void
ClientLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
{
if (!mDidCompositeObservers.Contains(aObserver)) {
mDidCompositeObservers.AppendElement(aObserver);
}
}
void
ClientLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver)
{
mDidCompositeObservers.RemoveElement(aObserver);
}
already_AddRefed<PersistentBufferProvider>
ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat)
{
// Don't use a shared buffer provider if compositing is considered "not cheap"
// because the canvas will most likely be flattened into a thebes layer instead
// of being sent to the compositor, in which case rendering into shared memory
// is wasteful.
if (IsCompositingCheap() &&
gfxPrefs::PersistentBufferProviderSharedEnabled()) {
RefPtr<PersistentBufferProvider> provider
= PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder());
if (provider) {
return provider.forget();
}
}
return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
}
ClientLayer::~ClientLayer()
{
MOZ_COUNT_DTOR(ClientLayer);
}
} // namespace layers
} // namespace mozilla