Do image scaling on the GPU (bug 650988, r=roc,cjones).

This commit is contained in:
Andreas Gal 2012-05-03 07:05:55 -07:00
parent b5690cc915
commit 6ced71cf11
12 changed files with 150 additions and 38 deletions

View File

@ -1602,7 +1602,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
mBounds.UnionRect(mBounds, itemContent);
itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect);
LayerState layerState = item->GetLayerState(mBuilder, mManager);
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
@ -2070,7 +2070,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
}
if (aContainerItem &&
aContainerItem->GetLayerState(aBuilder, aManager) == LAYER_ACTIVE_EMPTY) {
aContainerItem->GetLayerState(aBuilder, aManager, aParameters) == LAYER_ACTIVE_EMPTY) {
// Empty layers only have metadata and should never have display items. We
// early exit because later, invalidation will walk up the frame tree to
// determine which thebes layer gets invalidated. Since an empty layer

View File

@ -1654,9 +1654,10 @@ void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
}
bool nsDisplayWrapList::ChildrenCanBeInactive(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const nsDisplayList& aList,
nsIFrame* aActiveScrolledRoot) {
LayerManager* aManager,
const ContainerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aActiveScrolledRoot) {
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
nsIFrame* f = i->GetUnderlyingFrame();
if (f) {
@ -1666,12 +1667,12 @@ bool nsDisplayWrapList::ChildrenCanBeInactive(nsDisplayListBuilder* aBuilder,
return false;
}
LayerState state = i->GetLayerState(aBuilder, aManager);
LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
if (state == LAYER_ACTIVE)
return false;
if (state == LAYER_NONE) {
nsDisplayList* list = i->GetList();
if (list && !ChildrenCanBeInactive(aBuilder, aManager, *list, aActiveScrolledRoot))
if (list && !ChildrenCanBeInactive(aBuilder, aManager, aParameters, *list, aActiveScrolledRoot))
return false;
}
}
@ -1810,13 +1811,14 @@ IsItemTooSmallForActiveLayer(nsDisplayItem* aItem)
nsDisplayItem::LayerState
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) {
LayerManager* aManager,
const ContainerParameters& aParameters) {
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) &&
!IsItemTooSmallForActiveLayer(this))
return LAYER_ACTIVE;
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
return !ChildrenCanBeInactive(aBuilder, aManager, mList, activeScrolledRoot)
return !ChildrenCanBeInactive(aBuilder, aManager, aParameters, mList, activeScrolledRoot)
? LAYER_ACTIVE : LAYER_INACTIVE;
}
@ -1992,7 +1994,8 @@ nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
LayerState
nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{
// Force this as a layer so we can scroll asynchronously.
// This causes incorrect rendering for rounded clips!
@ -2083,7 +2086,8 @@ nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
LayerState
nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return LAYER_ACTIVE_EMPTY;
}
@ -2677,7 +2681,8 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
nsDisplayItem::LayerState
nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) {
LayerManager* aManager,
const ContainerParameters& aParameters) {
// Here we check if the *post-transform* bounds of this item are big enough
// to justify an active layer.
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
@ -2688,9 +2693,10 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
return !mStoredList.ChildrenCanBeInactive(aBuilder,
aManager,
*mStoredList.GetList(),
activeScrolledRoot)
aManager,
aParameters,
*mStoredList.GetList(),
activeScrolledRoot)
? LAYER_ACTIVE : LAYER_INACTIVE;
}

View File

@ -596,6 +596,7 @@ protected:
*/
class nsDisplayItem : public nsDisplayItemLink {
public:
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
@ -765,7 +766,8 @@ public:
* every time we paint.
*/
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{ return mozilla::LAYER_NONE; }
/**
* Actually paint this item to some rendering context.
@ -800,7 +802,6 @@ public:
* FrameLayerBuilder::BuildContainerLayerFor if a ContainerLayer is
* constructed.
*/
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
@ -1805,9 +1806,10 @@ public:
* and they all have the given aActiveScrolledRoot.
*/
static bool ChildrenCanBeInactive(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const nsDisplayList& aList,
nsIFrame* aActiveScrolledRoot);
LayerManager* aManager,
const ContainerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aActiveScrolledRoot);
protected:
nsDisplayWrapList() {}
@ -1875,7 +1877,8 @@ public:
LayerManager* aManager,
const ContainerParameters& aContainerParameters);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
@ -1899,7 +1902,8 @@ public:
LayerManager* aManager,
const ContainerParameters& aContainerParameters);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return mozilla::LAYER_ACTIVE;
}
@ -1966,7 +1970,8 @@ public:
const nsRect& aAllowVisibleRegionExpansion);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem);
@ -2007,7 +2012,8 @@ public:
#endif
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem);
@ -2230,7 +2236,8 @@ public:
bool* aSnap);
virtual bool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters);

View File

