Bug 922942 - Add a Validate() pass to BasicLayers to avoid needing to create a dummy destination context. r=roc

This commit is contained in:
Matt Woodrow 2013-10-15 16:23:21 +13:00
parent 762844a6e0
commit c8d82e8dcd
7 changed files with 114 additions and 96 deletions

View File

@ -115,6 +115,20 @@ BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect)
return covered.Contains(rect); return covered.Contains(rect);
} }
void
BasicContainerLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
BasicImplData* data = ToData(l);
data->Validate(aCallback, aCallbackData);
if (l->GetMaskLayer()) {
data = ToData(l->GetMaskLayer());
data->Validate(aCallback, aCallbackData);
}
}
}
already_AddRefed<ContainerLayer> already_AddRefed<ContainerLayer>
BasicLayerManager::CreateContainerLayer() BasicLayerManager::CreateContainerLayer()
{ {

View File

@ -76,6 +76,9 @@ public:
void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; } void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData) MOZ_OVERRIDE;
protected: protected:
BasicLayerManager* BasicManager() BasicLayerManager* BasicManager()
{ {

View File

@ -73,6 +73,9 @@ public:
void* aCallbackData, void* aCallbackData,
ReadbackProcessor* aReadback) {} ReadbackProcessor* aReadback) {}
virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData) {}
/** /**
* Layers will get this call when their layer manager is destroyed, this * Layers will get this call when their layer manager is destroyed, this
* indicates they should clear resources they don't really need after their * indicates they should clear resources they don't really need after their

View File

@ -581,22 +581,32 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
NS_ASSERTION(InConstruction(), "Should be in construction phase"); NS_ASSERTION(InConstruction(), "Should be in construction phase");
mPhase = PHASE_DRAWING; mPhase = PHASE_DRAWING;
Layer* aLayer = GetRoot(); RenderTraceLayers(mRoot, "FF00");
RenderTraceLayers(aLayer, "FF00");
mTransactionIncomplete = false; mTransactionIncomplete = false;
if (aFlags & END_NO_COMPOSITE) { if (mRoot) {
if (!mDummyTarget) { // Need to do this before we call ApplyDoubleBuffering,
// XXX: We should really just set mTarget to null and make sure we can handle that further down the call chain // which depends on correct effective transforms
// Creating this temporary surface can be expensive on some platforms (d2d in particular), so cache it between paints. mSnapEffectiveTransforms =
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), GFX_CONTENT_COLOR); mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
mDummyTarget = new gfxContext(surf); mRoot->ComputeEffectiveTransforms(mTarget ? gfx3DMatrix::From2D(mTarget->CurrentMatrix()) : gfx3DMatrix());
ToData(mRoot)->Validate(aCallback, aCallbackData);
if (mRoot->GetMaskLayer()) {
ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData);
}
if (aFlags & END_NO_COMPOSITE) {
// Apply pending tree updates before recomputing effective
// properties.
mRoot->ApplyPendingUpdatesToSubtree();
} }
mTarget = mDummyTarget;
} }
if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { if (mTarget && mRoot &&
!(aFlags & END_NO_IMMEDIATE_REDRAW) &&
!(aFlags & END_NO_COMPOSITE)) {
nsIntRect clipRect; nsIntRect clipRect;
{ {
@ -605,18 +615,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
clipRect = ToOutsideIntRect(mTarget->GetClipExtents()); clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
} }
if (aFlags & END_NO_COMPOSITE) {
// Apply pending tree updates before recomputing effective
// properties.
aLayer->ApplyPendingUpdatesToSubtree();
}
// Need to do this before we call ApplyDoubleBuffering,
// which depends on correct effective transforms
mSnapEffectiveTransforms =
!(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING);
mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix()));
if (IsRetained()) { if (IsRetained()) {
nsIntRegion region; nsIntRegion region;
MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE); MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
@ -625,22 +623,12 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
} }
} }
if (aFlags & END_NO_COMPOSITE) { PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
if (IsRetained()) { if (mWidget) {
// Clip the destination out so that we don't draw to it, and FlashWidgetUpdateArea(mTarget);
// only end up validating ThebesLayers.
mTarget->Clip(gfxRect(0, 0, 0, 0));
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
}
// If we're not retained, then don't composite means do nothing at all.
} else {
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
if (mWidget) {
FlashWidgetUpdateArea(mTarget);
}
RenderDebugOverlay();
LayerManager::PostPresent();
} }
RenderDebugOverlay();
LayerManager::PostPresent();
if (!mTransactionIncomplete) { if (!mTransactionIncomplete) {
// Clear out target if we have a complete transaction. // Clear out target if we have a complete transaction.

View File

@ -186,7 +186,6 @@ protected:
nsRefPtr<gfxContext> mDefaultTarget; nsRefPtr<gfxContext> mDefaultTarget;
// The context to draw into. // The context to draw into.
nsRefPtr<gfxContext> mTarget; nsRefPtr<gfxContext> mTarget;
nsRefPtr<gfxContext> mDummyTarget;
// Image factory we use. // Image factory we use.
nsRefPtr<ImageFactory> mFactory; nsRefPtr<ImageFactory> mFactory;

View File

@ -90,21 +90,11 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
NS_ASSERTION(BasicManager()->InDrawing(), NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase"); "Can only draw in drawing phase");
if (!mContentClient) {
// we pass a null pointer for the Forwarder argument, which means
// this will not have a ContentHost on the other side.
mContentClient = new ContentClientBasic(nullptr, BasicManager());
}
nsTArray<ReadbackProcessor::Update> readbackUpdates; nsTArray<ReadbackProcessor::Update> readbackUpdates;
if (aReadback && UsedForReadback()) { if (aReadback && UsedForReadback()) {
aReadback->GetThebesLayerUpdates(this, &readbackUpdates); aReadback->GetThebesLayerUpdates(this, &readbackUpdates);
} }
bool canUseOpaqueSurface = CanUseOpaqueSurface();
ContentType contentType =
canUseOpaqueSurface ? GFX_CONTENT_COLOR :
GFX_CONTENT_COLOR_ALPHA;
float opacity = GetEffectiveOpacity(); float opacity = GetEffectiveOpacity();
gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode();
@ -158,54 +148,6 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
return; return;
} }
{
uint32_t flags = 0;
#ifndef MOZ_WIDGET_ANDROID
if (BasicManager()->CompositorMightResample()) {
flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
}
if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) {
if (MayResample()) {
flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
}
}
#endif
if (mDrawAtomically) {
flags |= ThebesLayerBuffer::PAINT_NO_ROTATION;
}
PaintState state =
mContentClient->BeginPaintBuffer(this, contentType, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (state.mContext) {
// 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)
state.mRegionToInvalidate.And(state.mRegionToInvalidate,
GetEffectiveVisibleRegion());
nsIntRegion extendedDrawRegion = state.mRegionToDraw;
SetAntialiasingFlags(this, state.mContext);
RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds());
PaintBuffer(state.mContext,
state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
state.mDidSelfCopy,
aCallback, aCallbackData);
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();
RenderTraceInvalidateEnd(this, "FFFF00");
} else {
// It's possible that state.mRegionToInvalidate is nonempty here,
// if we are shrinking the valid region to nothing. So use mRegionToDraw
// instead.
NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(),
"No context when we have something to draw, resource exhaustion?");
}
}
if (BasicManager()->IsTransactionIncomplete()) if (BasicManager()->IsTransactionIncomplete())
return; return;
@ -242,6 +184,72 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
} }
} }
void
BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
if (!mContentClient) {
// we pass a null pointer for the Forwarder argument, which means
// this will not have a ContentHost on the other side.
mContentClient = new ContentClientBasic(nullptr, BasicManager());
}
if (!BasicManager()->IsRetained()) {
return;
}
bool canUseOpaqueSurface = CanUseOpaqueSurface();
ContentType contentType =
canUseOpaqueSurface ? GFX_CONTENT_COLOR :
GFX_CONTENT_COLOR_ALPHA;
uint32_t flags = 0;
#ifndef MOZ_WIDGET_ANDROID
if (BasicManager()->CompositorMightResample()) {
flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
}
if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) {
if (MayResample()) {
flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
}
}
#endif
if (mDrawAtomically) {
flags |= ThebesLayerBuffer::PAINT_NO_ROTATION;
}
PaintState state =
mContentClient->BeginPaintBuffer(this, contentType, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (state.mContext) {
// 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)
state.mRegionToInvalidate.And(state.mRegionToInvalidate,
GetEffectiveVisibleRegion());
nsIntRegion extendedDrawRegion = state.mRegionToDraw;
SetAntialiasingFlags(this, state.mContext);
RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds());
PaintBuffer(state.mContext,
state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
state.mDidSelfCopy,
aCallback, aCallbackData);
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();
RenderTraceInvalidateEnd(this, "FFFF00");
} else {
// It's possible that state.mRegionToInvalidate is nonempty here,
// if we are shrinking the valid region to nothing. So use mRegionToDraw
// instead.
NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(),
"No context when we have something to draw, resource exhaustion?");
}
}
already_AddRefed<ThebesLayer> already_AddRefed<ThebesLayer>
BasicLayerManager::CreateThebesLayer() BasicLayerManager::CreateThebesLayer()
{ {

View File

@ -64,6 +64,9 @@ public:
void* aCallbackData, void* aCallbackData,
ReadbackProcessor* aReadback); ReadbackProcessor* aReadback);
virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData) MOZ_OVERRIDE;
virtual void ClearCachedResources() virtual void ClearCachedResources()
{ {
if (mContentClient) { if (mContentClient) {