mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
61ffd37c9d
The bulk of this patch is fixing up pieces of code that infer the resolution as the inverse of the scaling transform on the root layer. This used to be how various bits of gfx code obtained the resolution, but now that we can set the resolution on the actual presShell that contains the content, we can also just read the resolution from the FrameMetrics directly.
473 lines
14 KiB
C++
473 lines
14 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 "gfx3DMatrix.h" // for gfx3DMatrix
|
|
#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/PLayerTransactionChild.h"
|
|
#include "nsAString.h"
|
|
#include "nsIWidget.h" // for nsIWidget
|
|
#include "nsTArray.h" // for AutoInfallibleTArray
|
|
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
|
#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)
|
|
{
|
|
MOZ_COUNT_CTOR(ClientLayerManager);
|
|
}
|
|
|
|
ClientLayerManager::~ClientLayerManager()
|
|
{
|
|
mRoot = nullptr;
|
|
|
|
MOZ_COUNT_DTOR(ClientLayerManager);
|
|
}
|
|
|
|
int32_t
|
|
ClientLayerManager::GetMaxTextureSize() const
|
|
{
|
|
return ShadowLayerForwarder::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);
|
|
}
|
|
ShadowLayerForwarder::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");
|
|
ShadowLayerForwarder::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;
|
|
ShadowLayerForwarder::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(gfx3DMatrix());
|
|
|
|
root->RenderLayer();
|
|
|
|
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();
|
|
|
|
if (mRepeatTransaction) {
|
|
mRepeatTransaction = false;
|
|
mIsRepeatTransaction = true;
|
|
BeginTransaction();
|
|
ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
|
|
mIsRepeatTransaction = false;
|
|
} else {
|
|
MakeSnapshotIfRequired();
|
|
}
|
|
}
|
|
|
|
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();
|
|
MakeSnapshotIfRequired();
|
|
return true;
|
|
}
|
|
|
|
CompositorChild *
|
|
ClientLayerManager::GetRemoteRenderer()
|
|
{
|
|
if (!mWidget) {
|
|
return nullptr;
|
|
}
|
|
|
|
return mWidget->GetRemoteRenderer();
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::MakeSnapshotIfRequired()
|
|
{
|
|
if (!mShadowTarget) {
|
|
return;
|
|
}
|
|
if (mWidget) {
|
|
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
|
|
nsIntRect bounds;
|
|
mWidget->GetBounds(bounds);
|
|
SurfaceDescriptor inSnapshot, snapshot;
|
|
if (AllocSurfaceDescriptor(bounds.Size(),
|
|
GFX_CONTENT_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)) {
|
|
ShadowLayerForwarder::DestroySharedSurface(&snapshot);
|
|
}
|
|
}
|
|
}
|
|
mShadowTarget = nullptr;
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::FlushRendering()
|
|
{
|
|
if (mWidget) {
|
|
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
|
remoteRenderer->SendFlushRendering();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::ForwardTransaction()
|
|
{
|
|
mPhase = PHASE_FORWARD;
|
|
|
|
// forward this transaction's changeset to our LayerManagerComposite
|
|
bool sent;
|
|
AutoInfallibleTArray<EditReply, 10> replies;
|
|
if (HasShadowManager() && ShadowLayerForwarder::EndTransaction(&replies, &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::TReplyTextureRemoved: {
|
|
// XXX - to manage reuse of gralloc buffers, we'll need to add some
|
|
// glue code here to find the TextureClient and invoke a callback to
|
|
// let the camera know that the gralloc buffer is not used anymore on
|
|
// the compositor side and that it can reuse it.
|
|
const ReplyTextureRemoved& rep = reply.get_ReplyTextureRemoved();
|
|
CompositableClient* compositable
|
|
= static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
|
|
compositable->OnReplyTextureRemoved(rep.textureId());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
NS_RUNTIMEABORT("not reached");
|
|
}
|
|
}
|
|
|
|
if (sent) {
|
|
mNeedsComposite = false;
|
|
}
|
|
} else if (HasShadowManager()) {
|
|
NS_WARNING("failed to forward Layers transaction");
|
|
}
|
|
|
|
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 mShadowManager &&
|
|
LayerManager::IsCompositingCheap(GetCompositorBackendType());
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::SetIsFirstPaint()
|
|
{
|
|
ShadowLayerForwarder::SetIsFirstPaint();
|
|
}
|
|
|
|
void
|
|
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
|
|
{
|
|
MOZ_ASSERT(!HasShadowManager() || !aSubtree);
|
|
if (PLayerTransactionChild* manager = GetShadowManager()) {
|
|
manager->SendClearCachedResources();
|
|
}
|
|
if (aSubtree) {
|
|
ClearLayer(aSubtree);
|
|
} else if (mRoot) {
|
|
ClearLayer(mRoot);
|
|
}
|
|
}
|
|
|
|
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 (GetCompositorBackendType()) {
|
|
case LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
|
|
case LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
|
|
case LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return;
|
|
case LAYERS_D3D10: aName.AssignLiteral("Direct3D 10"); return;
|
|
case LAYERS_D3D11: aName.AssignLiteral("Direct3D 11"); return;
|
|
default: NS_RUNTIMEABORT("Invalid backend");
|
|
}
|
|
}
|
|
|
|
bool
|
|
ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
|
gfx::Rect& aViewport,
|
|
float& aScaleX,
|
|
float& aScaleY,
|
|
bool aDrawingCritical)
|
|
{
|
|
aScaleX = aScaleY = 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.mScrollOffset) * paintScale;
|
|
|
|
return AndroidBridge::Bridge()->ProgressiveUpdateCallback(
|
|
aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
|
|
aViewport, aScaleX, aScaleY);
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
ClientLayer::~ClientLayer()
|
|
{
|
|
if (HasShadow()) {
|
|
PLayerChild::Send__delete__(GetShadow());
|
|
}
|
|
MOZ_COUNT_DTOR(ClientLayer);
|
|
}
|
|
|
|
}
|
|
}
|