@ -182,6 +182,20 @@ nsLayoutUtils::UseBackgroundNearestFiltering()
return sUseBackgroundNearestFilteringEnabled;
}
bool
nsLayoutUtils::GPUImageScalingEnabled()
{
static bool sGPUImageScalingEnabled;
static bool sGPUImageScalingPrefInitialised = false;
if (!sGPUImageScalingPrefInitialised) {
sGPUImageScalingPrefInitialised = true;
sGPUImageScalingEnabled = mozilla::Preferences::GetBool("layout.gpu-image-scaling.enabled", false);
}
return sGPUImageScalingEnabled;
}
void
nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
nsOverflowAreas& aOverflowAreas)

View File

@ -1502,6 +1502,12 @@ public:
*/
static bool UseBackgroundNearestFiltering();
/**
* Checks whether we want to use the GPU to scale images when
* possible.
*/
static bool GPUImageScalingEnabled();
/**
* Unions the overflow areas of all non-popup children of aFrame with
* aOverflowAreas.

View File

@ -109,7 +109,8 @@ public:
BuildLayer(aBuilder, aManager, this);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const FrameLayerBuilder::ContainerParameters& aParameters)
{
if (CanvasElementFromContent(mFrame->GetContent())->ShouldForceInactiveLayer(aManager))
return LAYER_INACTIVE;

View File

@ -1234,11 +1234,9 @@ nsDisplayImage::GetContainer()
return container.forget();
}
void
nsDisplayImage::ConfigureLayer(ImageLayer* aLayer)
gfxRect
nsDisplayImage::GetDestRect()
{
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
PRInt32 factor = mFrame->PresContext()->AppUnitsPerDevPixel();
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
@ -1246,11 +1244,77 @@ nsDisplayImage::ConfigureLayer(ImageLayer* aLayer)
gfxRect destRect(dest.x, dest.y, dest.width, dest.height);
destRect.ScaleInverse(factor);
return destRect;
}
LayerState
nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const FrameLayerBuilder::ContainerParameters& aParameters)
{
if (mImage->GetType() != imgIContainer::TYPE_RASTER ||
!aManager->IsCompositingCheap() ||
!nsLayoutUtils::GPUImageScalingEnabled()) {
return LAYER_NONE;
}
PRInt32 imageWidth;
PRInt32 imageHeight;
mImage->GetWidth(&imageWidth);
mImage->GetHeight(&imageHeight);
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
gfxRect destRect = GetDestRect();
destRect.width *= aParameters.mXScale;
destRect.height *= aParameters.mYScale;
// Calculate the scaling factor for the frame.
gfxSize scale = gfxSize(destRect.width / imageWidth, destRect.height / imageHeight);
// If we are not scaling at all, no point in separating this into a layer.
if (scale.width == 1.0f && scale.height == 1.0f) {
return LAYER_INACTIVE;
}
// If the target size is pretty small, no point in using a layer.
if (destRect.width * destRect.height < 64 * 64) {
return LAYER_INACTIVE;
}
return LAYER_ACTIVE;
}
already_AddRefed<Layer>
nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters)
{
nsRefPtr<ImageContainer> container;
nsresult rv = mImage->GetImageContainer(getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nsnull);
nsRefPtr<ImageLayer> layer = aManager->CreateImageLayer();
layer->SetContainer(container);
ConfigureLayer(layer);
return layer.forget();
}
void
nsDisplayImage::ConfigureLayer(ImageLayer *aLayer)
{
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
PRInt32 imageWidth;
PRInt32 imageHeight;
mImage->GetWidth(&imageWidth);
mImage->GetHeight(&imageHeight);
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
const gfxRect destRect = GetDestRect();
gfxMatrix transform;
transform.Translate(destRect.TopLeft());
transform.Scale(destRect.Width()/imageWidth,

View File

@ -410,13 +410,23 @@ public:
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);
/**
* Returns an ImageContainer for this image if the image type
* supports it (TYPE_RASTER only).
*/
already_AddRefed<ImageContainer> GetContainer();
gfxRect GetDestRect();
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters);
/**
* Configure an ImageLayer for this display item.
* Set the required filter and scaling transform.

View File

@ -932,7 +932,8 @@ public:
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return LAYER_ACTIVE;
}

View File

@ -168,8 +168,8 @@ public:
LayerManager* aManager,
nsDisplayItem* aItem);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
already_AddRefed<ImageContainer> GetImageContainer();
/**
@ -330,7 +330,8 @@ public:
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder,
aManager);

View File

@ -360,7 +360,8 @@ public:
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const FrameLayerBuilder::ContainerParameters& aParameters)
{
if (aManager->GetBackendType() != LayerManager::LAYERS_BASIC) {
// For non-basic layer managers we can assume that compositing

View File

@ -161,7 +161,8 @@ public:
NS_OVERRIDE
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
LayerManager* aManager,
const ContainerParameters& aParameters)
{ return mozilla::LAYER_ACTIVE; }
NS_OVERRIDE