зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1727398 - Remove ClientLayerManager. r=aosmond
Differential Revision: https://phabricator.services.mozilla.com/D123525
This commit is contained in:
Родитель
aac357d350
Коммит
8c1b1dcb3d
|
@ -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(¤tConfig);
|
||||
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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче