Bug 1727398 - Remove ClientLayerManager. r=aosmond

Differential Revision: https://phabricator.services.mozilla.com/D123525
This commit is contained in:
Jeff Muizelaar 2021-08-24 19:44:27 +00:00
Родитель aac357d350
Коммит 8c1b1dcb3d
23 изменённых файлов: 1 добавлений и 5002 удалений

Просмотреть файл

@ -6,7 +6,6 @@
#include "CanvasClient.h"
#include "ClientCanvasLayer.h" // for ClientCanvasLayer
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
#include "gfxPlatform.h" // for gfxPlatform
#include "mozilla/gfx/BaseSize.h" // for BaseSize

Просмотреть файл

@ -1,41 +0,0 @@
/* -*- 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 "ClientCanvasLayer.h"
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "nsCOMPtr.h" // for already_AddRefed
#include "mozilla/ProfilerLabels.h"
namespace mozilla {
namespace layers {
ClientCanvasLayer::~ClientCanvasLayer() { MOZ_COUNT_DTOR(ClientCanvasLayer); }
void ClientCanvasLayer::RenderLayer() {
AUTO_PROFILER_LABEL("ClientCanvasLayer::RenderLayer", GRAPHICS);
RenderMaskLayers(this);
ClientCanvasRenderer* canvasRenderer =
mCanvasRenderer->AsClientCanvasRenderer();
MOZ_ASSERT(canvasRenderer);
canvasRenderer->UpdateCompositableClient();
ClientManager()->Hold(this);
}
RefPtr<CanvasRenderer> ClientCanvasLayer::CreateCanvasRendererInternal() {
return new ClientCanvasRenderer(this);
}
already_AddRefed<CanvasLayer> ClientLayerManager::CreateCanvasLayer() {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
RefPtr<ClientCanvasLayer> layer = new ClientCanvasLayer(this);
CREATE_SHADOW(Canvas);
return layer.forget();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,79 +0,0 @@
/* -*- 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/. */
#ifndef GFX_CLIENTCANVASLAYER_H
#define GFX_CLIENTCANVASLAYER_H
#include "ClientCanvasRenderer.h"
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "Layers.h" // for CanvasLayer, etc
#include "mozilla/Attributes.h" // for override
#include "mozilla/layers/CanvasClient.h" // for CanvasClient, etc
#include "mozilla/layers/LayersMessages.h" // for CanvasLayerAttributes, etc
#include "mozilla/mozalloc.h" // for operator delete
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
namespace mozilla {
namespace layers {
class CompositableClient;
class ShadowableLayer;
class ClientCanvasLayer : public CanvasLayer, public ClientLayer {
public:
explicit ClientCanvasLayer(ClientLayerManager* aLayerManager)
: CanvasLayer(aLayerManager, static_cast<ClientLayer*>(this)) {
MOZ_COUNT_CTOR(ClientCanvasLayer);
}
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override;
protected:
virtual ~ClientCanvasLayer();
public:
void SetVisibleRegion(const LayerIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
CanvasLayer::SetVisibleRegion(aRegion);
}
void RenderLayer() override;
void ClearCachedResources() override {
mCanvasRenderer->ClearCachedResources();
}
void HandleMemoryPressure() override {
mCanvasRenderer->ClearCachedResources();
}
void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override {
aAttrs = CanvasLayerAttributes(mSamplingFilter, mBounds);
}
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
void Disconnect() override { mCanvasRenderer->DisconnectClient(); }
CompositableClient* GetCompositableClient() override {
ClientCanvasRenderer* canvasRenderer =
mCanvasRenderer->AsClientCanvasRenderer();
MOZ_ASSERT(canvasRenderer);
return canvasRenderer->GetCanvasClient();
}
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -1,37 +0,0 @@
/* -*- 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 "ClientCanvasRenderer.h"
#include "ClientCanvasLayer.h"
namespace mozilla {
namespace layers {
CompositableForwarder* ClientCanvasRenderer::GetForwarder() {
return mLayer->ClientManager()->AsShadowForwarder();
}
bool ClientCanvasRenderer::CreateCompositable() {
if (!mCanvasClient) {
auto compositableFlags = TextureFlags::NO_FLAGS;
if (!mData.mIsAlphaPremult) {
// WR needs this flag marked on the compositable, not just the texture.
compositableFlags |= TextureFlags::NON_PREMULTIPLIED;
}
mCanvasClient = new CanvasClient(GetForwarder(), compositableFlags);
if (mLayer->HasShadow()) {
mCanvasClient->Connect();
GetForwarder()->AsLayerForwarder()->Attach(mCanvasClient, mLayer);
}
}
return true;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,61 +0,0 @@
/* -*- 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" // for ClientLayerManager, etc
#include "Layers.h" // for ColorLayer, etc
#include "mozilla/layers/LayersMessages.h" // for ColorLayerAttributes, etc
#include "mozilla/mozalloc.h" // for operator new
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
#include "nsRegion.h" // for nsIntRegion
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
class ClientColorLayer : public ColorLayer, public ClientLayer {
public:
explicit ClientColorLayer(ClientLayerManager* aLayerManager)
: ColorLayer(aLayerManager, static_cast<ClientLayer*>(this)) {
MOZ_COUNT_CTOR(ClientColorLayer);
}
protected:
MOZ_COUNTED_DTOR_OVERRIDE(ClientColorLayer)
public:
void SetVisibleRegion(const LayerIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
ColorLayer::SetVisibleRegion(aRegion);
}
void RenderLayer() override { RenderMaskLayers(this); }
void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override {
aAttrs = ColorLayerAttributes(GetColor(), GetBounds());
}
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
protected:
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
};
already_AddRefed<ColorLayer> ClientLayerManager::CreateColorLayer() {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
RefPtr<ClientColorLayer> layer = new ClientColorLayer(this);
CREATE_SHADOW(Color);
return layer.forget();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,31 +0,0 @@
/* -*- 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 "ClientContainerLayer.h"
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "mozilla/mozalloc.h" // for operator new
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
namespace mozilla {
namespace layers {
already_AddRefed<ContainerLayer> ClientLayerManager::CreateContainerLayer() {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
RefPtr<ClientContainerLayer> layer = new ClientContainerLayer(this);
CREATE_SHADOW(Container);
return layer.forget();
}
already_AddRefed<RefLayer> ClientLayerManager::CreateRefLayer() {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
RefPtr<ClientRefLayer> layer = new ClientRefLayer(this);
CREATE_SHADOW(Ref);
return layer.forget();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,162 +0,0 @@
/* -*- 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/. */
#ifndef GFX_CLIENTCONTAINERLAYER_H
#define GFX_CLIENTCONTAINERLAYER_H
#include <stdint.h> // for uint32_t
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "Layers.h" // for Layer, ContainerLayer, etc
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
#include "nsRegion.h" // for nsIntRegion
#include "nsTArray.h" // for AutoTArray
#include "ReadbackProcessor.h"
#include "ClientPaintedLayer.h"
namespace mozilla {
namespace layers {
class ShadowableLayer;
class ClientContainerLayer : public ContainerLayer, public ClientLayer {
public:
explicit ClientContainerLayer(ClientLayerManager* aManager)
: ContainerLayer(aManager, static_cast<ClientLayer*>(this)) {
MOZ_COUNT_CTOR(ClientContainerLayer);
mSupportsComponentAlphaChildren = true;
}
protected:
virtual ~ClientContainerLayer() {
ContainerLayer::RemoveAllChildren();
MOZ_COUNT_DTOR(ClientContainerLayer);
}
public:
void RenderLayer() override {
RenderMaskLayers(this);
DefaultComputeSupportsComponentAlphaChildren();
ReadbackProcessor readback;
readback.BuildUpdates(this);
nsTArray<Layer*> children = CollectChildren();
for (uint32_t i = 0; i < children.Length(); i++) {
Layer* child = children.ElementAt(i);
ToClientLayer(child)->RenderLayerWithReadback(&readback);
if (!ClientManager()->GetRepeatTransaction() &&
!child->GetInvalidRegion().IsEmpty()) {
child->Mutated();
}
}
}
void SetVisibleRegion(const LayerIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
ContainerLayer::SetVisibleRegion(aRegion);
}
bool InsertAfter(Layer* aChild, Layer* aAfter) override {
if (!ClientManager()->InConstruction()) {
NS_ERROR("Can only set properties in construction phase");
return false;
}
if (!ContainerLayer::InsertAfter(aChild, aAfter)) {
return false;
}
ClientManager()->AsShadowForwarder()->InsertAfter(
ClientManager()->Hold(this), ClientManager()->Hold(aChild),
aAfter ? ClientManager()->Hold(aAfter) : nullptr);
return true;
}
bool RemoveChild(Layer* aChild) override {
if (!ClientManager()->InConstruction()) {
NS_ERROR("Can only set properties in construction phase");
return false;
}
// hold on to aChild before we remove it!
ShadowableLayer* heldChild = ClientManager()->Hold(aChild);
if (!ContainerLayer::RemoveChild(aChild)) {
return false;
}
ClientManager()->AsShadowForwarder()->RemoveChild(
ClientManager()->Hold(this), heldChild);
return true;
}
bool RepositionChild(Layer* aChild, Layer* aAfter) override {
if (!ClientManager()->InConstruction()) {
NS_ERROR("Can only set properties in construction phase");
return false;
}
if (!ContainerLayer::RepositionChild(aChild, aAfter)) {
return false;
}
ClientManager()->AsShadowForwarder()->RepositionChild(
ClientManager()->Hold(this), ClientManager()->Hold(aChild),
aAfter ? ClientManager()->Hold(aAfter) : nullptr);
return true;
}
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
void ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) override {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
void ForceIntermediateSurface() { mUseIntermediateSurface = true; }
void SetSupportsComponentAlphaChildren(bool aSupports) {
mSupportsComponentAlphaChildren = aSupports;
}
protected:
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
};
class ClientRefLayer : public RefLayer, public ClientLayer {
public:
explicit ClientRefLayer(ClientLayerManager* aManager)
: RefLayer(aManager, static_cast<ClientLayer*>(this)) {
MOZ_COUNT_CTOR(ClientRefLayer);
}
protected:
MOZ_COUNTED_DTOR_OVERRIDE(ClientRefLayer)
public:
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
void RenderLayer() override { RenderMaskLayers(this); }
void ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) override {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
private:
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -1,152 +0,0 @@
/* -*- 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" // for ClientLayerManager, etc
#include "ImageContainer.h" // for AutoLockImage, etc
#include "ImageLayers.h" // for ImageLayer
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/ImageClient.h" // for ImageClient, etc
#include "mozilla/layers/LayersMessages.h" // for ImageLayerAttributes, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
#include "nsRegion.h" // for nsIntRegion
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
class ClientImageLayer : public ImageLayer, public ClientLayer {
public:
explicit ClientImageLayer(ClientLayerManager* aLayerManager)
: ImageLayer(aLayerManager, static_cast<ClientLayer*>(this)),
mImageClientTypeContainer(CompositableType::UNKNOWN) {
MOZ_COUNT_CTOR(ClientImageLayer);
}
protected:
virtual ~ClientImageLayer() {
DestroyBackBuffer();
MOZ_COUNT_DTOR(ClientImageLayer);
}
void SetContainer(ImageContainer* aContainer) override {
ImageLayer::SetContainer(aContainer);
mImageClientTypeContainer = CompositableType::UNKNOWN;
}
void SetVisibleRegion(const LayerIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
ImageLayer::SetVisibleRegion(aRegion);
}
void RenderLayer() override;
void ClearCachedResources() override { DestroyBackBuffer(); }
bool SupportsAsyncUpdate() override {
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
return true;
}
return false;
}
void HandleMemoryPressure() override {
if (mImageClient) {
mImageClient->HandleMemoryPressure();
}
}
void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override {
aAttrs = ImageLayerAttributes(mSamplingFilter, mScaleToSize, mScaleMode);
}
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
void Disconnect() override { DestroyBackBuffer(); }
void DestroyBackBuffer() {
if (mImageClient) {
mImageClient->SetLayer(nullptr);
mImageClient->OnDetach();
mImageClient = nullptr;
}
}
CompositableClient* GetCompositableClient() override { return mImageClient; }
protected:
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
CompositableType GetImageClientType() {
if (mImageClientTypeContainer != CompositableType::UNKNOWN) {
return mImageClientTypeContainer;
}
if (mContainer->IsAsync()) {
mImageClientTypeContainer = CompositableType::IMAGE_BRIDGE;
return mImageClientTypeContainer;
}
AutoLockImage autoLock(mContainer);
mImageClientTypeContainer = autoLock.HasImage() ? CompositableType::IMAGE
: CompositableType::UNKNOWN;
return mImageClientTypeContainer;
}
RefPtr<ImageClient> mImageClient;
CompositableType mImageClientTypeContainer;
};
void ClientImageLayer::RenderLayer() {
RenderMaskLayers(this);
if (!mContainer) {
return;
}
if (!mImageClient ||
!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
CompositableType type = GetImageClientType();
if (type == CompositableType::UNKNOWN) {
return;
}
TextureFlags flags = TextureFlags::DEFAULT;
mImageClient = ImageClient::CreateImageClient(
type, ClientManager()->AsShadowForwarder(), flags);
if (!mImageClient) {
return;
}
mImageClient->SetLayer(this);
if (HasShadow() && !mContainer->IsAsync()) {
mImageClient->Connect();
ClientManager()->AsShadowForwarder()->Attach(mImageClient, this);
}
if (!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
return;
}
}
ClientManager()->Hold(this);
}
already_AddRefed<ImageLayer> ClientLayerManager::CreateImageLayer() {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
RefPtr<ClientImageLayer> layer = new ClientImageLayer(this);
CREATE_SHADOW(Image);
return layer.forget();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,860 +0,0 @@
/* -*- 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 "gfxEnv.h" // for gfxEnv
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Hal.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/StaticPrefs_apz.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/dom/BrowserChild.h" // for BrowserChild
#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 "mozilla/layers/TransactionIdAllocator.h"
#include "mozilla/PerfStats.h"
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
#include "nsAString.h"
#include "nsDisplayList.h"
#include "nsIWidgetListener.h"
#include "nsLayoutUtils.h"
#include "nsTArray.h" // for AutoTArray
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "TiledLayerBuffer.h"
#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;
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
: mPhase(PHASE_NONE),
mWidget(aWidget),
mPaintedLayerCallback(nullptr),
mPaintedLayerCallbackData(nullptr),
mLatestTransactionId{0},
mLastPaintTime(TimeDuration::Forever()),
mTargetRotation(ROTATION_0),
mRepeatTransaction(false),
mIsRepeatTransaction(false),
mTransactionIncomplete(false),
mCompositorMightResample(false),
mNeedsComposite(false),
mQueuedAsyncPaints(false),
mNotifyingWidgetListener(false),
mPaintSequenceNumber(0),
mForwarder(new ShadowLayerForwarder(this)) {
MOZ_COUNT_CTOR(ClientLayerManager);
mMemoryPressureObserver = MemoryPressureObserver::Create(this);
}
ClientLayerManager::~ClientLayerManager() {
mMemoryPressureObserver->Unregister();
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);
}
bool ClientLayerManager::Initialize(
PCompositorBridgeChild* aCBChild, bool aShouldAccelerate,
TextureFactoryIdentifier* aTextureFactoryIdentifier) {
MOZ_ASSERT(mForwarder);
MOZ_ASSERT(aTextureFactoryIdentifier);
nsTArray<LayersBackend> backendHints;
gfxPlatform::GetPlatform()->GetCompositorBackends(aShouldAccelerate,
backendHints);
if (backendHints.IsEmpty()) {
gfxCriticalNote << "Failed to get backend hints.";
return false;
}
PLayerTransactionChild* shadowManager =
aCBChild->SendPLayerTransactionConstructor(backendHints, LayersId{0});
TextureFactoryIdentifier textureFactoryIdentifier;
shadowManager->SendGetTextureFactoryIdentifier(&textureFactoryIdentifier);
if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE) {
gfxCriticalNote << "Failed to create an OMT compositor.";
return false;
}
mForwarder->SetShadowManager(shadowManager);
UpdateTextureFactoryIdentifier(textureFactoryIdentifier);
*aTextureFactoryIdentifier = textureFactoryIdentifier;
return true;
}
void ClientLayerManager::Destroy() {
MOZ_DIAGNOSTIC_ASSERT(!mNotifyingWidgetListener,
"Try to avoid destroying widgets and layer managers "
"during DidCompositeWindow, if you can");
// 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;
RefPtr<Runnable> task = NS_NewRunnableFunction(
"TransactionIdAllocator::NotifyTransactionCompleted",
[allocator, pending = std::move(mPendingTransactions)]() -> void {
for (auto& id : pending) {
allocator->NotifyTransactionCompleted(id);
}
});
NS_DispatchToMainThread(task.forget());
}
// Forget the widget pointer in case we outlive our owning widget.
mWidget = 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,
const nsCString& aURL) {
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();
mURL = aURL;
#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.
hal::ScreenOrientation orientation;
if (dom::BrowserChild* window = mWidget->GetOwningBrowserChild()) {
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->GetOwningBrowserChild()) {
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 (StaticPrefs::apz_test_logging_enabled()) {
mApzTestData.StartNewPaint(mPaintSequenceNumber);
}
}
return true;
}
bool ClientLayerManager::BeginTransaction(const nsCString& aURL) {
return BeginTransactionWithTarget(nullptr, aURL);
}
bool ClientLayerManager::EndTransactionInternal(
DrawPaintedLayerCallback aCallback, void* aCallbackData,
EndTransactionFlags) {
// This just causes the compositor to check whether the GPU is done with its
// textures or not and unlock them if it is. This helps us avoid the case
// where we take a long time painting asynchronously, turn IPC back on at
// the end of that, and then have to wait for the compositor to to get into
// TiledLayerBufferComposite::UseTiles before getting a response.
if (mForwarder) {
mForwarder->UpdateTextureLocks();
}
AUTO_PROFILER_TRACING_MARKER("Paint", "Rasterize", GRAPHICS);
PerfStats::AutoMetricRecording<PerfStats::Metric::Rasterizing> autoRecording;
Maybe<TimeStamp> startTime;
if (StaticPrefs::layers_acceleration_draw_fps()) {
startTime = Some(TimeStamp::Now());
}
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.
auto scrollIdsUpdated = 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 (StaticPrefs::gfx_content_always_paint() && XRE_IsContentProcess()) {
TimeStamp start = TimeStamp::Now();
root->RenderLayer();
mLastPaintTime = TimeStamp::Now() - start;
} else {
root->RenderLayer();
}
} else {
gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer().";
}
// Once we're sure we're not going to fall back to a full paint,
// notify the scroll frames which had pending updates.
if (!mTransactionIncomplete) {
for (ScrollableLayerGuid::ViewID scrollId : scrollIdsUpdated) {
nsLayoutUtils::NotifyPaintSkipTransaction(scrollId);
}
}
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 (startTime) {
PaintTiming& pt = mForwarder->GetPaintTiming();
pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
}
return !mTransactionIncomplete;
}
void ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags) {
if (!mForwarder->IPCOpen()) {
mInTransaction = false;
return;
}
if (mWidget) {
mWidget->PrepareWindowEffects();
}
EndTransactionInternal(aCallback, aCallbackData, aFlags);
if (XRE_IsContentProcess()) {
RegisterPayload({CompositionPayloadType::eContentPaint, TimeStamp::Now()});
}
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(mURL)) {
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.
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::ScheduleComposite() {
mForwarder->ScheduleComposite();
}
void ClientLayerManager::DidComposite(TransactionId aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd) {
if (!mWidget) {
return;
}
// 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) {
mNotifyingWidgetListener = true;
listener->DidCompositeWindow(aTransactionId, aCompositeStart,
aCompositeEnd);
mNotifyingWidgetListener = false;
}
// DidCompositeWindow might have called Destroy on us and nulled out
// mWidget, see bug 1510058. Re-check it here.
if (mWidget) {
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();
}
mPendingTransactions.RemoveElement(aTransactionId);
}
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 (StaticPrefs::apz_test_logging_enabled()) {
mApzTestData.StartNewRepaintRequest(aSequenceNumber);
}
}
void ClientLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) {
if (HasShadowManager()) {
mForwarder->GetShadowManager()->SendGetFrameUniformity(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() ||
StaticPrefs::layers_force_synchronous_resize()) {
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_MARKER("Paint", "ForwardTransaction", GRAPHICS);
TimeStamp start = TimeStamp::Now();
GetCompositorBridgeChild()->EndCanvasTransaction();
// 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 (syncObject) {
syncObject->Synchronize();
}
mPhase = PHASE_FORWARD;
mLatestTransactionId =
mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction);
TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
if (!refreshStart) {
refreshStart = mTransactionStart;
}
if (StaticPrefs::gfx_content_always_paint() && 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,
mTransactionIdAllocator->GetVsyncId(),
mTransactionIdAllocator->GetVsyncStart(), refreshStart, mTransactionStart,
mContainsSVG, mURL, &sent, mPayload);
if (ok) {
if (sent) {
// Our payload has now been dispatched.
mPayload.Clear();
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);
mLatestTransactionId = mLatestTransactionId.Prev();
} else {
mPendingTransactions.AppendElement(mLatestTransactionId);
}
mPhase = PHASE_NONE;
// this may result in Layers being deleted, which results in
// PLayer::Send__delete__() and DeallocShmem()
mKeepAlive.Clear();
BrowserChild* window = mWidget ? mWidget->GetOwningBrowserChild() : 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 &&
(mForwarder->GetCompositorBackendType() !=
LayersBackend::LAYERS_NONE &&
mForwarder->GetCompositorBackendType() !=
LayersBackend::LAYERS_BASIC);
}
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::OnMemoryPressure(MemoryPressureReason aWhy) {
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::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) {
mForwarder->SetLayersObserverEpoch(aEpoch);
}
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()) {
RefPtr<PersistentBufferProvider> provider =
PersistentBufferProviderShared::Create(aSize, aFormat,
AsShadowForwarder());
if (provider) {
return provider.forget();
}
}
return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
}
ClientLayer::~ClientLayer() { MOZ_COUNT_DTOR(ClientLayer); }
ClientLayer* ClientLayer::ToClientLayer(Layer* aLayer) {
return static_cast<ClientLayer*>(aLayer->ImplData());
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,202 +0,0 @@
/* -*- 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 "ClientPaintedLayer.h"
#include "ClientTiledPaintedLayer.h" // for ClientTiledPaintedLayer
#include <stdint.h> // for uint32_t
#include "client/ClientLayerManager.h" // for ClientLayerManager, etc
#include "gfxContext.h" // for gfxContext
#include "gfx2DGlue.h"
#include "gfxEnv.h" // for gfxEnv
#include "gfxRect.h" // for gfxRect
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/gfx/Matrix.h" // for Matrix
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
#include "mozilla/gfx/Types.h" // for Float, etc
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProfilerLabels.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
#include "nsRect.h" // for mozilla::gfx::IntRect
#include "ReadbackProcessor.h"
#include "RotatedBuffer.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
bool ClientPaintedLayer::EnsureContentClient() {
if (!mContentClient) {
mContentClient = ContentClient::CreateContentClient(
ClientManager()->AsShadowForwarder());
if (!mContentClient) {
return false;
}
mContentClient->Connect();
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
MOZ_ASSERT(mContentClient->GetForwarder());
}
return true;
}
void ClientPaintedLayer::UpdateContentClient(PaintState& aState) {
Mutated();
AddToValidRegion(aState.mRegionToDraw);
ContentClientRemoteBuffer* contentClientRemote =
static_cast<ContentClientRemoteBuffer*>(mContentClient.get());
MOZ_ASSERT(contentClientRemote->GetIPCHandle());
// Hold(this) ensures this layer is kept alive through the current transaction
// The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
// so deleting this Hold for whatever reason will break things.
ClientManager()->Hold(this);
contentClientRemote->Updated(aState.mRegionToDraw,
mVisibleRegion.ToUnknownRegion());
}
bool ClientPaintedLayer::UpdatePaintRegion(PaintState& aState) {
SubtractFromValidRegion(aState.mRegionToInvalidate);
if (!aState.mRegionToDraw.IsEmpty() &&
!ClientManager()->GetPaintedLayerCallback()) {
ClientManager()->SetTransactionIncomplete();
return false;
}
// The area that became invalid and is visible needs to be repainted
// (this could be the whole visible area if our buffer switched
// from RGB to RGBA, because we might need to repaint with
// subpixel AA)
aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
GetLocalVisibleRegion().ToUnknownRegion());
return true;
}
void ClientPaintedLayer::FinishPaintState(PaintState& aState) {
}
uint32_t ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback) {
uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
if (ClientManager()->CompositorMightResample()) {
flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
if (MayResample()) {
flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
}
#endif
return flags;
}
void ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor* aReadback) {
AUTO_PROFILER_LABEL("ClientPaintedLayer::RenderLayerWithReadback", GRAPHICS);
NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase");
RenderMaskLayers(this);
if (!EnsureContentClient()) {
return;
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
nsIntRegion readbackRegion;
if (aReadback && UsedForReadback()) {
aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
}
uint32_t flags = GetPaintFlags(aReadback);
PaintState state = mContentClient->BeginPaint(this, flags);
if (!UpdatePaintRegion(state)) {
mContentClient->EndPaint(state, nullptr);
FinishPaintState(state);
return;
}
bool didUpdate = false;
RotatedBuffer::DrawIterator iter;
while (DrawTarget* target =
mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
SetAntialiasingFlags(this, target);
RefPtr<gfxContext> ctx =
gfxContext::CreatePreservingTransformOrNull(target);
MOZ_ASSERT(ctx); // already checked the target above
if (!gfxEnv::SkipRasterization()) {
if (!target->IsCaptureDT()) {
target->ClearRect(Rect());
if (target->IsValid()) {
ClientManager()->GetPaintedLayerCallback()(
this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());
}
} else {
ClientManager()->GetPaintedLayerCallback()(
this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());
}
}
ctx = nullptr;
mContentClient->ReturnDrawTarget(target);
didUpdate = true;
}
mContentClient->EndPaint(state, &readbackUpdates);
FinishPaintState(state);
if (didUpdate) {
UpdateContentClient(state);
}
}
already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayer() {
return CreatePaintedLayerWithHint(NONE);
}
already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayerWithHint(
PaintedLayerCreationHint aHint) {
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
if (gfxPlatform::GetPlatform()->UsesTiling()) {
RefPtr<ClientTiledPaintedLayer> layer =
new ClientTiledPaintedLayer(this, aHint);
CREATE_SHADOW(Painted);
return layer.forget();
} else {
RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
CREATE_SHADOW(Painted);
return layer.forget();
}
}
void ClientPaintedLayer::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
PaintedLayer::PrintInfo(aStream, aPrefix);
if (mContentClient) {
aStream << "\n";
nsAutoCString pfx(aPrefix);
pfx += " ";
mContentClient->PrintInfo(aStream, pfx.get());
}
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,123 +0,0 @@
/* -*- 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/. */
#ifndef GFX_CLIENTPAINTEDLAYER_H
#define GFX_CLIENTPAINTEDLAYER_H
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "Layers.h" // for PaintedLayer, etc
#include "RotatedBuffer.h" // for RotatedBuffer, etc
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/layers/ContentClient.h" // for ContentClient
#include "mozilla/mozalloc.h" // for operator delete
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h" // for nsIntRegion
#include "mozilla/layers/PLayerTransaction.h" // for PaintedLayerAttributes
namespace mozilla {
namespace gfx {
class DrawEventRecorderMemory;
class DrawTargetCapture;
}; // namespace gfx
namespace layers {
class CompositableClient;
class ShadowableLayer;
class SpecificLayerAttributes;
class ClientPaintedLayer : public PaintedLayer, public ClientLayer {
public:
typedef ContentClient::PaintState PaintState;
typedef ContentClient::ContentType ContentType;
explicit ClientPaintedLayer(
ClientLayerManager* aLayerManager,
LayerManager::PaintedLayerCreationHint aCreationHint = LayerManager::NONE)
: PaintedLayer(aLayerManager, static_cast<ClientLayer*>(this),
aCreationHint),
mContentClient(nullptr) {
MOZ_COUNT_CTOR(ClientPaintedLayer);
}
protected:
virtual ~ClientPaintedLayer() {
if (mContentClient) {
mContentClient->OnDetach();
mContentClient = nullptr;
}
MOZ_COUNT_DTOR(ClientPaintedLayer);
}
public:
void SetVisibleRegion(const LayerIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
PaintedLayer::SetVisibleRegion(aRegion);
}
void InvalidateRegion(const nsIntRegion& aRegion) override {
NS_ASSERTION(ClientManager()->InConstruction(),
"Can only set properties in construction phase");
mInvalidRegion.Add(aRegion);
UpdateValidRegionAfterInvalidRegionChanged();
}
void RenderLayer() override { RenderLayerWithReadback(nullptr); }
void RenderLayerWithReadback(ReadbackProcessor* aReadback) override;
void ClearCachedResources() override {
if (mContentClient) {
mContentClient->Clear();
}
ClearValidRegion();
DestroyBackBuffer();
}
void HandleMemoryPressure() override {
if (mContentClient) {
mContentClient->HandleMemoryPressure();
}
}
void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override {
aAttrs = PaintedLayerAttributes(GetValidRegion());
}
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
CompositableClient* GetCompositableClient() override {
return mContentClient;
}
void Disconnect() override { mContentClient = nullptr; }
protected:
void RecordThebes();
bool HasMaskLayers();
bool EnsureContentClient();
uint32_t GetPaintFlags(ReadbackProcessor* aReadback);
void UpdateContentClient(PaintState& aState);
bool UpdatePaintRegion(PaintState& aState);
void FinishPaintState(PaintState& aState);
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
void DestroyBackBuffer() { mContentClient = nullptr; }
RefPtr<ContentClient> mContentClient;
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -1,648 +0,0 @@
/* -*- 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 "ClientTiledPaintedLayer.h"
#include "FrameMetrics.h" // for FrameMetrics
#include "Units.h" // for ScreenIntRect, CSSPoint, etc
#include "UnitTransforms.h" // for TransformTo
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxRect.h" // for gfxRect
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Rect.h" // for Rect, RectTyped
#include "mozilla/layers/APZUtils.h" // for ShouldUseProgressivePaint
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
#include "mozilla/layers/LayersMessages.h"
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "mozilla/layers/MultiTiledContentClient.h"
#include "mozilla/layers/SingleTiledContentClient.h"
namespace mozilla {
namespace layers {
using gfx::IntRect;
using gfx::IntSize;
using gfx::Rect;
ClientTiledPaintedLayer::ClientTiledPaintedLayer(
ClientLayerManager* const aManager,
ClientLayerManager::PaintedLayerCreationHint aCreationHint)
: PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint),
mContentClient(),
mHaveSingleTiledContentClient(false) {
MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
mPaintData.mFirstPaint = true;
}
ClientTiledPaintedLayer::~ClientTiledPaintedLayer() {
MOZ_COUNT_DTOR(ClientTiledPaintedLayer);
}
void ClientTiledPaintedLayer::ClearCachedResources() {
if (mContentClient) {
mContentClient->ClearCachedResources();
}
ClearValidRegion();
mContentClient = nullptr;
}
void ClientTiledPaintedLayer::FillSpecificAttributes(
SpecificLayerAttributes& aAttrs) {
aAttrs = PaintedLayerAttributes(GetValidRegion());
}
static Maybe<LayerRect> ApplyParentLayerToLayerTransform(
const ParentLayerToLayerMatrix4x4& aTransform,
const ParentLayerRect& aParentLayerRect, const LayerRect& aClip) {
return UntransformBy(aTransform, aParentLayerRect, aClip);
}
static LayerToParentLayerMatrix4x4 GetTransformToAncestorsParentLayer(
Layer* aStart, const LayerMetricsWrapper& aAncestor) {
// If the ancestor layer Combines3DTransformWithAncestors, then the
// scroll offset is contained in the transform of the layer at the
// root of the 3D context. So we must first find that layer, then
// calcuate the transform to its parent.
LayerMetricsWrapper root3dAncestor = aAncestor;
while (root3dAncestor.Combines3DTransformWithAncestors()) {
root3dAncestor = root3dAncestor.GetParent();
}
gfx::Matrix4x4 transform;
const LayerMetricsWrapper& ancestorParent = root3dAncestor.GetParent();
for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
ancestorParent ? iter != ancestorParent : iter.IsValid();
iter = iter.GetParent()) {
transform = transform * iter.GetTransform();
}
return ViewAs<LayerToParentLayerMatrix4x4>(transform);
}
void ClientTiledPaintedLayer::GetAncestorLayers(
LayerMetricsWrapper* aOutScrollAncestor,
LayerMetricsWrapper* aOutDisplayPortAncestor,
bool* aOutHasTransformAnimation) {
LayerMetricsWrapper scrollAncestor;
LayerMetricsWrapper displayPortAncestor;
bool hasTransformAnimation = false;
for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM);
ancestor; ancestor = ancestor.GetParent()) {
hasTransformAnimation |= ancestor.HasTransformAnimation();
const FrameMetrics& metrics = ancestor.Metrics();
if (!scrollAncestor &&
metrics.GetScrollId() != ScrollableLayerGuid::NULL_SCROLL_ID) {
scrollAncestor = ancestor;
}
if (!metrics.GetDisplayPort().IsEmpty()) {
displayPortAncestor = ancestor;
// Any layer that has a displayport must be scrollable, so we can break
// here.
break;
}
}
if (aOutScrollAncestor) {
*aOutScrollAncestor = scrollAncestor;
}
if (aOutDisplayPortAncestor) {
*aOutDisplayPortAncestor = displayPortAncestor;
}
if (aOutHasTransformAnimation) {
*aOutHasTransformAnimation = hasTransformAnimation;
}
}
void ClientTiledPaintedLayer::BeginPaint() {
mPaintData.ResetPaintData();
if (!GetBaseTransform().Is2D()) {
// Give up if there is a complex CSS transform on the layer. We might
// eventually support these but for now it's too complicated to handle
// given that it's a pretty rare scenario.
return;
}
// Get the metrics of the nearest scrollable layer and the nearest layer
// with a displayport.
LayerMetricsWrapper scrollAncestor;
LayerMetricsWrapper displayPortAncestor;
bool hasTransformAnimation;
GetAncestorLayers(&scrollAncestor, &displayPortAncestor,
&hasTransformAnimation);
if (!displayPortAncestor || !scrollAncestor) {
// No displayport or scroll ancestor, so we can't do progressive rendering.
#if defined(MOZ_WIDGET_ANDROID)
// Android are guaranteed to have a displayport set, so this
// should never happen.
NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
#endif
return;
}
TILING_LOG(
"TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform "
"%d\n",
this, scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(),
hasTransformAnimation);
const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
// Calculate the transform required to convert ParentLayer space of our
// display port ancestor to the Layer space of this layer.
ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
LayerRect layerBounds(GetVisibleRegion().GetBounds());
// Compute the critical display port that applies to this layer in the
// LayoutDevice space of this layer, but only if there is no OMT animation
// on this layer. If there is an OMT animation then we need to draw the whole
// visible region of this layer as determined by layout, because we don't know
// what parts of it might move into view in the compositor.
mPaintData.mHasTransformAnimation = hasTransformAnimation;
if (!mPaintData.mHasTransformAnimation &&
mContentClient->GetLowPrecisionTiledBuffer()) {
ParentLayerRect criticalDisplayPort =
(displayportMetrics.GetCriticalDisplayPort() *
displayportMetrics.GetZoom()) +
displayportMetrics.GetCompositionBounds().TopLeft();
Maybe<LayerRect> criticalDisplayPortTransformed =
ApplyParentLayerToLayerTransform(transformDisplayPortToLayer,
criticalDisplayPort, layerBounds);
if (criticalDisplayPortTransformed) {
mPaintData.mCriticalDisplayPort =
Some(RoundedToInt(*criticalDisplayPortTransformed));
} else {
mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
}
}
TILING_LOG("TILING %p: Critical displayport %s\n", this,
mPaintData.mCriticalDisplayPort
? ToString(*mPaintData.mCriticalDisplayPort).c_str()
: "not set");
// Store the resolution from the displayport ancestor layer. Because this is
// Gecko-side, before any async transforms have occurred, we can use the zoom
// for this.
mPaintData.mResolution = displayportMetrics.GetZoom();
TILING_LOG("TILING %p: Resolution %s\n", this,
ToString(mPaintData.mResolution).c_str());
// Store the applicable composition bounds in this layer's Layer units.
mPaintData.mTransformToCompBounds =
GetTransformToAncestorsParentLayer(this, scrollAncestor);
ParentLayerToLayerMatrix4x4 transformToBounds =
mPaintData.mTransformToCompBounds.Inverse();
Maybe<LayerRect> compositionBoundsTransformed =
ApplyParentLayerToLayerTransform(
transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
if (compositionBoundsTransformed) {
mPaintData.mCompositionBounds = *compositionBoundsTransformed;
} else {
mPaintData.mCompositionBounds.SetEmpty();
}
TILING_LOG("TILING %p: Composition bounds %s\n", this,
ToString(mPaintData.mCompositionBounds).c_str());
// Calculate the scroll offset since the last transaction
mPaintData.mScrollOffset =
displayportMetrics.GetLayoutScrollOffset() * displayportMetrics.GetZoom();
TILING_LOG("TILING %p: Scroll offset %s\n", this,
ToString(mPaintData.mScrollOffset).c_str());
}
bool ClientTiledPaintedLayer::IsScrollingOnCompositor(
const FrameMetrics& aParentMetrics) {
CompositorBridgeChild* compositor = nullptr;
if (!compositor) {
return false;
}
FrameMetrics compositorMetrics;
if (!compositor->LookupCompositorFrameMetrics(aParentMetrics.GetScrollId(),
compositorMetrics)) {
return false;
}
// 1 is a tad high for a fuzzy equals epsilon however if our scroll delta
// is so small then we have nothing to gain from using paint heuristics.
float COORDINATE_EPSILON = 1.f;
return !FuzzyEqualsAdditive(compositorMetrics.GetVisualScrollOffset().x,
aParentMetrics.GetVisualScrollOffset().x,
COORDINATE_EPSILON) ||
!FuzzyEqualsAdditive(compositorMetrics.GetVisualScrollOffset().y,
aParentMetrics.GetVisualScrollOffset().y,
COORDINATE_EPSILON);
}
bool ClientTiledPaintedLayer::UseProgressiveDraw() {
if (!apz::ShouldUseProgressivePaint()) {
// pref is disabled or platform does not support progressive, so never do
// progressive
return false;
}
if (!mContentClient->GetTiledBuffer()->SupportsProgressiveUpdate()) {
return false;
}
if (ClientManager()->HasShadowTarget()) {
// This condition is true when we are in a reftest scenario. We don't want
// to draw progressively here because it can cause intermittent reftest
// failures because the harness won't wait for all the tiles to be drawn.
return false;
}
if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
// This layer is fixed-position and so even if it does have a scrolling
// ancestor it will likely be entirely on-screen all the time, so we
// should draw it all at once
return false;
}
if (mPaintData.mHasTransformAnimation) {
// The compositor is going to animate this somehow, so we want it all
// on the screen at once.
return false;
}
if (ClientManager()->AsyncPanZoomEnabled()) {
LayerMetricsWrapper scrollAncestor;
GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
if (!scrollAncestor) {
return false;
}
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
if (!IsScrollingOnCompositor(parentMetrics)) {
return false;
}
}
return true;
}
bool ClientTiledPaintedLayer::RenderHighPrecision(
const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
// If we have started drawing low-precision already, then we
// shouldn't do anything there.
if (mPaintData.mLowPrecisionPaintCount != 0) {
return false;
}
// Only draw progressively when there is something to paint and the
// resolution is unchanged
if (!aInvalidRegion.IsEmpty() && UseProgressiveDraw() &&
mContentClient->GetTiledBuffer()->GetFrameResolution() ==
mPaintData.mResolution) {
// Store the old valid region, then clear it before painting.
// We clip the old valid region to the visible region, as it only gets
// used to decide stale content (currently valid and previously visible)
nsIntRegion oldValidRegion =
mContentClient->GetTiledBuffer()->GetValidRegion();
oldValidRegion.And(oldValidRegion, aVisibleRegion);
if (mPaintData.mCriticalDisplayPort) {
oldValidRegion.And(oldValidRegion,
mPaintData.mCriticalDisplayPort->ToUnknownRect());
}
TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this,
ToString(oldValidRegion).c_str());
nsIntRegion drawnRegion;
bool updatedBuffer = mContentClient->GetTiledBuffer()->ProgressiveUpdate(
GetValidRegion(), aInvalidRegion, oldValidRegion, drawnRegion,
&mPaintData, aCallback, aCallbackData);
AddToValidRegion(drawnRegion);
return updatedBuffer;
}
// Otherwise do a non-progressive paint. We must do this even when
// the region to paint is empty as the valid region may have shrunk.
nsIntRegion validRegion = aVisibleRegion;
if (mPaintData.mCriticalDisplayPort) {
validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
}
SetValidRegion(validRegion);
TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this,
ToString(aInvalidRegion).c_str());
TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this,
ToString(GetValidRegion()).c_str());
TilePaintFlags flags = TilePaintFlags::None;
mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
mContentClient->GetTiledBuffer()->PaintThebes(
GetValidRegion(), aInvalidRegion, aInvalidRegion, aCallback,
aCallbackData, flags);
mPaintData.mPaintFinished = true;
return true;
}
bool ClientTiledPaintedLayer::RenderLowPrecision(
const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
nsIntRegion invalidRegion = aInvalidRegion;
// Render the low precision buffer, if the visible region is larger than the
// critical display port.
if (!mPaintData.mCriticalDisplayPort ||
!nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect())
.Contains(aVisibleRegion)) {
nsIntRegion oldValidRegion =
mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
oldValidRegion.And(oldValidRegion, aVisibleRegion);
bool updatedBuffer = false;
// If the frame resolution or format have changed, invalidate the buffer
if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() !=
mPaintData.mResolution ||
mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
if (!mLowPrecisionValidRegion.IsEmpty()) {
updatedBuffer = true;
}
oldValidRegion.SetEmpty();
mLowPrecisionValidRegion.SetEmpty();
mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(
mPaintData.mResolution);
invalidRegion = aVisibleRegion;
}
// Invalidate previously valid content that is no longer visible
if (mPaintData.mLowPrecisionPaintCount == 1) {
mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
}
mPaintData.mLowPrecisionPaintCount++;
// Remove the valid high-precision region from the invalid low-precision
// region. We don't want to spend time drawing things twice.
invalidRegion.SubOut(GetValidRegion());
TILING_LOG(
"TILING %p: Progressive paint: low-precision invalid region is %s\n",
this, ToString(invalidRegion).c_str());
TILING_LOG(
"TILING %p: Progressive paint: low-precision old valid region is %s\n",
this, ToString(oldValidRegion).c_str());
if (!invalidRegion.IsEmpty()) {
nsIntRegion drawnRegion;
updatedBuffer =
mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
mLowPrecisionValidRegion, invalidRegion, oldValidRegion,
drawnRegion, &mPaintData, aCallback, aCallbackData);
mLowPrecisionValidRegion.OrWith(drawnRegion);
}
TILING_LOG(
"TILING %p: Progressive paint: low-precision new valid region is %s\n",
this, ToString(mLowPrecisionValidRegion).c_str());
return updatedBuffer;
}
if (!mLowPrecisionValidRegion.IsEmpty()) {
TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
// Clear the low precision tiled buffer.
mLowPrecisionValidRegion.SetEmpty();
mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
// Return true here so we send a Painted callback after clearing the valid
// region of the low precision buffer. This allows the shadow buffer's valid
// region to be updated and the associated resources to be freed.
return true;
}
return false;
}
void ClientTiledPaintedLayer::EndPaint() {
mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
mPaintData.mPaintFinished = true;
mPaintData.mFirstPaint = false;
TILING_LOG("TILING %p: Paint finished\n", this);
}
void ClientTiledPaintedLayer::RenderLayer() {
if (!ClientManager()->IsRepeatTransaction()) {
// Only paint the mask layers on the first transaction.
RenderMaskLayers(this);
}
LayerManager::DrawPaintedLayerCallback callback =
ClientManager()->GetPaintedLayerCallback();
void* data = ClientManager()->GetPaintedLayerCallbackData();
IntSize layerSize = mVisibleRegion.GetBounds().ToUnknownRect().Size();
IntSize tileSize = gfx::gfxVars::TileSize();
bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
layerSize.height <= tileSize.height / 2;
// Use single tile when layer is not scrollable, is smaller than one
// tile, or when more than half of the tiles' pixels in either
// dimension would be wasted.
bool wantSingleTiledContentClient =
(mCreationHint == LayerManager::NONE || layerSize <= tileSize ||
isHalfTileWidthOrHeight) &&
SingleTiledContentClient::ClientSupportsLayerSize(layerSize,
ClientManager()) &&
StaticPrefs::layers_single_tile_enabled();
if (mContentClient && mHaveSingleTiledContentClient &&
!wantSingleTiledContentClient) {
mContentClient = nullptr;
ClearValidRegion();
}
if (!mContentClient) {
if (wantSingleTiledContentClient) {
mContentClient = new SingleTiledContentClient(*this, ClientManager());
mHaveSingleTiledContentClient = true;
} else {
mContentClient = new MultiTiledContentClient(*this, ClientManager());
mHaveSingleTiledContentClient = false;
}
mContentClient->Connect();
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
MOZ_ASSERT(mContentClient->GetForwarder());
}
if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
ClearValidRegion();
mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
}
TILING_LOG("TILING %p: Initial visible region %s\n", this,
ToString(mVisibleRegion).c_str());
TILING_LOG("TILING %p: Initial valid region %s\n", this,
ToString(GetValidRegion()).c_str());
TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this,
ToString(mLowPrecisionValidRegion).c_str());
nsIntRegion neededRegion = mVisibleRegion.ToUnknownRegion();
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
// This is handled by PadDrawTargetOutFromRegion in TiledContentClient for
// mobile
if (MayResample()) {
// If we're resampling then bilinear filtering can read up to 1 pixel
// outside of our texture coords. Make the visible region a single rect,
// and pad it out by 1 pixel (restricted to tile boundaries) so that
// we always have valid content or transparent pixels to sample from.
IntRect bounds = neededRegion.GetBounds();
IntRect wholeTiles = bounds;
wholeTiles.InflateToMultiple(gfx::gfxVars::TileSize());
IntRect padded = bounds;
padded.Inflate(1);
padded.IntersectRect(padded, wholeTiles);
neededRegion = padded;
}
#endif
nsIntRegion invalidRegion;
invalidRegion.Sub(neededRegion, GetValidRegion());
if (invalidRegion.IsEmpty()) {
EndPaint();
return;
}
if (!callback) {
ClientManager()->SetTransactionIncomplete();
return;
}
if (!ClientManager()->IsRepeatTransaction()) {
// For more complex cases we need to calculate a bunch of metrics before we
// can do the paint.
BeginPaint();
if (mPaintData.mPaintFinished) {
return;
}
// Make sure that tiles that fall outside of the visible region or outside
// of the critical displayport are discarded on the first update. Also make
// sure that we only draw stuff inside the critical displayport on the first
// update.
nsIntRegion validRegion;
validRegion.And(GetValidRegion(), neededRegion);
if (mPaintData.mCriticalDisplayPort) {
validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
invalidRegion.And(invalidRegion,
mPaintData.mCriticalDisplayPort->ToUnknownRect());
}
SetValidRegion(validRegion);
TILING_LOG("TILING %p: First-transaction valid region %s\n", this,
ToString(validRegion).c_str());
TILING_LOG("TILING %p: First-transaction invalid region %s\n", this,
ToString(invalidRegion).c_str());
} else {
if (mPaintData.mCriticalDisplayPort) {
invalidRegion.And(invalidRegion,
mPaintData.mCriticalDisplayPort->ToUnknownRect());
}
TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this,
ToString(invalidRegion).c_str());
}
nsIntRegion lowPrecisionInvalidRegion;
if (mContentClient->GetLowPrecisionTiledBuffer()) {
// Calculate the invalid region for the low precision buffer. Make sure
// to remove the valid high-precision area so we don't double-paint it.
lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, GetValidRegion());
}
TILING_LOG("TILING %p: Low-precision invalid region %s\n", this,
ToString(lowPrecisionInvalidRegion).c_str());
bool updatedHighPrecision =
RenderHighPrecision(invalidRegion, neededRegion, callback, data);
if (updatedHighPrecision) {
ClientManager()->Hold(this);
mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
if (!mPaintData.mPaintFinished) {
// There is still more high-res stuff to paint, so we're not
// done yet. A subsequent transaction will take care of this.
ClientManager()->SetRepeatTransaction();
return;
}
}
// If there is nothing to draw in low-precision, then we're done.
if (lowPrecisionInvalidRegion.IsEmpty()) {
EndPaint();
return;
}
if (updatedHighPrecision) {
// If there are low precision updates, but we just did some high-precision
// updates, then mark the paint as unfinished and request a repeat
// transaction. This is so that we don't perform low-precision updates in
// the same transaction as high-precision updates.
TILING_LOG(
"TILING %p: Scheduling repeat transaction for low-precision painting\n",
this);
ClientManager()->SetRepeatTransaction();
mPaintData.mLowPrecisionPaintCount = 1;
mPaintData.mPaintFinished = false;
return;
}
bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
neededRegion, callback, data);
if (updatedLowPrecision) {
ClientManager()->Hold(this);
mContentClient->UpdatedBuffer(
TiledContentClient::LOW_PRECISION_TILED_BUFFER);
if (!mPaintData.mPaintFinished) {
// There is still more low-res stuff to paint, so we're not
// done yet. A subsequent transaction will take care of this.
ClientManager()->SetRepeatTransaction();
return;
}
}
// If we get here, we've done all the high- and low-precision
// paints we wanted to do, so we can finish the paint and chill.
EndPaint();
}
bool ClientTiledPaintedLayer::IsOptimizedFor(
LayerManager::PaintedLayerCreationHint aHint) {
// The only creation hint is whether the layer is scrollable or not, and this
// is only respected on OSX, where it's used to determine whether to
// use a tiled content client or not.
// There are pretty nasty performance consequences for not using tiles on
// large, scrollable layers, so we want the layer to be recreated in this
// situation.
return aHint == GetCreationHint();
}
void ClientTiledPaintedLayer::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
PaintedLayer::PrintInfo(aStream, aPrefix);
if (mContentClient) {
aStream << "\n";
nsAutoCString pfx(aPrefix);
pfx += " ";
mContentClient->PrintInfo(aStream, pfx.get());
}
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,150 +0,0 @@
/* -*- 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/. */
#ifndef GFX_CLIENTTILEDPAINTEDLAYER_H
#define GFX_CLIENTTILEDPAINTEDLAYER_H
#include "ClientLayerManager.h" // for ClientLayer, etc
#include "Layers.h" // for PaintedLayer, etc
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/layers/TiledContentClient.h"
#include "nsRegion.h" // for nsIntRegion
namespace mozilla {
namespace layers {
class ShadowableLayer;
class SpecificLayerAttributes;
/**
* An implementation of PaintedLayer that ONLY supports remote
* composition that is backed by tiles. This painted layer implementation
* is better suited to mobile hardware to work around slow implementation
* of glTexImage2D (for OGL compositors), and restrait memory bandwidth.
*
* Tiled PaintedLayers use a different protocol compared with other
* layers. A copy of the tiled buffer is made and sent to the compositing
* thread via the layers protocol. Tiles are uploaded by the buffers
* asynchonously without using IPC, that means they are not safe for cross-
* process use (bug 747811). Each tile has a TextureHost/Client pair but
* they communicate directly rather than using the Texture protocol.
*
* There is no ContentClient for tiled layers. There is a ContentHost, however.
*/
class ClientTiledPaintedLayer : public PaintedLayer, public ClientLayer {
typedef PaintedLayer Base;
public:
explicit ClientTiledPaintedLayer(ClientLayerManager* const aManager,
ClientLayerManager::PaintedLayerCreationHint
aCreationHint = LayerManager::NONE);
protected:
virtual ~ClientTiledPaintedLayer();
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
public:
// Override name to distinguish it from ClientPaintedLayer in layer dumps
const char* Name() const override { return "TiledPaintedLayer"; }
// PaintedLayer
Layer* AsLayer() override { return this; }
void InvalidateRegion(const nsIntRegion& aRegion) override {
mInvalidRegion.Add(aRegion);
UpdateValidRegionAfterInvalidRegionChanged();
if (!mLowPrecisionValidRegion.IsEmpty()) {
// Also update mLowPrecisionValidRegion. Unfortunately we call
// mInvalidRegion.GetRegion() here, which is expensive.
mLowPrecisionValidRegion.SubOut(mInvalidRegion.GetRegion());
}
}
// Shadow methods
void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override;
ShadowableLayer* AsShadowableLayer() override { return this; }
void RenderLayer() override;
void ClearCachedResources() override;
void HandleMemoryPressure() override {
if (mContentClient) {
mContentClient->HandleMemoryPressure();
}
}
/**
* Helper method to find the nearest ancestor layers which
* scroll and have a displayport. The parameters are out-params
* which hold the return values; the values passed in may be null.
*/
void GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
LayerMetricsWrapper* aOutDisplayPortAncestor,
bool* aOutHasTransformAnimation);
bool IsOptimizedFor(
LayerManager::PaintedLayerCreationHint aCreationHint) override;
private:
ClientLayerManager* ClientManager() {
return static_cast<ClientLayerManager*>(mManager);
}
/**
* For the initial PaintThebes of a transaction, calculates all the data
* needed for that paint and any repeated transactions.
*/
void BeginPaint();
/**
* Check if the layer is being scrolled by APZ on the compositor.
*/
bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics);
/**
* Check if we should use progressive draw on this layer. We will
* disable progressive draw based on a preference or if the layer
* is not being scrolled.
*/
bool UseProgressiveDraw();
/**
* Helper function to do the high-precision paint.
* This function returns true if it updated the paint buffer.
*/
bool RenderHighPrecision(const nsIntRegion& aInvalidRegion,
const nsIntRegion& aVisibleRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
/**
* Helper function to do the low-precision paint.
* This function returns true if it updated the paint buffer.
*/
bool RenderLowPrecision(const nsIntRegion& aInvalidRegion,
const nsIntRegion& aVisibleRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
/**
* This causes the paint to be marked as finished, and updates any data
* necessary to persist until the next paint.
*/
void EndPaint();
RefPtr<TiledContentClient> mContentClient;
// Flag to indicate if mContentClient is a SingleTiledContentClient. This is
// only valid when mContentClient is non-null.
bool mHaveSingleTiledContentClient;
nsIntRegion mLowPrecisionValidRegion;
BasicTiledLayerPaintData mPaintData;
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -1,657 +0,0 @@
/* -*- 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 "mozilla/layers/MultiTiledContentClient.h"
#include "ClientTiledPaintedLayer.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/layers/APZUtils.h"
#include "mozilla/layers/LayerMetricsWrapper.h"
namespace mozilla {
using namespace gfx;
namespace layers {
MultiTiledContentClient::MultiTiledContentClient(
ClientTiledPaintedLayer& aPaintedLayer, ClientLayerManager* aManager)
: TiledContentClient(aManager, "Multi"),
mTiledBuffer(aPaintedLayer, *this, aManager, &mSharedFrameMetricsHelper),
mLowPrecisionTiledBuffer(aPaintedLayer, *this, aManager,
&mSharedFrameMetricsHelper) {
MOZ_COUNT_CTOR(MultiTiledContentClient);
mLowPrecisionTiledBuffer.SetResolution(
StaticPrefs::layers_low_precision_resolution());
mHasLowPrecision = StaticPrefs::layers_low_precision_buffer();
}
void MultiTiledContentClient::ClearCachedResources() {
CompositableClient::ClearCachedResources();
mTiledBuffer.DiscardBuffers();
mLowPrecisionTiledBuffer.DiscardBuffers();
}
void MultiTiledContentClient::UpdatedBuffer(TiledBufferType aType) {
ClientMultiTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
? &mLowPrecisionTiledBuffer
: &mTiledBuffer;
MOZ_ASSERT(aType != LOW_PRECISION_TILED_BUFFER || mHasLowPrecision);
mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
}
ClientMultiTiledLayerBuffer::ClientMultiTiledLayerBuffer(
ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient, ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper)
: ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient),
mManager(aManager),
mCallback(nullptr),
mCallbackData(nullptr),
mSharedFrameMetricsHelper(aHelper) {}
void ClientMultiTiledLayerBuffer::DiscardBuffers() {
for (TileClient& tile : mRetainedTiles) {
tile.DiscardBuffers();
}
}
SurfaceDescriptorTiles
ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() {
nsTArray<TileDescriptor> tiles;
for (TileClient& tile : mRetainedTiles) {
TileDescriptor tileDesc = tile.GetTileDescriptor();
tiles.AppendElement(tileDesc);
// Reset the update rect
tile.mUpdateRect = IntRect();
}
return SurfaceDescriptorTiles(
mValidRegion, tiles, mTileOrigin, mTileSize, mTiles.mFirst.x,
mTiles.mFirst.y, mTiles.mSize.width, mTiles.mSize.height, mResolution,
mFrameResolution.xScale, mFrameResolution.yScale,
mWasLastPaintProgressive);
}
void ClientMultiTiledLayerBuffer::PaintThebes(
const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData,
TilePaintFlags aFlags) {
TILING_LOG("TILING %p: PaintThebes painting region %s\n", &mPaintedLayer,
ToString(aPaintRegion).c_str());
TILING_LOG("TILING %p: PaintThebes new valid region %s\n", &mPaintedLayer,
ToString(aNewValidRegion).c_str());
mCallback = aCallback;
mCallbackData = aCallbackData;
mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
long start = PR_IntervalNow();
#endif
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 30) {
const IntRect bounds = aPaintRegion.GetBounds();
printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start,
bounds.x, bounds.y, bounds.width, bounds.height);
if (aPaintRegion.IsComplex()) {
printf_stderr("Complex region\n");
for (auto iter = aPaintRegion.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
printf_stderr(" rect %i, %i, %i, %i\n", rect.x, rect.y, rect.width,
rect.height);
}
}
}
start = PR_IntervalNow();
#endif
AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::PaintThebes", GRAPHICS);
mNewValidRegion = aNewValidRegion;
Update(aNewValidRegion, aPaintRegion, aDirtyRegion, aFlags);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 10) {
const IntRect bounds = aPaintRegion.GetBounds();
printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start,
bounds.x, bounds.y, bounds.width, bounds.height);
}
#endif
mLastPaintContentType = GetContentType(&mLastPaintSurfaceMode);
mCallback = nullptr;
mCallbackData = nullptr;
}
void ClientMultiTiledLayerBuffer::MaybeSyncTextures(
const nsIntRegion& aPaintRegion, const TilesPlacement& aNewTiles,
const IntSize& aScaledTileSize) {
if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) {
AutoTArray<uint64_t, 10> syncTextureSerials;
SurfaceMode mode;
Unused << GetContentType(&mode);
// Pre-pass through the tiles (mirroring the filter logic below) to gather
// texture IDs that we need to ensure are unused by the GPU before we
// continue.
if (!aPaintRegion.IsEmpty()) {
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
const TileCoordIntPoint tileCoord = aNewTiles.TileCoord(i);
IntPoint tileOffset = GetTileOffset(tileCoord);
nsIntRegion tileDrawRegion = IntRect(tileOffset, aScaledTileSize);
tileDrawRegion.AndWith(aPaintRegion);
if (tileDrawRegion.IsEmpty()) {
continue;
}
TileClient& tile = mRetainedTiles[i];
tile.GetSyncTextureSerials(mode, syncTextureSerials);
}
}
if (syncTextureSerials.Length() > 0) {
mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials);
}
}
}
void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
TilePaintFlags aFlags) {
const IntSize scaledTileSize = GetScaledTileSize();
const gfx::IntRect newBounds = newValidRegion.GetBounds();
const TilesPlacement oldTiles = mTiles;
const TilesPlacement newTiles(
floor_div(newBounds.X(), scaledTileSize.width),
floor_div(newBounds.Y(), scaledTileSize.height),
floor_div(
GetTileStart(newBounds.X(), scaledTileSize.width) + newBounds.Width(),
scaledTileSize.width) +
1,
floor_div(GetTileStart(newBounds.Y(), scaledTileSize.height) +
newBounds.Height(),
scaledTileSize.height) +
1);
const size_t oldTileCount = mRetainedTiles.Length();
const size_t newTileCount = newTiles.mSize.width * newTiles.mSize.height;
nsTArray<TileClient> oldRetainedTiles = std::move(mRetainedTiles);
mRetainedTiles.SetLength(newTileCount);
for (size_t oldIndex = 0; oldIndex < oldTileCount; oldIndex++) {
const TileCoordIntPoint tileCoord = oldTiles.TileCoord(oldIndex);
const size_t newIndex = newTiles.TileIndex(tileCoord);
// First, get the already existing tiles to the right place in the new
// array. Leave placeholders (default constructor) where there was no tile.
if (newTiles.HasTile(tileCoord)) {
mRetainedTiles[newIndex] = oldRetainedTiles[oldIndex];
} else {
// release tiles that we are not going to reuse before allocating new ones
// to avoid allocating unnecessarily.
oldRetainedTiles[oldIndex].DiscardBuffers();
}
}
oldRetainedTiles.Clear();
nsIntRegion paintRegion = aPaintRegion;
nsIntRegion dirtyRegion = aDirtyRegion;
MaybeSyncTextures(paintRegion, newTiles, scaledTileSize);
if (!paintRegion.IsEmpty()) {
for (size_t i = 0; i < newTileCount; ++i) {
const TileCoordIntPoint tileCoord = newTiles.TileCoord(i);
IntPoint tileOffset = GetTileOffset(tileCoord);
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
tileDrawRegion.AndWith(paintRegion);
if (tileDrawRegion.IsEmpty()) {
continue;
}
TileClient& tile = mRetainedTiles[i];
if (!ValidateTile(tile, GetTileOffset(tileCoord), tileDrawRegion,
aFlags)) {
gfxCriticalError() << "ValidateTile failed";
}
// Validating the tile may have required more to be painted.
paintRegion.OrWith(tileDrawRegion);
dirtyRegion.OrWith(tileDrawRegion);
}
if (!mPaintTiles.IsEmpty()) {
// Create a tiled draw target
gfx::TileSet tileset;
for (size_t i = 0; i < mPaintTiles.Length(); ++i) {
mPaintTiles[i].mTileOrigin -= mTilingOrigin;
}
tileset.mTiles = mPaintTiles.Elements();
tileset.mTileCount = mPaintTiles.Length();
RefPtr<DrawTarget> drawTarget =
gfx::Factory::CreateTiledDrawTarget(tileset);
if (!drawTarget || !drawTarget->IsValid()) {
gfxDevCrash(LogReason::InvalidContext) << "Invalid tiled draw target";
return;
}
drawTarget->SetTransform(Matrix());
// Draw into the tiled draw target
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
MOZ_ASSERT(ctx); // already checked the draw target above
ctx->SetMatrix(ctx->CurrentMatrix()
.PreScale(mResolution, mResolution)
.PreTranslate(-mTilingOrigin));
mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
ctx = nullptr;
// Edge padding allows us to avoid resampling artifacts
if (StaticPrefs::layers_tiles_edge_padding_AtStartup() &&
mResolution == 1) {
drawTarget->PadEdges(newValidRegion.MovedBy(-mTilingOrigin));
}
// Reset
mPaintTiles.Clear();
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max());
}
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
TileClient& tile = mRetainedTiles[i];
UnlockTile(tile);
}
}
mTiles = newTiles;
mValidRegion = newValidRegion;
}
bool ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
const nsIntPoint& aTileOrigin,
nsIntRegion& aDirtyRegion,
TilePaintFlags aFlags) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (aDirtyRegion.IsComplex()) {
printf_stderr("Complex region\n");
}
#endif
SurfaceMode mode;
gfxContentType content = GetContentType(&mode);
if (!aTile.mAllocator) {
aTile.SetTextureAllocator(
mManager->GetCompositorBridgeChild()->GetTexturePool(
mManager->AsShadowForwarder(),
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD |
TextureFlags::NON_BLOCKING_READ_LOCK));
MOZ_ASSERT(aTile.mAllocator);
}
nsIntRegion tileDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
tileDirtyRegion.ScaleRoundOut(mResolution, mResolution);
nsIntRegion tileVisibleRegion = mNewValidRegion.MovedBy(-aTileOrigin);
tileVisibleRegion.ScaleRoundOut(mResolution, mResolution);
std::vector<RefPtr<TextureClient>> asyncPaintClients;
Maybe<AcquiredBackBuffer> backBuffer =
aTile.AcquireBackBuffer(mCompositableClient, tileDirtyRegion,
tileVisibleRegion, content, mode, aFlags);
if (!backBuffer) {
return false;
}
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
aTile.mInvalidFront.OrWith(tileDirtyRegion);
// Add the backbuffer's invalid region intersected with the visible region to
// the dirty region we will be painting. This will be empty if we are able to
// copy from the front into the back.
nsIntRegion tileInvalidRegion = aTile.mInvalidBack;
tileInvalidRegion.AndWith(tileVisibleRegion);
nsIntRegion invalidRegion = tileInvalidRegion;
invalidRegion.MoveBy(aTileOrigin);
invalidRegion.ScaleInverseRoundOut(mResolution, mResolution);
tileDirtyRegion.OrWith(tileInvalidRegion);
aDirtyRegion.OrWith(invalidRegion);
// Mark the region we will be painting and the region we copied from the front
// buffer as needing to be uploaded to the compositor
aTile.mUpdateRect =
tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect);
// We need to clear the dirty region of the tile before painting
// if we are painting non-opaque content
if (mode != SurfaceMode::SURFACE_OPAQUE) {
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
backBuffer->mTarget->ClearRect(drawRect);
}
}
gfx::Tile paintTile;
paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
paintTile.mDrawTarget = backBuffer->mTarget;
mPaintTiles.AppendElement(paintTile);
MOZ_RELEASE_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
MOZ_RELEASE_ASSERT(backBuffer->mCapture == nullptr);
mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);
// The new buffer is now validated, remove the dirty region from it.
aTile.mInvalidBack.SubOut(tileDirtyRegion);
aTile.Flip();
return true;
}
/**
* This function takes the transform stored in aTransformToCompBounds
* (which was generated in GetTransformToAncestorsParentLayer), and
* modifies it with the ViewTransform from the compositor side so that
* it reflects what the compositor is actually rendering. This operation
* basically adds in the layer's async transform.
* This function then returns the scroll ancestor's composition bounds,
* transformed into the painted layer's LayerPixel coordinates, accounting
* for the compositor state.
*/
static Maybe<LayerRect> GetCompositorSideCompositionBounds(
const LayerMetricsWrapper& aScrollAncestor,
const LayerToParentLayerMatrix4x4& aTransformToCompBounds,
const AsyncTransform& aAPZTransform, const LayerRect& aClip) {
LayerToParentLayerMatrix4x4 transform =
aTransformToCompBounds * AsyncTransformComponentMatrix(aAPZTransform);
return UntransformBy(transform.Inverse(),
aScrollAncestor.Metrics().GetCompositionBounds(), aClip);
}
bool ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion(
const nsIntRegion& aInvalidRegion, const nsIntRegion& aOldValidRegion,
nsIntRegion& aRegionToPaint, BasicTiledLayerPaintData* aPaintData,
bool aIsRepeated) {
aRegionToPaint = aInvalidRegion;
// If the composition bounds rect is empty, we can't make any sensible
// decision about how to update coherently. In this case, just update
// everything in one transaction.
if (aPaintData->mCompositionBounds.IsEmpty()) {
aPaintData->mPaintFinished = true;
return false;
}
// If this is a low precision buffer, we force progressive updates. The
// assumption is that the contents is less important, so visual coherency
// is lower priority than speed.
bool drawingLowPrecision = IsLowPrecision();
// Find out if we have any non-stale content to update.
nsIntRegion staleRegion;
staleRegion.And(aInvalidRegion, aOldValidRegion);
TILING_LOG("TILING %p: Progressive update stale region %s\n", &mPaintedLayer,
ToString(staleRegion).c_str());
LayerMetricsWrapper scrollAncestor;
mPaintedLayer.GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
// Find out the current view transform to determine which tiles to draw
// first, and see if we should just abort this paint. Aborting is usually
// caused by there being an incoming, more relevant paint.
AsyncTransform viewTransform;
MOZ_ASSERT(mSharedFrameMetricsHelper);
bool abortPaint = mSharedFrameMetricsHelper->UpdateFromCompositorFrameMetrics(
scrollAncestor, !staleRegion.Contains(aInvalidRegion),
drawingLowPrecision, viewTransform);
TILING_LOG(
"TILING %p: Progressive update view transform %s zoom %f abort %d\n",
&mPaintedLayer, ToString(viewTransform.mTranslation).c_str(),
viewTransform.mScale.scale, abortPaint);
if (abortPaint) {
// We ignore if front-end wants to abort if this is the first,
// non-low-precision paint, as in that situation, we're about to override
// front-end's page/viewport metrics.
if (!aPaintData->mFirstPaint || drawingLowPrecision) {
AUTO_PROFILER_LABEL(
"ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion",
GRAPHICS);
aRegionToPaint.SetEmpty();
return aIsRepeated;
}
}
Maybe<LayerRect> transformedCompositionBounds =
GetCompositorSideCompositionBounds(
scrollAncestor, aPaintData->mTransformToCompBounds, viewTransform,
LayerRect(mPaintedLayer.GetVisibleRegion().GetBounds()));
if (!transformedCompositionBounds) {
aPaintData->mPaintFinished = true;
return false;
}
TILING_LOG("TILING %p: Progressive update transformed compositor bounds %s\n",
&mPaintedLayer, ToString(*transformedCompositionBounds).c_str());
// Compute a "coherent update rect" that we should paint all at once in a
// single transaction. This is to avoid rendering glitches on animated
// page content, and when layers change size/shape.
// On Fennec uploads are more expensive because we're not using gralloc, so
// we use a coherent update rect that is intersected with the screen at the
// time of issuing the draw command. This will paint faster but also
// potentially make the progressive paint more visible to the user while
// scrolling.
IntRect coherentUpdateRect(RoundedOut(
#ifdef MOZ_WIDGET_ANDROID
transformedCompositionBounds->Intersect(
aPaintData->mCompositionBounds)
#else
*transformedCompositionBounds
#endif
)
.ToUnknownRect());
TILING_LOG("TILING %p: Progressive update final coherency rect %s\n",
&mPaintedLayer, ToString(coherentUpdateRect).c_str());
aRegionToPaint.And(aInvalidRegion, coherentUpdateRect);
aRegionToPaint.Or(aRegionToPaint, staleRegion);
bool drawingStale = !aRegionToPaint.IsEmpty();
if (!drawingStale) {
aRegionToPaint = aInvalidRegion;
}
// Prioritise tiles that are currently visible on the screen.
bool paintingVisible = false;
if (aRegionToPaint.Intersects(coherentUpdateRect)) {
aRegionToPaint.And(aRegionToPaint, coherentUpdateRect);
paintingVisible = true;
}
TILING_LOG("TILING %p: Progressive update final paint region %s\n",
&mPaintedLayer, ToString(aRegionToPaint).c_str());
// Paint area that's visible and overlaps previously valid content to avoid
// visible glitches in animated elements, such as gifs.
bool paintInSingleTransaction =
paintingVisible && (drawingStale || aPaintData->mFirstPaint);
TILING_LOG(
"TILING %p: paintingVisible %d drawingStale %d firstPaint %d "
"singleTransaction %d\n",
&mPaintedLayer, paintingVisible, drawingStale, aPaintData->mFirstPaint,
paintInSingleTransaction);
// The following code decides what order to draw tiles in, based on the
// current scroll direction of the primary scrollable layer.
NS_ASSERTION(!aRegionToPaint.IsEmpty(), "Unexpectedly empty paint region!");
IntRect paintBounds = aRegionToPaint.GetBounds();
int startX, incX, startY, incY;
gfx::IntSize scaledTileSize = GetScaledTileSize();
if (aPaintData->mScrollOffset.x >= aPaintData->mLastScrollOffset.x) {
startX = RoundDownToTileEdge(paintBounds.X(), scaledTileSize.width);
incX = scaledTileSize.width;
} else {
startX = RoundDownToTileEdge(paintBounds.XMost() - 1, scaledTileSize.width);
incX = -scaledTileSize.width;
}
if (aPaintData->mScrollOffset.y >= aPaintData->mLastScrollOffset.y) {
startY = RoundDownToTileEdge(paintBounds.Y(), scaledTileSize.height);
incY = scaledTileSize.height;
} else {
startY =
RoundDownToTileEdge(paintBounds.YMost() - 1, scaledTileSize.height);
incY = -scaledTileSize.height;
}
// Find a tile to draw.
IntRect tileBounds(startX, startY, scaledTileSize.width,
scaledTileSize.height);
int32_t scrollDiffX =
aPaintData->mScrollOffset.x - aPaintData->mLastScrollOffset.x;
int32_t scrollDiffY =
aPaintData->mScrollOffset.y - aPaintData->mLastScrollOffset.y;
// This loop will always terminate, as there is at least one tile area
// along the first/last row/column intersecting with regionToPaint, or its
// bounds would have been smaller.
while (true) {
aRegionToPaint.And(aInvalidRegion, tileBounds);
if (!aRegionToPaint.IsEmpty()) {
if (mResolution != 1) {
// Paint the entire tile for low-res. This is aimed to fixing low-res
// resampling and to avoid doing costly region accurate painting for a
// small area.
aRegionToPaint = tileBounds;
}
break;
}
if (Abs(scrollDiffY) >= Abs(scrollDiffX)) {
tileBounds.MoveByX(incX);
} else {
tileBounds.MoveByY(incY);
}
}
if (!aRegionToPaint.Contains(aInvalidRegion)) {
// The region needed to paint is larger then our progressive chunk size
// therefore update what we want to paint and ask for a new paint
// transaction.
// If we need to draw more than one tile to maintain coherency, make
// sure it happens in the same transaction by requesting this work be
// repeated immediately.
// If this is unnecessary, the remaining work will be done tile-by-tile in
// subsequent transactions. The caller code is responsible for scheduling
// the subsequent transactions as long as we don't set the mPaintFinished
// flag to true.
return (!drawingLowPrecision && paintInSingleTransaction);
}
// We're not repeating painting and we've not requested a repeat transaction,
// so the paint is finished. If there's still a separate low precision
// paint to do, it will get marked as unfinished later.
aPaintData->mPaintFinished = true;
return false;
}
bool ClientMultiTiledLayerBuffer::ProgressiveUpdate(
const nsIntRegion& aValidRegion, const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion, nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
TILING_LOG("TILING %p: Progressive update valid region %s\n", &mPaintedLayer,
ToString(aValidRegion).c_str());
TILING_LOG("TILING %p: Progressive update invalid region %s\n",
&mPaintedLayer, ToString(aInvalidRegion).c_str());
TILING_LOG("TILING %p: Progressive update old valid region %s\n",
&mPaintedLayer, ToString(aOldValidRegion).c_str());
bool repeat = false;
bool isBufferChanged = false;
nsIntRegion remainingInvalidRegion = aInvalidRegion;
nsIntRegion updatedValidRegion = aValidRegion;
do {
// Compute the region that should be updated. Repeat as many times as
// is required.
nsIntRegion regionToPaint;
repeat =
ComputeProgressiveUpdateRegion(remainingInvalidRegion, aOldValidRegion,
regionToPaint, aPaintData, repeat);
TILING_LOG(
"TILING %p: Progressive update computed paint region %s repeat %d\n",
&mPaintedLayer, ToString(regionToPaint).c_str(), repeat);
// There's no further work to be done.
if (regionToPaint.IsEmpty()) {
break;
}
isBufferChanged = true;
// Keep track of what we're about to refresh.
aOutDrawnRegion.OrWith(regionToPaint);
updatedValidRegion.OrWith(regionToPaint);
// aValidRegion may have been altered by InvalidateRegion, but we still
// want to display stale content until it gets progressively updated.
// Create a region that includes stale content.
nsIntRegion validOrStale;
validOrStale.Or(updatedValidRegion, aOldValidRegion);
// Paint the computed region and subtract it from the invalid region.
PaintThebes(validOrStale, regionToPaint, remainingInvalidRegion, aCallback,
aCallbackData, TilePaintFlags::Progressive);
remainingInvalidRegion.SubOut(regionToPaint);
} while (repeat);
TILING_LOG(
"TILING %p: Progressive update final valid region %s buffer changed %d\n",
&mPaintedLayer, ToString(updatedValidRegion).c_str(), isBufferChanged);
TILING_LOG("TILING %p: Progressive update final invalid region %s\n",
&mPaintedLayer, ToString(remainingInvalidRegion).c_str());
// Return false if nothing has been drawn, or give what has been drawn
// to the shadow layer to upload.
return isBufferChanged;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,198 +0,0 @@
/* -*- 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/. */
#ifndef MOZILLA_GFX_MULTITILEDCONTENTCLIENT_H
#define MOZILLA_GFX_MULTITILEDCONTENTCLIENT_H
#include "ClientLayerManager.h" // for ClientLayerManager
#include "nsRegion.h" // for nsIntRegion
#include "mozilla/gfx/2D.h" // for gfx::Tile
#include "mozilla/gfx/Point.h" // for IntPoint
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
#include "mozilla/layers/TiledContentClient.h" // for ClientTiledPaintedLayer
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "TiledLayerBuffer.h" // for TiledLayerBuffer
namespace mozilla {
namespace layers {
class ClientLayerManager;
class ClientMultiTiledLayerBuffer
: public TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>,
public ClientTiledLayerBuffer {
friend class TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>;
public:
ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient,
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper);
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
TilePaintFlags aFlags = TilePaintFlags::None) override;
bool SupportsProgressiveUpdate() override { return true; }
/**
* Performs a progressive update of a given tiled buffer.
* See ComputeProgressiveUpdateRegion below for parameter documentation.
* aOutDrawnRegion is an outparameter that contains the region that was
* drawn, and which can now be added to the layer's valid region.
*/
bool ProgressiveUpdate(const nsIntRegion& aValidRegion,
const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData) override;
void ResetPaintedAndValidState() override {
mValidRegion.SetEmpty();
mTiles.mSize.width = 0;
mTiles.mSize.height = 0;
DiscardBuffers();
mRetainedTiles.Clear();
}
const nsIntRegion& GetValidRegion() override {
return TiledLayerBuffer::GetValidRegion();
}
bool IsLowPrecision() const override {
return TiledLayerBuffer::IsLowPrecision();
}
void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml,
TextureDumpMode aCompress) override {
TiledLayerBuffer::Dump(aStream, aPrefix, aDumpHtml, aCompress);
}
void ReadLock();
void Release();
void DiscardBuffers();
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
void SetResolution(float aResolution) {
if (mResolution == aResolution) {
return;
}
Update(nsIntRegion(), nsIntRegion(), nsIntRegion(), TilePaintFlags::None);
mResolution = aResolution;
}
protected:
bool ValidateTile(TileClient& aTile, const nsIntPoint& aTileRect,
nsIntRegion& aDirtyRegion, TilePaintFlags aFlags);
void Update(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion,
TilePaintFlags aFlags);
TileClient GetPlaceholderTile() const { return TileClient(); }
private:
RefPtr<ClientLayerManager> mManager;
LayerManager::DrawPaintedLayerCallback mCallback;
void* mCallbackData;
// The region that will be made valid during Update(). Once Update() is
// completed then this is identical to mValidRegion.
nsIntRegion mNewValidRegion;
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
// Parameters that are collected during Update for a paint before they
// are either executed or replayed on the paint thread.
AutoTArray<gfx::Tile, 4> mPaintTiles;
/**
* While we're adding tiles, this is used to keep track of the position of
* the top-left of the top-left-most tile. When we come to wrap the tiles in
* TiledDrawTarget we subtract the value of this member from each tile's
* offset so that all the tiles have a positive offset, then add a
* translation to the TiledDrawTarget to compensate. This is important so
* that the mRect of the TiledDrawTarget is always at a positive x/y
* position, otherwise its GetSize() methods will be broken.
*/
gfx::IntPoint mTilingOrigin;
/**
* Calculates the region to update in a single progressive update transaction.
* This employs some heuristics to update the most 'sensible' region to
* update at this point in time, and how large an update should be performed
* at once to maintain visual coherency.
*
* aInvalidRegion is the current invalid region.
* aOldValidRegion is the valid region of mTiledBuffer at the beginning of the
* current transaction.
* aRegionToPaint will be filled with the region to update. This may be empty,
* which indicates that there is no more work to do.
* aIsRepeated should be true if this function has already been called during
* this transaction.
*
* Returns true if it should be called again, false otherwise. In the case
* that aRegionToPaint is empty, this will return aIsRepeated for convenience.
*/
bool ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
nsIntRegion& aRegionToPaint,
BasicTiledLayerPaintData* aPaintData,
bool aIsRepeated);
void MaybeSyncTextures(const nsIntRegion& aPaintRegion,
const TilesPlacement& aNewTiles,
const gfx::IntSize& aScaledTileSize);
};
/**
* An implementation of TiledContentClient that supports
* multiple tiles and a low precision buffer.
*/
class MultiTiledContentClient : public TiledContentClient {
public:
MultiTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
ClientLayerManager* aManager);
protected:
~MultiTiledContentClient() {
MOZ_COUNT_DTOR(MultiTiledContentClient);
mTiledBuffer.DiscardBuffers();
mLowPrecisionTiledBuffer.DiscardBuffers();
}
public:
void ClearCachedResources() override;
void UpdatedBuffer(TiledBufferType aType) override;
ClientTiledLayerBuffer* GetTiledBuffer() override { return &mTiledBuffer; }
ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override {
if (mHasLowPrecision) {
return &mLowPrecisionTiledBuffer;
}
return nullptr;
}
private:
SharedFrameMetricsHelper mSharedFrameMetricsHelper;
ClientMultiTiledLayerBuffer mTiledBuffer;
ClientMultiTiledLayerBuffer mLowPrecisionTiledBuffer;
bool mHasLowPrecision;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_MULTITILEDCONTENTCLIENT_H

Просмотреть файл

@ -1,243 +0,0 @@
/* -*- 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 "mozilla/layers/SingleTiledContentClient.h"
#include "ClientTiledPaintedLayer.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "TiledLayerBuffer.h"
namespace mozilla {
namespace layers {
SingleTiledContentClient::SingleTiledContentClient(
ClientTiledPaintedLayer& aPaintedLayer, ClientLayerManager* aManager)
: TiledContentClient(aManager, "Single") {
MOZ_COUNT_CTOR(SingleTiledContentClient);
mTiledBuffer =
new ClientSingleTiledLayerBuffer(aPaintedLayer, *this, aManager);
}
void SingleTiledContentClient::ClearCachedResources() {
CompositableClient::ClearCachedResources();
mTiledBuffer->DiscardBuffers();
}
void SingleTiledContentClient::UpdatedBuffer(TiledBufferType aType) {
mForwarder->UseTiledLayerBuffer(this,
mTiledBuffer->GetSurfaceDescriptorTiles());
}
/* static */
bool SingleTiledContentClient::ClientSupportsLayerSize(
const gfx::IntSize& aSize, ClientLayerManager* aManager) {
int32_t maxTextureSize = aManager->GetMaxTextureSize();
return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize;
}
ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(
ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient, ClientLayerManager* aManager)
: ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient),
mManager(aManager),
mWasLastPaintProgressive(false),
mFormat(gfx::SurfaceFormat::UNKNOWN) {}
void ClientSingleTiledLayerBuffer::ReleaseTiles() {
if (!mTile.IsPlaceholderTile()) {
mTile.DiscardBuffers();
}
mTile.SetTextureAllocator(nullptr);
}
void ClientSingleTiledLayerBuffer::DiscardBuffers() {
if (!mTile.IsPlaceholderTile()) {
mTile.DiscardFrontBuffer();
mTile.DiscardBackBuffer();
}
}
SurfaceDescriptorTiles
ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles() {
nsTArray<TileDescriptor> tiles;
TileDescriptor tileDesc = mTile.GetTileDescriptor();
tiles.AppendElement(tileDesc);
mTile.mUpdateRect = gfx::IntRect();
return SurfaceDescriptorTiles(mValidRegion, tiles, mTilingOrigin, mSize, 0, 0,
1, 1, 1.0, mFrameResolution.xScale,
mFrameResolution.yScale,
mWasLastPaintProgressive);
}
already_AddRefed<TextureClient>
ClientSingleTiledLayerBuffer::GetTextureClient() {
MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN);
return mCompositableClient.CreateTextureClientForDrawing(
gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content,
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD |
TextureFlags::NON_BLOCKING_READ_LOCK);
}
void ClientSingleTiledLayerBuffer::PaintThebes(
const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData,
TilePaintFlags aFlags) {
mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive);
bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
// Compare layer valid region size to current backbuffer size, discard if not
// matching.
gfx::IntSize size = aNewValidRegion.GetBounds().Size();
gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
nsIntRegion paintRegion = aPaintRegion;
RefPtr<TextureClient> discardedFrontBuffer = nullptr;
RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr;
nsIntRegion discardedValidRegion;
if (mSize != size || mTilingOrigin != origin) {
discardedFrontBuffer = mTile.mFrontBuffer;
discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite;
discardedValidRegion = mValidRegion;
TILING_LOG(
"TILING %p: Single-tile valid region changed. Discarding buffers.\n",
&mPaintedLayer);
ResetPaintedAndValidState();
mSize = size;
mTilingOrigin = origin;
paintRegion = aNewValidRegion;
}
SurfaceMode mode;
gfxContentType content = GetContentType(&mode);
mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content);
if (mTile.IsPlaceholderTile()) {
mTile.SetTextureAllocator(this);
}
if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) {
AutoTArray<uint64_t, 2> syncTextureSerials;
mTile.GetSyncTextureSerials(mode, syncTextureSerials);
if (syncTextureSerials.Length() > 0) {
mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials);
}
}
// The dirty region relative to the top-left of the tile.
nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin);
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
Maybe<AcquiredBackBuffer> backBuffer =
mTile.AcquireBackBuffer(mCompositableClient, tileDirtyRegion,
tileVisibleRegion, content, mode, aFlags);
if (!backBuffer) {
return;
}
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
mTile.mInvalidFront.OrWith(tileDirtyRegion);
// Add backbuffer's invalid region to the dirty region to be painted.
// This will be empty if we were able to copy from the front in to the back.
nsIntRegion tileInvalidRegion = mTile.mInvalidBack;
tileInvalidRegion.AndWith(tileVisibleRegion);
paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin));
tileDirtyRegion.OrWith(tileInvalidRegion);
// Mark the region we will be painting and the region we copied from the front
// buffer as needing to be uploaded to the compositor
mTile.mUpdateRect =
tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect);
// If the old frontbuffer was discarded then attempt to copy what we
// can from it to the new backbuffer.
if (discardedFrontBuffer) {
nsIntRegion copyableRegion;
copyableRegion.And(aNewValidRegion, discardedValidRegion);
copyableRegion.SubOut(aDirtyRegion);
OpenMode readMode =
asyncPaint ? OpenMode::OPEN_READ_ASYNC : OpenMode::OPEN_READ;
DualTextureClientAutoLock discardedBuffer(
discardedFrontBuffer, discardedFrontBufferOnWhite, readMode);
if (discardedBuffer.Succeeded()) {
RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot();
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect src =
iter.Get() - discardedValidRegion.GetBounds().TopLeft();
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
backBuffer->mTarget->CopySurface(discardedSurface, src, dest);
}
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n",
&mPaintedLayer, ToString(copyableRegion).c_str());
// We don't need to repaint valid content that was just copied.
paintRegion.SubOut(copyableRegion);
copyableRegion.MoveBy(-mTilingOrigin);
tileDirtyRegion.SubOut(copyableRegion);
} else {
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front "
"buffer's draw target";
}
}
if (mode != SurfaceMode::SURFACE_OPAQUE) {
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
backBuffer->mTarget->ClearRect(drawRect);
}
}
// Paint into the target
{
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget);
if (!ctx) {
gfxDevCrash(gfx::LogReason::InvalidContext)
<< "SingleTiledContextClient context problem "
<< gfx::hexa(backBuffer->mTarget);
return;
}
ctx->SetMatrix(
ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion,
DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
}
MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
MOZ_ASSERT(!backBuffer->mCapture);
// The new buffer is now validated, remove the dirty region from it.
mTile.mInvalidBack.SubOut(tileDirtyRegion);
backBuffer = Nothing();
mTile.Flip();
UnlockTile(mTile);
mValidRegion = aNewValidRegion;
mLastPaintSurfaceMode = mode;
mLastPaintContentType = content;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,128 +0,0 @@
/* -*- 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/. */
#ifndef MOZILLA_GFX_SINGLETILEDCONTENTCLIENT_H
#define MOZILLA_GFX_SINGLETILEDCONTENTCLIENT_H
#include "TiledContentClient.h"
namespace mozilla {
namespace layers {
class ClientTiledPaintedLayer;
class ClientLayerManager;
/**
* Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
* This buffer provides an implementation of ValidateTile using a
* thebes callback and can support painting using a single paint buffer.
* Whether a single paint buffer is used is controlled by
* StaticPrefs::PerTileDrawing().
*/
class ClientSingleTiledLayerBuffer : public ClientTiledLayerBuffer,
public TextureClientAllocator {
virtual ~ClientSingleTiledLayerBuffer() = default;
public:
ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient,
ClientLayerManager* aManager);
// TextureClientAllocator
already_AddRefed<TextureClient> GetTextureClient() override;
void ReturnTextureClientDeferred(TextureClient* aClient) override {}
void ReportClientLost() override {}
// ClientTiledLayerBuffer
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
TilePaintFlags aFlags = TilePaintFlags::None) override;
bool SupportsProgressiveUpdate() override { return false; }
bool ProgressiveUpdate(const nsIntRegion& aValidRegion,
const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData) override {
MOZ_ASSERT(false, "ProgressiveUpdate not supported!");
return false;
}
void ResetPaintedAndValidState() override {
mValidRegion.SetEmpty();
mTile.DiscardBuffers();
}
const nsIntRegion& GetValidRegion() override { return mValidRegion; }
bool IsLowPrecision() const override { return false; }
void ReleaseTiles();
void DiscardBuffers();
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
private:
TileClient mTile;
RefPtr<ClientLayerManager> mManager;
nsIntRegion mValidRegion;
bool mWasLastPaintProgressive;
/**
* While we're adding tiles, this is used to keep track of the position of
* the top-left of the top-left-most tile. When we come to wrap the tiles in
* TiledDrawTarget we subtract the value of this member from each tile's
* offset so that all the tiles have a positive offset, then add a
* translation to the TiledDrawTarget to compensate. This is important so
* that the mRect of the TiledDrawTarget is always at a positive x/y
* position, otherwise its GetSize() methods will be broken.
*/
gfx::IntPoint mTilingOrigin;
gfx::IntSize mSize;
gfxImageFormat mFormat;
};
class SingleTiledContentClient : public TiledContentClient {
public:
SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
ClientLayerManager* aManager);
protected:
~SingleTiledContentClient() {
MOZ_COUNT_DTOR(SingleTiledContentClient);
mTiledBuffer->ReleaseTiles();
}
public:
static bool ClientSupportsLayerSize(const gfx::IntSize& aSize,
ClientLayerManager* aManager);
void ClearCachedResources() override;
void UpdatedBuffer(TiledBufferType aType) override;
ClientTiledLayerBuffer* GetTiledBuffer() override { return mTiledBuffer; }
ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override {
return nullptr;
}
private:
RefPtr<ClientSingleTiledLayerBuffer> mTiledBuffer;
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -8,7 +8,6 @@
#include "CompositableClient.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/TextureForwarder.h"
#include "mozilla/layers/TiledContentClient.h"
#include "mozilla/StaticPrefs_layers.h"
#include "nsComponentManagerUtils.h"

