mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
18f873ac9e
CLOSED TREE Backed out changeset 147581a518c3 (bug 991028) Backed out changeset e5bacc566e58 (bug 991028) Backed out changeset 6dc852777a4d (bug 991028) Backed out changeset 780bec5571b9 (bug 991028)
561 lines
17 KiB
C++
561 lines
17 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* 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 "CompositorChild.h" // for CompositorChild
|
|
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
|
#include "gfxASurface.h" // for gfxASurface, etc
|
|
#include "ipc/AutoOpenSurface.h" // for AutoOpenSurface
|
|
#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/hal_sandbox/PHal.h" // for ScreenConfiguration
|
|
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
|
|
#include "mozilla/layers/ContentClient.h" // for ContentClientRemote
|
|
#include "mozilla/layers/ISurfaceAllocator.h"
|
|
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
|
|
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
|
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
|
|
#include "mozilla/layers/LayerTransactionChild.h"
|
|
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
|
|
#include "mozilla/layers/SimpleTextureClientPool.h" // for SimpleTextureClientPool
|
|
#include "nsAString.h"
|
|
#include "nsIWidget.h" // for nsIWidget
|
|
#include "nsTArray.h" // for AutoInfallibleTArray
|
|
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
|
#include "TiledLayerBuffer.h"
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
#include "AndroidBridge.h"
|
|
#endif
|
|
|
|
using namespace mozilla::dom;
|
|
using namespace mozilla::gfx;
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
|
: mPhase(PHASE_NONE)
|
|
, mWidget(aWidget)
|
|
, mTargetRotation(ROTATION_0)
|
|
, mRepeatTransaction(false)
|
|
, mIsRepeatTransaction(false)
|
|
, mTransactionIncomplete(false)
|
|
, mCompositorMightResample(false)
|
|
, mNeedsComposite(false)
|
|
, mForwarder(new ShadowLayerForwarder)
|
|
{
|
|
MOZ_COUNT_CTOR(ClientLayerManager);
|
|
}
|
|
|
|
ClientLayerManager::~ClientLayerManager()
|
|
{
|
|
mRoot = nullptr;
|
|
|
|
MOZ_COUNT_DTOR(ClientLayerManager);
|
|
}
|
|
|
|
int32_t
|
|
ClientLayerManager::GetMaxTextureSize() const
|
|
{
|
|
return mForwarder->GetMaxTextureSize();
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering,
|
|
ScreenRotation aRotation)
|
|
{
|
|
mTargetRotation = aRotation;
|
|
if (mWidget) {
|
|
mTargetBounds = mWidget->GetNaturalBounds();
|
|
}
|
|
}
|
|
|
|
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::BeginTransactionWithTarget(gfxContext* aTarget)
|
|
{
|
|
mInTransaction = true;
|
|
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
MOZ_LAYERS_LOG(("[----- BeginTransaction"));
|
|
Log();
|
|
#endif
|
|
|
|
NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
|
|
mPhase = PHASE_CONSTRUCTION;
|
|
|
|
NS_ABORT_IF_FALSE(mKeepAlive.IsEmpty(), "uncommitted txn?");
|
|
nsRefPtr<gfxContext> targetContext = aTarget;
|
|
|
|
// If the last transaction was incomplete (a failed DoEmptyTransaction),
|
|
// don't signal a new transaction to ShadowLayerForwarder. Carry on adding
|
|
// to the previous transaction.
|
|
ScreenOrientation orientation;
|
|
if (TabChild* window = mWidget->GetOwningTabChild()) {
|
|
orientation = window->GetOrientation();
|
|
} else {
|
|
hal::ScreenConfiguration currentConfig;
|
|
hal::GetCurrentScreenConfiguration(¤tConfig);
|
|
orientation = currentConfig.orientation();
|
|
}
|
|
nsIntRect clientBounds;
|
|
mWidget->GetClientBounds(clientBounds);
|
|
clientBounds.x = clientBounds.y = 0;
|
|
mForwarder->BeginTransaction(mTargetBounds, mTargetRotation, clientBounds, orientation);
|
|
|
|
// If we're drawing on behalf of a context with async pan/zoom
|
|
// enabled, then the entire buffer of thebes 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.
|
|
if (mWidget) {
|
|
if (TabChild* window = mWidget->GetOwningTabChild()) {
|
|
mCompositorMightResample = window->IsAsyncPanZoomEnabled();
|
|
}
|
|
}
|
|
|
|
// 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_GetProcessType() == GeckoProcessType_Default) {
|
|
mShadowTarget = aTarget;
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::BeginTransaction()
|
|
{
|
|
mInTransaction = true;
|
|
BeginTransactionWithTarget(nullptr);
|
|
}
|
|
|
|
bool
|
|
ClientLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
|
void* aCallbackData,
|
|
EndTransactionFlags)
|
|
{
|
|
PROFILER_LABEL("ClientLayerManager", "EndTransactionInternal");
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
|
|
Log();
|
|
#endif
|
|
profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_START);
|
|
|
|
NS_ASSERTION(InConstruction(), "Should be in construction phase");
|
|
mPhase = PHASE_DRAWING;
|
|
|
|
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
|
|
|
|
mTransactionIncomplete = false;
|
|
|
|
// Apply pending tree updates before recomputing effective
|
|
// properties.
|
|
GetRoot()->ApplyPendingUpdatesToSubtree();
|
|
|
|
mThebesLayerCallback = aCallback;
|
|
mThebesLayerCallbackData = aCallbackData;
|
|
|
|
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
|
|
|
|
root->RenderLayer();
|
|
if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
|
|
GetRoot()->Mutated();
|
|
}
|
|
|
|
mThebesLayerCallback = nullptr;
|
|
mThebesLayerCallbackData = 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");
|
|
|
|
return !mTransactionIncomplete;
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
|
|
void* aCallbackData,
|
|
EndTransactionFlags aFlags)
|
|
{
|
|
if (mWidget) {
|
|
mWidget->PrepareWindowEffects();
|
|
}
|
|
EndTransactionInternal(aCallback, aCallbackData, aFlags);
|
|
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
|
|
|
|
if (mRepeatTransaction) {
|
|
mRepeatTransaction = false;
|
|
mIsRepeatTransaction = true;
|
|
BeginTransaction();
|
|
ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
|
|
mIsRepeatTransaction = false;
|
|
} else {
|
|
MakeSnapshotIfRequired();
|
|
}
|
|
|
|
for (size_t i = 0; i < mTexturePools.Length(); i++) {
|
|
mTexturePools[i]->ReturnDeferredClients();
|
|
}
|
|
}
|
|
|
|
bool
|
|
ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
|
|
{
|
|
mInTransaction = false;
|
|
|
|
if (!mRoot) {
|
|
return false;
|
|
}
|
|
if (!EndTransactionInternal(nullptr, nullptr, aFlags)) {
|
|
// Return without calling ForwardTransaction. This leaves the
|
|
// ShadowLayerForwarder transaction open; the following
|
|
// EndTransaction will complete it.
|
|
return false;
|
|
}
|
|
if (mWidget) {
|
|
mWidget->PrepareWindowEffects();
|
|
}
|
|
ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
|
|
MakeSnapshotIfRequired();
|
|
return true;
|
|
}
|
|
|
|
CompositorChild *
|
|
ClientLayerManager::GetRemoteRenderer()
|
|
{
|
|
if (!mWidget) {
|
|
return nullptr;
|
|
}
|
|
|
|
return mWidget->GetRemoteRenderer();
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::Composite()
|
|
{
|
|
if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
|
|
manager->SendForceComposite();
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::MakeSnapshotIfRequired()
|
|
{
|
|
if (!mShadowTarget) {
|
|
return;
|
|
}
|
|
if (mWidget) {
|
|
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
|
|
nsIntRect bounds;
|
|
mWidget->GetBounds(bounds);
|
|
SurfaceDescriptor inSnapshot, snapshot;
|
|
if (mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
|
|
gfxContentType::COLOR_ALPHA,
|
|
&inSnapshot) &&
|
|
// The compositor will usually reuse |snapshot| and return
|
|
// it through |outSnapshot|, but if it doesn't, it's
|
|
// responsible for freeing |snapshot|.
|
|
remoteRenderer->SendMakeSnapshot(inSnapshot, &snapshot)) {
|
|
AutoOpenSurface opener(OPEN_READ_ONLY, snapshot);
|
|
gfxASurface* source = opener.Get();
|
|
|
|
mShadowTarget->DrawSurface(source, source->GetSize());
|
|
}
|
|
if (IsSurfaceDescriptorValid(snapshot)) {
|
|
mForwarder->DestroySharedSurface(&snapshot);
|
|
}
|
|
}
|
|
}
|
|
mShadowTarget = nullptr;
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::FlushRendering()
|
|
{
|
|
if (mWidget) {
|
|
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
|
remoteRenderer->SendFlushRendering();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
|
|
{
|
|
if (mWidget) {
|
|
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
|
remoteRenderer->SendNotifyRegionInvalidated(aRegion);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
ClientLayerManager::StartFrameTimeRecording(int32_t aBufferSize)
|
|
{
|
|
CompositorChild* renderer = GetRemoteRenderer();
|
|
if (renderer) {
|
|
uint32_t startIndex;
|
|
renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
|
|
return startIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
|
|
nsTArray<float>& aFrameIntervals)
|
|
{
|
|
CompositorChild* renderer = GetRemoteRenderer();
|
|
if (renderer) {
|
|
renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
|
{
|
|
mPhase = PHASE_FORWARD;
|
|
|
|
// forward this transaction's changeset to our LayerManagerComposite
|
|
bool sent;
|
|
AutoInfallibleTArray<EditReply, 10> replies;
|
|
if (HasShadowManager() && mForwarder->EndTransaction(&replies, mRegionToClear, aScheduleComposite, &sent)) {
|
|
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
|
|
const EditReply& reply = replies[i];
|
|
|
|
switch (reply.type()) {
|
|
case EditReply::TOpContentBufferSwap: {
|
|
MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
|
|
|
|
const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
|
|
|
|
CompositableChild* compositableChild =
|
|
static_cast<CompositableChild*>(obs.compositableChild());
|
|
ContentClientRemote* contentClient =
|
|
static_cast<ContentClientRemote*>(compositableChild->GetCompositableClient());
|
|
MOZ_ASSERT(contentClient);
|
|
|
|
contentClient->SwapBuffers(obs.frontUpdatedRegion());
|
|
|
|
break;
|
|
}
|
|
case EditReply::TOpTextureSwap: {
|
|
MOZ_LAYERS_LOG(("[LayersForwarder] TextureSwap"));
|
|
|
|
const OpTextureSwap& ots = reply.get_OpTextureSwap();
|
|
|
|
CompositableChild* compositableChild =
|
|
static_cast<CompositableChild*>(ots.compositableChild());
|
|
MOZ_ASSERT(compositableChild);
|
|
|
|
compositableChild->GetCompositableClient()
|
|
->SetDescriptorFromReply(ots.textureId(), ots.image());
|
|
break;
|
|
}
|
|
case EditReply::TReturnReleaseFence: {
|
|
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
|
|
FenceHandle fence = rep.fence();
|
|
PTextureChild* child = rep.textureChild();
|
|
|
|
if (!fence.IsValid() || !child) {
|
|
break;
|
|
}
|
|
RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child);
|
|
if (texture) {
|
|
texture->SetReleaseFenceHandle(fence);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
NS_RUNTIMEABORT("not reached");
|
|
}
|
|
}
|
|
|
|
if (sent) {
|
|
mNeedsComposite = false;
|
|
}
|
|
} else if (HasShadowManager()) {
|
|
NS_WARNING("failed to forward Layers transaction");
|
|
}
|
|
|
|
mForwarder->RemoveTexturesIfNecessary();
|
|
mPhase = PHASE_NONE;
|
|
|
|
// this may result in Layers being deleted, which results in
|
|
// PLayer::Send__delete__() and DeallocShmem()
|
|
mKeepAlive.Clear();
|
|
}
|
|
|
|
ShadowableLayer*
|
|
ClientLayerManager::Hold(Layer* aLayer)
|
|
{
|
|
NS_ABORT_IF_FALSE(HasShadowManager(),
|
|
"top-level tree, no shadow tree to remote to");
|
|
|
|
ShadowableLayer* shadowable = ClientLayer::ToClientLayer(aLayer);
|
|
NS_ABORT_IF_FALSE(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());
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::SetIsFirstPaint()
|
|
{
|
|
mForwarder->SetIsFirstPaint();
|
|
}
|
|
|
|
TextureClientPool*
|
|
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
|
|
{
|
|
for (size_t i = 0; i < mTexturePools.Length(); i++) {
|
|
if (mTexturePools[i]->GetFormat() == aFormat) {
|
|
return mTexturePools[i];
|
|
}
|
|
}
|
|
|
|
mTexturePools.AppendElement(
|
|
new TextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
|
|
TILEDLAYERBUFFER_TILE_SIZE),
|
|
mForwarder));
|
|
|
|
return mTexturePools.LastElement();
|
|
}
|
|
|
|
SimpleTextureClientPool*
|
|
ClientLayerManager::GetSimpleTileTexturePool(SurfaceFormat aFormat)
|
|
{
|
|
int index = (int) aFormat;
|
|
mSimpleTilePools.EnsureLengthAtLeast(index+1);
|
|
|
|
if (mSimpleTilePools[index].get() == nullptr) {
|
|
mSimpleTilePools[index] = new SimpleTextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
|
|
TILEDLAYERBUFFER_TILE_SIZE),
|
|
mForwarder);
|
|
}
|
|
|
|
return mSimpleTilePools[index];
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
|
|
{
|
|
MOZ_ASSERT(!HasShadowManager() || !aSubtree);
|
|
if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
|
|
manager->SendClearCachedResources();
|
|
}
|
|
if (aSubtree) {
|
|
ClearLayer(aSubtree);
|
|
} else if (mRoot) {
|
|
ClearLayer(mRoot);
|
|
}
|
|
for (size_t i = 0; i < mTexturePools.Length(); i++) {
|
|
mTexturePools[i]->Clear();
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::ClearLayer(Layer* aLayer)
|
|
{
|
|
ClientLayer::ToClientLayer(aLayer)->ClearCachedResources();
|
|
for (Layer* child = aLayer->GetFirstChild(); child;
|
|
child = child->GetNextSibling()) {
|
|
ClearLayer(child);
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::GetBackendName(nsAString& aName)
|
|
{
|
|
switch (mForwarder->GetCompositorBackendType()) {
|
|
case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
|
|
case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
|
|
case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return;
|
|
case LayersBackend::LAYERS_D3D10: aName.AssignLiteral("Direct3D 10"); return;
|
|
case LayersBackend::LAYERS_D3D11: aName.AssignLiteral("Direct3D 11"); return;
|
|
default: NS_RUNTIMEABORT("Invalid backend");
|
|
}
|
|
}
|
|
|
|
bool
|
|
ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
|
ParentLayerRect& aCompositionBounds,
|
|
CSSToParentLayerScale& aZoom,
|
|
bool aDrawingCritical)
|
|
{
|
|
aZoom.scale = 1.0;
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
Layer* primaryScrollable = GetPrimaryScrollableLayer();
|
|
if (primaryScrollable) {
|
|
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
|
|
|
|
// This is derived from the code in
|
|
// gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
|
|
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
|
|
const CSSRect& metricsDisplayPort =
|
|
(aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ?
|
|
metrics.mCriticalDisplayPort : metrics.mDisplayPort;
|
|
LayerRect displayPort = (metricsDisplayPort + metrics.GetScrollOffset()) * paintScale;
|
|
|
|
return AndroidBridge::Bridge()->ProgressiveUpdateCallback(
|
|
aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
|
|
aCompositionBounds, aZoom);
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
ClientLayer::~ClientLayer()
|
|
{
|
|
if (HasShadow()) {
|
|
PLayerChild::Send__delete__(GetShadow());
|
|
}
|
|
MOZ_COUNT_DTOR(ClientLayer);
|
|
}
|
|
|
|
}
|
|
}
|