Bug 1006084 - Allow ThebesLayers to be recreated when the creation hint changes. r=mattwoodrow

This commit is contained in:
Chris Lord 2014-06-13 17:11:08 +01:00
Родитель 0bfb7d3b01
Коммит ffcda6a27d
9 изменённых файлов: 115 добавлений и 63 удалений

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

@ -357,6 +357,13 @@ public:
NONE, SCROLLABLE
};
/**
* Returns true if aLayer is optimized for the given ThebesLayerCreationHint.
*/
virtual bool IsOptimizedFor(ThebesLayer* aLayer,
ThebesLayerCreationHint aCreationHint)
{ return true; }
/**
* CONSTRUCTION PHASE ONLY
* Create a ThebesLayer for this manager's layer tree.
@ -1549,6 +1556,8 @@ public:
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
}
LayerManager::ThebesLayerCreationHint GetCreationHint() const { return mCreationHint; }
bool UsedForReadback() { return mUsedForReadback; }
void SetUsedForReadback(bool aUsed) { mUsedForReadback = aUsed; }
/**
@ -1562,9 +1571,11 @@ public:
gfxPoint GetResidualTranslation() const { return mResidualTranslation; }
protected:
ThebesLayer(LayerManager* aManager, void* aImplData)
ThebesLayer(LayerManager* aManager, void* aImplData,
LayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE)
: Layer(aManager, aImplData)
, mValidRegion()
, mCreationHint(aCreationHint)
, mUsedForReadback(false)
, mAllowResidualTranslation(false)
{
@ -1580,6 +1591,10 @@ protected:
*/
gfxPoint mResidualTranslation;
nsIntRegion mValidRegion;
/**
* The creation hint that was used when constructing this layer.
*/
const LayerManager::ThebesLayerCreationHint mCreationHint;
/**
* Set when this ThebesLayer is participating in readback, i.e. some
* ReadbackLayer (may) be getting its background from this layer.

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

@ -73,6 +73,8 @@ public:
virtual void Mutated(Layer* aLayer);
virtual bool IsOptimizedFor(ThebesLayer* aLayer, ThebesLayerCreationHint aHint);
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
virtual already_AddRefed<ThebesLayer> CreateThebesLayerWithHint(ThebesLayerCreationHint aHint);
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();

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

@ -127,6 +127,22 @@ ClientThebesLayer::RenderLayer()
mContentClient->EndPaint();
}
bool
ClientLayerManager::IsOptimizedFor(ThebesLayer* aLayer, ThebesLayerCreationHint aHint)
{
#ifdef MOZ_B2G
// The only creation hint is whether the layer is scrollable or not, and this
// is only respected on B2G, where it's used to determine whether to use
// tiled layers 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 == aLayer->GetCreationHint();
#else
return LayerManager::IsOptimizedFor(aLayer, aHint);
#endif
}
already_AddRefed<ThebesLayer>
ClientLayerManager::CreateThebesLayer()
{
@ -150,19 +166,19 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
}
if (gfxPrefs::LayersUseSimpleTiles()) {
nsRefPtr<SimpleClientTiledThebesLayer> layer =
new SimpleClientTiledThebesLayer(this);
new SimpleClientTiledThebesLayer(this, aHint);
CREATE_SHADOW(Thebes);
return layer.forget();
} else {
nsRefPtr<ClientTiledThebesLayer> layer =
new ClientTiledThebesLayer(this);
new ClientTiledThebesLayer(this, aHint);
CREATE_SHADOW(Thebes);
return layer.forget();
}
} else
{
nsRefPtr<ClientThebesLayer> layer =
new ClientThebesLayer(this);
new ClientThebesLayer(this, aHint);
CREATE_SHADOW(Thebes);
return layer.forget();
}

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

@ -27,15 +27,17 @@ class CompositableClient;
class ShadowableLayer;
class SpecificLayerAttributes;
class ClientThebesLayer : public ThebesLayer,
class ClientThebesLayer : public ThebesLayer,
public ClientLayer {
public:
typedef RotatedContentBuffer::PaintState PaintState;
typedef RotatedContentBuffer::ContentType ContentType;
ClientThebesLayer(ClientLayerManager* aLayerManager) :
ClientThebesLayer(ClientLayerManager* aLayerManager,
LayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE) :
ThebesLayer(aLayerManager,
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST())),
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
aCreationHint),
mContentClient(nullptr)
{
MOZ_COUNT_CTOR(ClientThebesLayer);

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

@ -29,9 +29,11 @@ namespace mozilla {
namespace layers {
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager)
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager,
ClientLayerManager::ThebesLayerCreationHint aCreationHint)
: ThebesLayer(aManager,
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
aCreationHint)
, mContentClient()
{
MOZ_COUNT_CTOR(ClientTiledThebesLayer);

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

@ -41,7 +41,8 @@ class ClientTiledThebesLayer : public ThebesLayer,
typedef ThebesLayer Base;
public:
ClientTiledThebesLayer(ClientLayerManager* const aManager);
ClientTiledThebesLayer(ClientLayerManager* const aManager,
ClientLayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE);
~ClientTiledThebesLayer();
// Override name to distinguish it from ClientThebesLayer in layer dumps

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

@ -247,9 +247,11 @@ SimpleTiledContentClient::UseTiledLayerBuffer()
mTiledBuffer.ClearPaintedRegion();
}
SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager)
SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager,
ClientLayerManager::ThebesLayerCreationHint aCreationHint)
: ThebesLayer(aManager,
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
aCreationHint)
, mContentClient()
{
MOZ_COUNT_CTOR(SimpleClientTiledThebesLayer);

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

@ -159,7 +159,8 @@ class SimpleClientTiledThebesLayer : public ThebesLayer,
typedef ThebesLayer Base;
public:
SimpleClientTiledThebesLayer(ClientLayerManager* const aManager);
SimpleClientTiledThebesLayer(ClientLayerManager* const aManager,
ClientLayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE);
~SimpleClientTiledThebesLayer();
// Thebes Layer

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

@ -1446,74 +1446,85 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot
// We need a new thebes layer
nsRefPtr<ThebesLayer> layer;
ThebesDisplayItemLayerUserData* data;
bool layerRecycled = false;
#ifndef MOZ_ANDROID_OMTC
bool didResetScrollPositionForLayerPixelAlignment = false;
#endif
// Check whether the layer will be scrollable. This is used as a hint to
// influence whether tiled layers are used or not.
LayerManager::ThebesLayerCreationHint creationHint = LayerManager::NONE;
nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent();
if (animatedGeometryRootParent &&
animatedGeometryRootParent->GetType() == nsGkAtoms::scrollFrame) {
creationHint = LayerManager::SCROLLABLE;
}
if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) {
// Recycle a layer
// Try to recycle a layer
layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer];
++mNextFreeRecycledThebesLayer;
// Clear clip rect and mask layer so we don't accidentally stay clipped.
// We will reapply any necessary clipping.
layer->SetMaskLayer(nullptr);
data = static_cast<ThebesDisplayItemLayerUserData*>
(layer->GetUserData(&gThebesDisplayItemLayerUserData));
NS_ASSERTION(data, "Recycled ThebesLayers must have user data");
// Check if the layer hint has changed and whether or not the layer should
// be recreated because of it.
if (mManager->IsOptimizedFor(layer->AsThebesLayer(), creationHint)) {
layerRecycled = true;
// This gets called on recycled ThebesLayers that are going to be in the
// final layer tree, so it's a convenient time to invalidate the
// content that changed where we don't know what ThebesLayer it belonged
// to, or if we need to invalidate the entire layer, we can do that.
// This needs to be done before we update the ThebesLayer to its new
// transform. See nsGfxScrollFrame::InvalidateInternal, where
// we ensure that mInvalidThebesContent is updated according to the
// scroll position as of the most recent paint.
if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
!FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
// Clear clip rect and mask layer so we don't accidentally stay clipped.
// We will reapply any necessary clipping.
layer->SetMaskLayer(nullptr);
data = static_cast<ThebesDisplayItemLayerUserData*>
(layer->GetUserData(&gThebesDisplayItemLayerUserData));
NS_ASSERTION(data, "Recycled ThebesLayers must have user data");
// This gets called on recycled ThebesLayers that are going to be in the
// final layer tree, so it's a convenient time to invalidate the
// content that changed where we don't know what ThebesLayer it belonged
// to, or if we need to invalidate the entire layer, we can do that.
// This needs to be done before we update the ThebesLayer to its new
// transform. See nsGfxScrollFrame::InvalidateInternal, where
// we ensure that mInvalidThebesContent is updated according to the
// scroll position as of the most recent paint.
if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
!FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf_stderr("Recycled layer %p changed scale\n", layer.get());
}
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf_stderr("Recycled layer %p changed scale\n", layer.get());
}
#endif
InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot);
InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot);
#ifndef MOZ_ANDROID_OMTC
didResetScrollPositionForLayerPixelAlignment = true;
didResetScrollPositionForLayerPixelAlignment = true;
#endif
}
if (!data->mRegionToInvalidate.IsEmpty()) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf_stderr("Invalidating deleted frame content from layer %p\n", layer.get());
}
#endif
layer->InvalidateRegion(data->mRegionToInvalidate);
if (!data->mRegionToInvalidate.IsEmpty()) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
nsAutoCString str;
AppendToString(str, data->mRegionToInvalidate);
printf_stderr("Invalidating layer %p: %s\n", layer.get(), str.get());
}
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf_stderr("Invalidating deleted frame content from layer %p\n", layer.get());
}
#endif
data->mRegionToInvalidate.SetEmpty();
}
layer->InvalidateRegion(data->mRegionToInvalidate);
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
nsAutoCString str;
AppendToString(str, data->mRegionToInvalidate);
printf_stderr("Invalidating layer %p: %s\n", layer.get(), str.get());
}
#endif
data->mRegionToInvalidate.SetEmpty();
}
// We do not need to Invalidate these areas in the widget because we
// assume the caller of InvalidateThebesLayerContents has ensured
// the area is invalidated in the widget.
} else {
// Check whether the layer will be scrollable. This is used as a hint to
// influence whether tiled layers are used or not.
bool canScroll = false;
nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent();
if (animatedGeometryRootParent &&
animatedGeometryRootParent->GetType() == nsGkAtoms::scrollFrame) {
canScroll = true;
// We do not need to Invalidate these areas in the widget because we
// assume the caller of InvalidateThebesLayerContents has ensured
// the area is invalidated in the widget.
}
}
if (!layerRecycled) {
// Create a new thebes layer
layer = mManager->CreateThebesLayerWithHint(canScroll ? LayerManager::SCROLLABLE :
LayerManager::NONE);
layer = mManager->CreateThebesLayerWithHint(creationHint);
if (!layer)
return nullptr;
// Mark this layer as being used for Thebes-painting display items