Просмотреть файл

@ -1,729 +0,0 @@
/* -*- 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 "mozilla/layers/TiledContentClient.h"
#include <math.h> // for ceil, ceilf, floor
#include <algorithm>
#include "ClientTiledPaintedLayer.h" // for ClientTiledPaintedLayer
#include "ClientLayerManager.h" // for ClientLayerManager
#include "gfxContext.h" // for gfxContext, etc
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxRect.h" // for gfxRect
#include "mozilla/MathAlgorithms.h" // for Abs
#include "mozilla/ProfilerLabels.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Tools.h" // for BytesPerPixel
#include "mozilla/layers/APZUtils.h" // for AboutToCheckerboard
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "TextureClientPool.h"
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
#include "nsExpirationTracker.h" // for nsExpirationTracker
#include "nsMathUtils.h" // for NS_lroundf
#include "TiledLayerBuffer.h"
#include "UnitTransforms.h" // for TransformTo
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/UniquePtr.h"
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
# include "cairo.h"
# include <sstream>
using mozilla::layers::Layer;
static void DrawDebugOverlay(mozilla::gfx::DrawTarget* dt, int x, int y,
int width, int height) {
gfxContext c(dt);
// Draw border
c.NewPath();
c.SetDeviceColor(Color(0.f, 0.f, 0.f));
c.Rectangle(gfxRect(0, 0, width, height));
c.Stroke();
// Build tile description
std::stringstream ss;
ss << x << ", " << y;
// Draw text using cairo toy text API
// XXX: this drawing will silently fail if |dt| doesn't have a Cairo backend
cairo_t* cr = gfxFont::RefCairo(dt);
cairo_set_font_size(cr, 25);
cairo_text_extents_t extents;
cairo_text_extents(cr, ss.str().c_str(), &extents);
int textWidth = extents.width + 6;
c.NewPath();
c.SetDeviceColor(Color(0.f, 0.f, 0.f));
c.Rectangle(gfxRect(gfxPoint(2, 2), gfxSize(textWidth, 30)));
c.Fill();
c.NewPath();
c.SetDeviceColor(Color(1.0, 0.0, 0.0));
c.Rectangle(gfxRect(gfxPoint(2, 2), gfxSize(textWidth, 30)));
c.Stroke();
c.NewPath();
cairo_move_to(cr, 4, 28);
cairo_show_text(cr, ss.str().c_str());
}
#endif
namespace mozilla {
using namespace gfx;
namespace layers {
SharedFrameMetricsHelper::SharedFrameMetricsHelper()
: mLastProgressiveUpdateWasLowPrecision(false),
mProgressiveUpdateWasInDanger(false) {
MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
}
SharedFrameMetricsHelper::~SharedFrameMetricsHelper() {
MOZ_COUNT_DTOR(SharedFrameMetricsHelper);
}
static inline bool FuzzyEquals(float a, float b) {
return (fabsf(a - b) < 1e-6);
}
static AsyncTransform ComputeViewTransform(
const FrameMetrics& aContentMetrics,
const FrameMetrics& aCompositorMetrics) {
// This is basically the same code as
// AsyncPanZoomController::GetCurrentAsyncTransform but with aContentMetrics
// used in place of mLastContentPaintMetrics, because they should be
// equivalent, modulo race conditions while transactions are inflight.
ParentLayerPoint translation = (aCompositorMetrics.GetVisualScrollOffset() -
aContentMetrics.GetLayoutScrollOffset()) *
aCompositorMetrics.GetZoom();
return AsyncTransform(aCompositorMetrics.GetAsyncZoom(), -translation);
}
bool SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
const LayerMetricsWrapper& aLayer, bool aHasPendingNewThebesContent,
bool aLowPrecision, AsyncTransform& aViewTransform) {
MOZ_ASSERT(aLayer);
CompositorBridgeChild* compositor = nullptr;
if (!compositor) {
return false;
}
const FrameMetrics& contentMetrics = aLayer.Metrics();
FrameMetrics compositorMetrics;
if (!compositor->LookupCompositorFrameMetrics(contentMetrics.GetScrollId(),
compositorMetrics)) {
return false;
}
aViewTransform = ComputeViewTransform(contentMetrics, compositorMetrics);
// Reset the checkerboard risk flag when switching to low precision
// rendering.
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
// Skip low precision rendering until we're at risk of checkerboarding.
if (!mProgressiveUpdateWasInDanger) {
TILING_LOG(
"TILING: Aborting low-precision rendering because not at risk of "
"checkerboarding\n");
return true;
}
mProgressiveUpdateWasInDanger = false;
}
mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
// Always abort updates if the resolution has changed. There's no use
// in drawing at the incorrect resolution.
if (!FuzzyEquals(compositorMetrics.GetZoom().xScale,
contentMetrics.GetZoom().xScale) ||
!FuzzyEquals(compositorMetrics.GetZoom().yScale,
contentMetrics.GetZoom().yScale)) {
TILING_LOG("TILING: Aborting because resolution changed from %s to %s\n",
ToString(contentMetrics.GetZoom()).c_str(),
ToString(compositorMetrics.GetZoom()).c_str());
return true;
}
// Never abort drawing if we can't be sure we've sent a more recent
// display-port. If we abort updating when we shouldn't, we can end up
// with blank regions on the screen and we open up the risk of entering
// an endless updating cycle.
// XXX Suspicious comparisons between layout and visual scroll offsets.
// This may not do the right thing when we're zoomed in.
// However, note that the code as written will err on the side of returning
// false (whenever we're zoomed in and there's a persistent nonzero offset
// between the layout and visual viewports), which is the safer option.
if (fabsf(contentMetrics.GetLayoutScrollOffset().x -
compositorMetrics.GetVisualScrollOffset().x) <= 2 &&
fabsf(contentMetrics.GetLayoutScrollOffset().y -
compositorMetrics.GetVisualScrollOffset().y) <= 2 &&
fabsf(contentMetrics.GetDisplayPort().X() -
compositorMetrics.GetDisplayPort().X()) <= 2 &&
fabsf(contentMetrics.GetDisplayPort().Y() -
compositorMetrics.GetDisplayPort().Y()) <= 2 &&
fabsf(contentMetrics.GetDisplayPort().Width() -
compositorMetrics.GetDisplayPort().Width()) <= 2 &&
fabsf(contentMetrics.GetDisplayPort().Height() -
compositorMetrics.GetDisplayPort().Height()) <= 2) {
return false;
}
// When not a low precision pass and the page is in danger of checker boarding
// abort update.
if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
const nsTArray<ScrollPositionUpdate>& scrollUpdates =
aLayer.Metadata().GetScrollUpdates();
bool scrollUpdatePending = !scrollUpdates.IsEmpty() &&
compositorMetrics.GetScrollGeneration() <
scrollUpdates.LastElement().GetGeneration();
// If scrollUpdatePending is true, then that means the content-side
// metrics has a new scroll offset that is going to be forced into the
// compositor but it hasn't gotten there yet.
// Even though right now comparing the metrics might indicate we're
// about to checkerboard (and that's true), the checkerboarding will
// disappear as soon as the new scroll offset update is processed
// on the compositor side. To avoid leaving things in a low-precision
// paint, we need to detect and handle this case (bug 1026756).
if (!scrollUpdatePending &&
apz::AboutToCheckerboard(contentMetrics, compositorMetrics)) {
mProgressiveUpdateWasInDanger = true;
return true;
}
}
// Abort drawing stale low-precision content if there's a more recent
// display-port in the pipeline.
if (aLowPrecision && !aHasPendingNewThebesContent) {
TILING_LOG(
"TILING: Aborting low-precision because of new pending content\n");
return true;
}
return false;
}
bool ClientTiledLayerBuffer::HasFormatChanged() const {
SurfaceMode mode;
gfxContentType content = GetContentType(&mode);
return content != mLastPaintContentType || mode != mLastPaintSurfaceMode;
}
gfxContentType ClientTiledLayerBuffer::GetContentType(
SurfaceMode* aMode) const {
gfxContentType content = mPaintedLayer.CanUseOpaqueSurface()
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA;
SurfaceMode mode = mPaintedLayer.GetSurfaceMode();
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
#else
if (!mPaintedLayer.GetParent() ||
!mPaintedLayer.GetParent()->SupportsComponentAlphaChildren()) {
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
} else {
content = gfxContentType::COLOR;
}
#endif
} else if (mode == SurfaceMode::SURFACE_OPAQUE) {
#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
if (IsLowPrecision()) {
// If we're in low-res mode, drawing can sample from outside the visible
// region. Make sure that we only sample transparency if that happens.
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
content = gfxContentType::COLOR_ALPHA;
}
#else
if (mPaintedLayer.MayResample()) {
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
content = gfxContentType::COLOR_ALPHA;
}
#endif
}
if (aMode) {
*aMode = mode;
}
return content;
}
class TileExpiry final : public nsExpirationTracker<TileClient, 3> {
public:
TileExpiry() : nsExpirationTracker<TileClient, 3>(1000, "TileExpiry") {}
static void AddTile(TileClient* aTile) {
if (!sTileExpiry) {
sTileExpiry = MakeUnique<TileExpiry>();
}
sTileExpiry->AddObject(aTile);
}
static void RemoveTile(TileClient* aTile) {
MOZ_ASSERT(sTileExpiry);
sTileExpiry->RemoveObject(aTile);
}
static void Shutdown() { sTileExpiry = nullptr; }
private:
virtual void NotifyExpired(TileClient* aTile) override {
aTile->DiscardBackBuffer();
}
static UniquePtr<TileExpiry> sTileExpiry;
};
UniquePtr<TileExpiry> TileExpiry::sTileExpiry;
void ShutdownTileCache() { TileExpiry::Shutdown(); }
void TileClient::PrivateProtector::Set(TileClient* const aContainer,
RefPtr<TextureClient> aNewValue) {
if (mBuffer) {
TileExpiry::RemoveTile(aContainer);
}
mBuffer = aNewValue;
if (mBuffer) {
TileExpiry::AddTile(aContainer);
}
}
void TileClient::PrivateProtector::Set(TileClient* const aContainer,
TextureClient* aNewValue) {
Set(aContainer, RefPtr<TextureClient>(aNewValue));
}
// Placeholder
TileClient::TileClient() : mWasPlaceholder(false) {}
TileClient::~TileClient() {
if (mExpirationState.IsTracked()) {
MOZ_ASSERT(mBackBuffer);
TileExpiry::RemoveTile(this);
}
}
TileClient::TileClient(const TileClient& o) {
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mWasPlaceholder = o.mWasPlaceholder;
mUpdateRect = o.mUpdateRect;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mAllocator = o.mAllocator;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
}
TileClient& TileClient::operator=(const TileClient& o) {
if (this == &o) return *this;
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mWasPlaceholder = o.mWasPlaceholder;
mUpdateRect = o.mUpdateRect;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mAllocator = o.mAllocator;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
return *this;
}
void TileClient::Dump(std::stringstream& aStream) {
aStream << "TileClient(bb=" << (TextureClient*)mBackBuffer
<< " fb=" << mFrontBuffer.get();
if (mBackBufferOnWhite) {
aStream << " bbow=" << mBackBufferOnWhite.get();
}
if (mFrontBufferOnWhite) {
aStream << " fbow=" << mFrontBufferOnWhite.get();
}
aStream << ")";
}
void TileClient::Flip() {
RefPtr<TextureClient> frontBuffer = mFrontBuffer;
RefPtr<TextureClient> frontBufferOnWhite = mFrontBufferOnWhite;
mFrontBuffer = mBackBuffer;
mFrontBufferOnWhite = mBackBufferOnWhite;
mBackBuffer.Set(this, frontBuffer);
mBackBufferOnWhite = frontBufferOnWhite;
nsIntRegion invalidFront = mInvalidFront;
mInvalidFront = mInvalidBack;
mInvalidBack = invalidFront;
}
void TileClient::ValidateFromFront(
const nsIntRegion& aDirtyRegion, const nsIntRegion& aVisibleRegion,
gfx::DrawTarget* aBackBuffer, TilePaintFlags aFlags, IntRect* aCopiedRect,
AutoTArray<RefPtr<TextureClient>, 4>* aClients) {
if (!mBackBuffer || !mFrontBuffer) {
return;
}
gfx::IntSize tileSize = mFrontBuffer->GetSize();
const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
if (aDirtyRegion.Contains(tileRect)) {
// The dirty region means that we no longer need the front buffer, so
// discard it.
DiscardFrontBuffer();
return;
}
// Region that needs copying.
nsIntRegion regionToCopy = mInvalidBack;
regionToCopy.Sub(regionToCopy, aDirtyRegion);
regionToCopy.And(regionToCopy, aVisibleRegion);
*aCopiedRect = regionToCopy.GetBounds();
if (regionToCopy.IsEmpty()) {
// Just redraw it all.
return;
}
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
// is unlikely that we'd save much by copying each individual rect of the
// region, but we can reevaluate this if it becomes an issue.
const IntRect rectToCopy = regionToCopy.GetBounds();
OpenMode readMode = !!(aFlags & TilePaintFlags::Async)
? OpenMode::OPEN_READ_ASYNC
: OpenMode::OPEN_READ;
DualTextureClientAutoLock frontBuffer(mFrontBuffer, mFrontBufferOnWhite,
readMode);
if (!frontBuffer.Succeeded()) {
return;
}
RefPtr<gfx::SourceSurface> frontSurface = frontBuffer->Snapshot();
aBackBuffer->CopySurface(frontSurface, rectToCopy, rectToCopy.TopLeft());
if (aFlags & TilePaintFlags::Async) {
aClients->AppendElement(mFrontBuffer);
if (mFrontBufferOnWhite) {
aClients->AppendElement(mFrontBufferOnWhite);
}
}
mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
}
void TileClient::DiscardFrontBuffer() {
if (mFrontBuffer) {
MOZ_ASSERT(mFrontBuffer->GetReadLock());
MOZ_ASSERT(mAllocator);
if (mAllocator) {
mAllocator->ReturnTextureClientDeferred(mFrontBuffer);
if (mFrontBufferOnWhite) {
mAllocator->ReturnTextureClientDeferred(mFrontBufferOnWhite);
}
}
if (mFrontBuffer->IsLocked()) {
mFrontBuffer->Unlock();
}
if (mFrontBufferOnWhite && mFrontBufferOnWhite->IsLocked()) {
mFrontBufferOnWhite->Unlock();
}
mFrontBuffer = nullptr;
mFrontBufferOnWhite = nullptr;
}
}
static void DiscardTexture(TextureClient* aTexture,
TextureClientAllocator* aAllocator) {
MOZ_ASSERT(aAllocator);
if (aTexture && aAllocator) {
MOZ_ASSERT(aTexture->GetReadLock());
if (!aTexture->HasSynchronization() && aTexture->IsReadLocked()) {
// Our current back-buffer is still locked by the compositor. This can
// occur when the client is producing faster than the compositor can
// consume. In this case we just want to drop it and not return it to the
// pool.
aAllocator->ReportClientLost();
} else {
aAllocator->ReturnTextureClientDeferred(aTexture);
}
if (aTexture->IsLocked()) {
aTexture->Unlock();
}
}
}
void TileClient::DiscardBackBuffer() {
if (mBackBuffer) {
DiscardTexture(mBackBuffer, mAllocator);
mBackBuffer.Set(this, nullptr);
DiscardTexture(mBackBufferOnWhite, mAllocator);
mBackBufferOnWhite = nullptr;
}
}
static already_AddRefed<TextureClient> CreateBackBufferTexture(
TextureClient* aCurrentTexture, CompositableClient& aCompositable,
TextureClientAllocator* aAllocator) {
if (aCurrentTexture) {
// Our current back-buffer is still locked by the compositor. This can occur
// when the client is producing faster than the compositor can consume. In
// this case we just want to drop it and not return it to the pool.
aAllocator->ReportClientLost();
}
RefPtr<TextureClient> texture = aAllocator->GetTextureClient();
if (!texture) {
gfxCriticalError() << "[Tiling:Client] Failed to allocate a TextureClient";
return nullptr;
}
if (!aCompositable.AddTextureClient(texture)) {
gfxCriticalError() << "[Tiling:Client] Failed to connect a TextureClient";
return nullptr;
}
return texture.forget();
}
void TileClient::GetSyncTextureSerials(SurfaceMode aMode,
nsTArray<uint64_t>& aSerials) {
if (mFrontBuffer && mFrontBuffer->HasIntermediateBuffer() &&
!mFrontBuffer->IsReadLocked() &&
(aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA ||
(mFrontBufferOnWhite && !mFrontBufferOnWhite->IsReadLocked()))) {
return;
}
if (mBackBuffer && !mBackBuffer->HasIntermediateBuffer() &&
mBackBuffer->IsReadLocked()) {
aSerials.AppendElement(mBackBuffer->GetSerial());
}
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && mBackBufferOnWhite &&
!mBackBufferOnWhite->HasIntermediateBuffer() &&
mBackBufferOnWhite->IsReadLocked()) {
aSerials.AppendElement(mBackBufferOnWhite->GetSerial());
}
}
Maybe<AcquiredBackBuffer> TileClient::AcquireBackBuffer(
CompositableClient& aCompositable, const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion, gfxContentType aContent,
SurfaceMode aMode, TilePaintFlags aFlags) {
AUTO_PROFILER_LABEL("TileClient::AcquireBackBuffer", GRAPHICS_TileAllocation);
if (!mAllocator) {
gfxCriticalError() << "[TileClient] Missing TextureClientAllocator.";
return Nothing();
}
if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA) {
// It can happen that a component-alpha layer stops being on component alpha
// on the next frame, just drop the buffers on white if that happens.
if (mBackBufferOnWhite) {
mAllocator->ReportClientLost();
mBackBufferOnWhite = nullptr;
}
if (mFrontBufferOnWhite) {
mAllocator->ReportClientLost();
mFrontBufferOnWhite = nullptr;
}
}
// Try to re-use the front-buffer if possible
if (mFrontBuffer && mFrontBuffer->HasIntermediateBuffer() &&
!mFrontBuffer->IsReadLocked() &&
(aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA ||
(mFrontBufferOnWhite && !mFrontBufferOnWhite->IsReadLocked()))) {
// If we had a backbuffer we no longer need it since we can re-use the
// front buffer here. It can be worth it to hold on to the back buffer
// so we don't need to pay the cost of initializing a new back buffer
// later (copying pixels and texture upload). But this could increase
// our memory usage and lead to OOM more frequently from spikes in usage,
// so we have this behavior behind a pref.
if (!StaticPrefs::layers_tiles_retain_back_buffer()) {
DiscardBackBuffer();
}
Flip();
} else {
if (!mBackBuffer || mBackBuffer->IsReadLocked()) {
mBackBuffer.Set(this, CreateBackBufferTexture(mBackBuffer, aCompositable,
mAllocator));
if (!mBackBuffer) {
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
mInvalidBack = IntRect(IntPoint(), mBackBuffer->GetSize());
}
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!mBackBufferOnWhite || mBackBufferOnWhite->IsReadLocked()) {
mBackBufferOnWhite = CreateBackBufferTexture(mBackBufferOnWhite,
aCompositable, mAllocator);
if (!mBackBufferOnWhite) {
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
}
}
}
// Lock the texture clients
OpenMode lockMode = aFlags & TilePaintFlags::Async
? OpenMode::OPEN_READ_WRITE_ASYNC
: OpenMode::OPEN_READ_WRITE;
if (!mBackBuffer->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
if (mBackBufferOnWhite && !mBackBufferOnWhite->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (W)";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
// Borrow their draw targets
RefPtr<gfx::DrawTarget> backBuffer = mBackBuffer->BorrowDrawTarget();
RefPtr<gfx::DrawTarget> backBufferOnWhite = nullptr;
if (mBackBufferOnWhite) {
backBufferOnWhite = mBackBufferOnWhite->BorrowDrawTarget();
}
if (!backBuffer || (mBackBufferOnWhite && !backBufferOnWhite)) {
gfxCriticalError()
<< "[Tiling:Client] Failed to acquire draw targets for tile";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
// Construct a dual target if necessary
RefPtr<DrawTarget> target;
if (backBufferOnWhite) {
backBuffer = Factory::CreateDualDrawTarget(backBuffer, backBufferOnWhite);
backBufferOnWhite = nullptr;
target = backBuffer;
} else {
target = backBuffer;
}
// Construct a capture draw target if necessary
RefPtr<DrawTargetCapture> capture;
if (aFlags & TilePaintFlags::Async) {
capture = Factory::CreateCaptureDrawTargetForTarget(
target, StaticPrefs::layers_omtp_capture_limit_AtStartup());
target = capture;
}
// Gather texture clients
AutoTArray<RefPtr<TextureClient>, 4> clients;
clients.AppendElement(RefPtr<TextureClient>(mBackBuffer));
if (mBackBufferOnWhite) {
clients.AppendElement(mBackBufferOnWhite);
}
// Copy from the front buerr to the back if necessary
IntRect updatedRect;
ValidateFromFront(aDirtyRegion, aVisibleRegion, target, aFlags, &updatedRect,
&clients);
return Some(AcquiredBackBuffer{
target,
capture,
backBuffer,
std::move(updatedRect),
std::move(clients),
});
}
TileDescriptor TileClient::GetTileDescriptor() {
if (IsPlaceholderTile()) {
mWasPlaceholder = true;
return PlaceholderTileDescriptor();
}
bool wasPlaceholder = mWasPlaceholder;
mWasPlaceholder = false;
bool readLocked = mFrontBuffer->OnForwardedToHost();
bool readLockedOnWhite = false;
if (mFrontBufferOnWhite) {
readLockedOnWhite = mFrontBufferOnWhite->OnForwardedToHost();
}
return TexturedTileDescriptor(
nullptr, mFrontBuffer->GetIPDLActor(), Nothing(),
mFrontBufferOnWhite ? Some(mFrontBufferOnWhite->GetIPDLActor())
: Nothing(),
mUpdateRect, readLocked, readLockedOnWhite, wasPlaceholder);
}
void ClientTiledLayerBuffer::UnlockTile(TileClient& aTile) {
// We locked the back buffer, and flipped so we now need to unlock the front
if (aTile.mFrontBuffer && aTile.mFrontBuffer->IsLocked()) {
aTile.mFrontBuffer->Unlock();
aTile.mFrontBuffer->SyncWithObject(
mCompositableClient.GetForwarder()->GetSyncObject());
}
if (aTile.mFrontBufferOnWhite && aTile.mFrontBufferOnWhite->IsLocked()) {
aTile.mFrontBufferOnWhite->Unlock();
aTile.mFrontBufferOnWhite->SyncWithObject(
mCompositableClient.GetForwarder()->GetSyncObject());
}
if (aTile.mBackBuffer && aTile.mBackBuffer->IsLocked()) {
aTile.mBackBuffer->Unlock();
}
if (aTile.mBackBufferOnWhite && aTile.mBackBufferOnWhite->IsLocked()) {
aTile.mBackBufferOnWhite->Unlock();
}
}
void TiledContentClient::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
aStream << aPrefix;
aStream << nsPrintfCString("%sTiledContentClient (0x%p)", mName, this).get();
}
void TiledContentClient::Dump(std::stringstream& aStream, const char* aPrefix,
bool aDumpHtml, TextureDumpMode aCompress) {
GetTiledBuffer()->Dump(aStream, aPrefix, aDumpHtml, aCompress);
}
void BasicTiledLayerPaintData::ResetPaintData() {
mLowPrecisionPaintCount = 0;
mPaintFinished = false;
mHasTransformAnimation = false;
mCompositionBounds.SetEmpty();
mCriticalDisplayPort = Nothing();
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -1,406 +0,0 @@
/* -*- 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/. */
#ifndef MOZILLA_GFX_TILEDCONTENTCLIENT_H
#define MOZILLA_GFX_TILEDCONTENTCLIENT_H
#include <cstdint> // for uint64_t, uint16_t, uint8_t
#include <iosfwd> // for stringstream
#include <utility> // for move
#include "ClientLayerManager.h" // for ClientLayerManager
#include "Units.h" // for CSSToParentLayerScale2D, ParentLayerPoint, LayerIntRect, LayerRect, LayerToParent...
#include "gfxTypes.h" // for gfxContentType, gfxContentType::COLOR
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h" // for RefPtr, operator==, operator!=
#include "mozilla/TypedEnumBits.h" // for CastableTypedEnumResult, UnsignedIntegerTypeForEnum, MOZ_MAKE_ENUM_CLASS_BITWISE_...
#include "mozilla/gfx/2D.h" // for DrawTarget, DrawTargetCapture
#include "mozilla/gfx/Rect.h" // for IntRect
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, CompositableType, CompositableType::CONTENT_TILED
#include "mozilla/layers/LayerManager.h" // for LayerManager, LayerManager::DrawPaintedLayerCallback
#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
#include "mozilla/layers/LayersTypes.h" // for SurfaceMode, TextureDumpMode, Compress, SurfaceMode::SURFACE_OPAQUE
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/layers/TextureClientPool.h" // for TextureClientAllocator
#include "nsExpirationTracker.h" // for nsExpirationState
#include "nsRegion.h" // for nsIntRegion
#include "nsTArray.h" // for AutoTArray, nsTArray (ptr only)
namespace mozilla {
namespace layers {
class ClientTiledPaintedLayer;
class LayerMetricsWrapper;
struct AsyncTransform;
struct FrameMetrics;
enum class TilePaintFlags : uint8_t {
None = 0x0,
Async = 0x1,
Progressive = 0x2,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TilePaintFlags)
void ShutdownTileCache();
struct AcquiredBackBuffer {
AcquiredBackBuffer(gfx::DrawTarget* aTarget, gfx::DrawTargetCapture* aCapture,
gfx::DrawTarget* aBackBuffer,
const gfx::IntRect& aUpdatedRect,
AutoTArray<RefPtr<TextureClient>, 4>&& aTextureClients)
: mTarget(aTarget),
mCapture(aCapture),
mBackBuffer(aBackBuffer),
mUpdatedRect(aUpdatedRect),
mTextureClients(std::move(aTextureClients)) {}
AcquiredBackBuffer(const AcquiredBackBuffer&) = delete;
AcquiredBackBuffer& operator=(const AcquiredBackBuffer&) = delete;
AcquiredBackBuffer(AcquiredBackBuffer&&) = default;
AcquiredBackBuffer& operator=(AcquiredBackBuffer&&) = default;
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTargetCapture> mCapture;
RefPtr<gfx::DrawTarget> mBackBuffer;
gfx::IntRect mUpdatedRect;
AutoTArray<RefPtr<TextureClient>, 4> mTextureClients;
};
/**
* Represent a single tile in tiled buffer. The buffer keeps tiles,
* each tile keeps a reference to a texture client and a read-lock. This
* read-lock is used to help implement a copy-on-write mechanism. The tile
* should be locked before being sent to the compositor. The compositor should
* unlock the read-lock as soon as it has finished with the buffer in the
* TextureHost to prevent more textures being created than is necessary.
* Ideal place to store per tile debug information.
*/
struct TileClient {
// Placeholder
TileClient();
~TileClient();
TileClient(const TileClient& o);
TileClient& operator=(const TileClient& o);
bool operator==(const TileClient& o) const {
return mFrontBuffer == o.mFrontBuffer;
}
bool operator!=(const TileClient& o) const {
return mFrontBuffer != o.mFrontBuffer;
}
void SetTextureAllocator(TextureClientAllocator* aAllocator) {
mAllocator = aAllocator;
}
bool IsPlaceholderTile() const {
return mBackBuffer == nullptr && mFrontBuffer == nullptr;
}
void DiscardBuffers() {
DiscardFrontBuffer();
DiscardBackBuffer();
}
nsExpirationState* GetExpirationState() { return &mExpirationState; }
TileDescriptor GetTileDescriptor();
/**
* For debugging.
*/
void Dump(std::stringstream& aStream);
/**
* Swaps the front and back buffers.
*/
void Flip();
void DumpTexture(std::stringstream& aStream, TextureDumpMode aCompress) {
// TODO We should combine the OnWhite/OnBlack here an just output a single
// image.
CompositableClient::DumpTextureClient(aStream, mFrontBuffer, aCompress);
}
void GetSyncTextureSerials(SurfaceMode aMode, nsTArray<uint64_t>& aSerials);
/**
* Returns an unlocked TextureClient that can be used for writing new
* data to the tile. This may flip the front-buffer to the back-buffer if
* the front-buffer is still locked by the host, or does not have an
* internal buffer (and so will always be locked).
*
* If getting the back buffer required copying pixels from the front buffer
* then the copied region is stored in aAddPaintedRegion so the host side
* knows to upload it.
*
* If nullptr is returned, aTextureClientOnWhite is undefined.
*/
Maybe<AcquiredBackBuffer> AcquireBackBuffer(CompositableClient&,
const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfxContentType aContent,
SurfaceMode aMode,
TilePaintFlags aFlags);
void DiscardFrontBuffer();
void DiscardBackBuffer();
/* We wrap the back buffer in a class that disallows assignment
* so that we can track when ever it changes so that we can update
* the expiry tracker for expiring the back buffers */
class PrivateProtector {
public:
void Set(TileClient* container, RefPtr<TextureClient>);
void Set(TileClient* container, TextureClient*);
// Implicitly convert to TextureClient* because we can't chain
// implicit conversion that would happen on RefPtr<TextureClient>
operator TextureClient*() const { return mBuffer; }
RefPtr<TextureClient> operator->() { return mBuffer; }
private:
PrivateProtector& operator=(const PrivateProtector&);
RefPtr<TextureClient> mBuffer;
} mBackBuffer;
RefPtr<TextureClient> mBackBufferOnWhite;
RefPtr<TextureClient> mFrontBuffer;
RefPtr<TextureClient> mFrontBufferOnWhite;
RefPtr<TextureClientAllocator> mAllocator;
gfx::IntRect mUpdateRect;
bool mWasPlaceholder;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
TimeStamp mLastUpdate;
#endif
nsIntRegion mInvalidFront;
nsIntRegion mInvalidBack;
nsExpirationState mExpirationState;
private:
/*
* Copies dirty pixels from the front buffer into the back buffer,
* and records the copied region in aAddPaintedRegion.
*/
void ValidateFromFront(const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfx::DrawTarget* aBackBuffer, TilePaintFlags aFlags,
gfx::IntRect* aCopiedRegion,
AutoTArray<RefPtr<TextureClient>, 4>* aClients);
};
/**
* This struct stores all the data necessary to perform a paint so that it
* doesn't need to be recalculated on every repeated transaction.
*/
struct BasicTiledLayerPaintData {
/*
* The scroll offset of the content from the nearest ancestor layer that
* represents scrollable content with a display port set.
*/
ParentLayerPoint mScrollOffset;
/*
* The scroll offset of the content from the nearest ancestor layer that
* represents scrollable content with a display port set, for the last
* layer update transaction.
*/
ParentLayerPoint mLastScrollOffset;
/*
* The transform matrix to go from this layer's Layer units to
* the scroll ancestor's ParentLayer units. The "scroll ancestor" is
* the closest ancestor layer which scrolls, and is used to obtain
* the composition bounds that are relevant for this layer.
*/
LayerToParentLayerMatrix4x4 mTransformToCompBounds;
/*
* The critical displayport of the content from the nearest ancestor layer
* that represents scrollable content with a display port set. isNothing()
* if a critical displayport is not set.
*/
Maybe<LayerIntRect> mCriticalDisplayPort;
/*
* The render resolution of the document that the content this layer
* represents is in.
*/
CSSToParentLayerScale2D mResolution;
/*
* The composition bounds of the layer, in Layer coordinates. This is
* used to make sure that tiled updates to regions that are visible to the
* user are grouped coherently.
*/
LayerRect mCompositionBounds;
/*
* Low precision updates are always executed a tile at a time in repeated
* transactions. This counter is set to 1 on the first transaction of a low
* precision update, and incremented for each subsequent transaction.
*/
uint16_t mLowPrecisionPaintCount;
/*
* Whether this is the first time this layer is painting
*/
bool mFirstPaint : 1;
/*
* Whether there is further work to complete this paint. This is used to
* determine whether or not to repeat the transaction when painting
* progressively.
*/
bool mPaintFinished : 1;
/*
* Whether or not there is an async transform animation active
*/
bool mHasTransformAnimation : 1;
/*
* Initializes/clears data to prepare for paint action.
*/
void ResetPaintData();
};
class SharedFrameMetricsHelper {
public:
SharedFrameMetricsHelper();
~SharedFrameMetricsHelper();
/**
* This is called by the BasicTileLayer to determine if it is still interested
* in the update of this display-port to continue. We can return true here
* to abort the current update and continue with any subsequent ones. This
* is useful for slow-to-render pages when the display-port starts lagging
* behind enough that continuing to draw it is wasted effort.
*/
bool UpdateFromCompositorFrameMetrics(const LayerMetricsWrapper& aLayer,
bool aHasPendingNewThebesContent,
bool aLowPrecision,
AsyncTransform& aViewTransform);
/**
* Determines if the compositor's upcoming composition bounds has fallen
* outside of the contents display port. If it has then the compositor
* will start to checker board. Checker boarding is when the compositor
* tries to composite a tile and it is not available. Historically
* a tile with a checker board pattern was used. Now a blank tile is used.
*/
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
const FrameMetrics& aCompositorMetrics);
private:
bool mLastProgressiveUpdateWasLowPrecision;
bool mProgressiveUpdateWasInDanger;
};
/**
* Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
* This buffer provides an implementation of ValidateTile using a
* thebes callback and can support painting using a single paint buffer.
* Whether a single paint buffer is used is controlled by
* StaticPrefs::PerTileDrawing().
*/
class ClientTiledLayerBuffer {
public:
ClientTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient)
: mPaintedLayer(aPaintedLayer),
mCompositableClient(aCompositableClient),
mLastPaintContentType(gfxContentType::COLOR),
mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE),
mWasLastPaintProgressive(false) {}
virtual void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData, TilePaintFlags aFlags) = 0;
virtual void GetSyncTextureSerials(const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
nsTArray<uint64_t>& aSerials) {
return;
}
virtual bool SupportsProgressiveUpdate() = 0;
virtual bool ProgressiveUpdate(
const nsIntRegion& aValidRegion, const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion, nsIntRegion& aOutDrawnRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData) = 0;
virtual void ResetPaintedAndValidState() = 0;
virtual const nsIntRegion& GetValidRegion() = 0;
virtual bool IsLowPrecision() const = 0;
virtual void Dump(std::stringstream& aStream, const char* aPrefix,
bool aDumpHtml, TextureDumpMode aCompress) {}
const CSSToParentLayerScale2D& GetFrameResolution() {
return mFrameResolution;
}
void SetFrameResolution(const CSSToParentLayerScale2D& aResolution) {
mFrameResolution = aResolution;
}
bool HasFormatChanged() const;
protected:
void UnlockTile(TileClient& aTile);
gfxContentType GetContentType(SurfaceMode* aMode = nullptr) const;
ClientTiledPaintedLayer& mPaintedLayer;
CompositableClient& mCompositableClient;
gfxContentType mLastPaintContentType;
SurfaceMode mLastPaintSurfaceMode;
CSSToParentLayerScale2D mFrameResolution;
bool mWasLastPaintProgressive;
};
class TiledContentClient : public CompositableClient {
public:
TiledContentClient(ClientLayerManager* aManager, const char* aName = "")
: CompositableClient(aManager->AsShadowForwarder()), mName(aName) {}
protected:
~TiledContentClient() {}
public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
void Dump(std::stringstream& aStream, const char* aPrefix = "",
bool aDumpHtml = false,
TextureDumpMode aCompress = TextureDumpMode::Compress) override;
TextureInfo GetTextureInfo() const override {
return TextureInfo(CompositableType::CONTENT_TILED);
}
virtual ClientTiledLayerBuffer* GetTiledBuffer() = 0;
virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() = 0;
enum TiledBufferType { TILED_BUFFER, LOW_PRECISION_TILED_BUFFER };
virtual void UpdatedBuffer(TiledBufferType aType) = 0;
private:
const char* mName;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_TILEDCONTENTCLIENT_H

Просмотреть файл

@ -410,35 +410,6 @@ void ShadowLayerForwarder::UseTextures(
CompositableClient* aCompositable,
const nsTArray<TimedTextureClient>& aTextures) {
MOZ_ASSERT(aCompositable);
if (!aCompositable->IsConnected()) {
return;
}
AutoTArray<TimedTexture, 4> textures;
for (auto& t : aTextures) {
MOZ_ASSERT(t.mTextureClient);
MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() ==
mShadowManager->GetIPCChannel());
bool readLocked = t.mTextureClient->OnForwardedToHost();
textures.AppendElement(
TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), t.mTimeStamp,
t.mPictureRect, t.mFrameID, t.mProducerID, readLocked));
mClientLayerManager->GetCompositorBridgeChild()
->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
auto fenceFd = t.mTextureClient->GetInternalData()->GetAcquireFence();
if (fenceFd.IsValid()) {
mTxn->AddEdit(CompositableOperation(
aCompositable->GetIPCHandle(),
OpDeliverAcquireFence(nullptr, t.mTextureClient->GetIPDLActor(),
fenceFd)));
}
}
mTxn->AddEdit(CompositableOperation(aCompositable->GetIPCHandle(),
OpUseTexture(textures)));
}
void ShadowLayerForwarder::UseComponentAlphaTextures(
@ -446,50 +417,7 @@ void ShadowLayerForwarder::UseComponentAlphaTextures(
TextureClient* aTextureOnWhite) {
MOZ_ASSERT(aCompositable);
if (!aCompositable->IsConnected()) {
return;
}
MOZ_ASSERT(aTextureOnWhite);
MOZ_ASSERT(aTextureOnBlack);
MOZ_ASSERT(aCompositable->GetIPCHandle());
MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() ==
mShadowManager->GetIPCChannel());
MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() ==
mShadowManager->GetIPCChannel());
bool readLockedB = aTextureOnBlack->OnForwardedToHost();
bool readLockedW = aTextureOnWhite->OnForwardedToHost();
mClientLayerManager->GetCompositorBridgeChild()
->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
mClientLayerManager->GetCompositorBridgeChild()
->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
auto fenceFdB = aTextureOnBlack->GetInternalData()->GetAcquireFence();
if (fenceFdB.IsValid()) {
mTxn->AddEdit(CompositableOperation(
aCompositable->GetIPCHandle(),
OpDeliverAcquireFence(nullptr, aTextureOnBlack->GetIPDLActor(),
fenceFdB)));
}
auto fenceFdW = aTextureOnWhite->GetInternalData()->GetAcquireFence();
if (fenceFdW.IsValid()) {
mTxn->AddEdit(CompositableOperation(
aCompositable->GetIPCHandle(),
OpDeliverAcquireFence(nullptr, aTextureOnWhite->GetIPDLActor(),
fenceFdW)));
}
mTxn->AddEdit(CompositableOperation(
aCompositable->GetIPCHandle(),
OpUseComponentAlphaTextures(nullptr, aTextureOnBlack->GetIPDLActor(),
nullptr, aTextureOnWhite->GetIPDLActor(),
readLockedB, readLockedW)));
return;
}
static bool AddOpDestroy(Transaction* aTxn, const OpDestroy& op) {

Просмотреть файл

@ -16,11 +16,7 @@ EXPORTS += [
"basic/BasicLayers.h",
"basic/BasicLayersImpl.h",
"basic/BasicPaintedLayer.h",
"client/ClientCanvasLayer.h",
"client/ClientContainerLayer.h",
"client/ClientLayerManager.h",
"client/ClientPaintedLayer.h",
"client/ClientTiledPaintedLayer.h",
"composite/CompositableHost.h",
"composite/ImageHost.h",
"CompositorTypes.h",
@ -140,14 +136,11 @@ EXPORTS.mozilla.layers += [
"client/ContentClient.h",
"client/GPUVideoTextureClient.h",
"client/ImageClient.h",
"client/MultiTiledContentClient.h",
"client/SingleTiledContentClient.h",
"client/TextureClient.h",
"client/TextureClientPool.h",
"client/TextureClientRecycleAllocator.h",
"client/TextureClientSharedSurface.h",
"client/TextureRecorded.h",
"client/TiledContentClient.h",
"composite/AsyncCompositionManager.h",
"composite/CanvasLayerComposite.h",
"composite/ColorLayerComposite.h",
@ -408,25 +401,14 @@ UNIFIED_SOURCES += [
"CanvasDrawEventRecorder.cpp",
"CanvasRenderer.cpp",
"client/CanvasClient.cpp",
"client/ClientCanvasLayer.cpp",
"client/ClientCanvasRenderer.cpp",
"client/ClientColorLayer.cpp",
"client/ClientContainerLayer.cpp",
"client/ClientImageLayer.cpp",
"client/ClientLayerManager.cpp",
"client/ClientPaintedLayer.cpp",
"client/ClientTiledPaintedLayer.cpp",
"client/CompositableClient.cpp",
"client/ContentClient.cpp",
"client/GPUVideoTextureClient.cpp",
"client/ImageClient.cpp",
"client/MultiTiledContentClient.cpp",
"client/SingleTiledContentClient.cpp",
"client/TextureClientPool.cpp",
"client/TextureClientRecycleAllocator.cpp",
"client/TextureClientSharedSurface.cpp",
"client/TextureRecorded.cpp",
"client/TiledContentClient.cpp",
"composite/AsyncCompositionManager.cpp",
"composite/CanvasLayerComposite.cpp",
"composite/ColorLayerComposite.cpp",

Просмотреть файл

@ -11,7 +11,6 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/TiledContentClient.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webrender/webrender_ffi.h"
@ -1237,7 +1236,6 @@ void gfxPlatform::Shutdown() {
gfxGraphiteShaper::Shutdown();
gfxPlatformFontList::Shutdown();
gfxFontMissingGlyphs::Shutdown();
ShutdownTileCache();
// Free the various non-null transforms and loaded profiles
ShutdownCMS();