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);
}
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>
BasicLayerManager::CreateContainerLayer()
{

View File

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

View File

@ -73,6 +73,9 @@ public:
void* aCallbackData,
ReadbackProcessor* aReadback) {}
virtual void Validate(LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData) {}
/**
* Layers will get this call when their layer manager is destroyed, this
* 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");
mPhase = PHASE_DRAWING;
Layer* aLayer = GetRoot();
RenderTraceLayers(aLayer, "FF00");
RenderTraceLayers(mRoot, "FF00");
mTransactionIncomplete = false;
if (aFlags & END_NO_COMPOSITE) {
if (!mDummyTarget) {
// XXX: We should really just set mTarget to null and make sure we can handle that further down the call chain
// Creating this temporary surface can be expensive on some platforms (d2d in particular), so cache it between paints.
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), GFX_CONTENT_COLOR);
mDummyTarget = new gfxContext(surf);
if (mRoot) {
// Need to do this before we call ApplyDoubleBuffering,
// which depends on correct effective transforms
mSnapEffectiveTransforms =
mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
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;
{
@ -605,18 +615,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
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()) {
nsIntRegion region;
MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
@ -625,22 +623,12 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
}
}
if (aFlags & END_NO_COMPOSITE) {
if (IsRetained()) {
// Clip the destination out so that we don't draw to it, and
// 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();
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
if (mWidget) {
FlashWidgetUpdateArea(mTarget);
}
RenderDebugOverlay();
LayerManager::PostPresent();
if (!mTransactionIncomplete) {
// Clear out target if we have a complete transaction.

View File

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

View File

@ -90,21 +90,11 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
NS_ASSERTION(BasicManager()->InDrawing(),
"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;
if (aReadback && UsedForReadback()) {
aReadback->GetThebesLayerUpdates(this, &readbackUpdates);
}
bool canUseOpaqueSurface = CanUseOpaqueSurface();
ContentType contentType =
canUseOpaqueSurface ? GFX_CONTENT_COLOR :
GFX_CONTENT_COLOR_ALPHA;
float opacity = GetEffectiveOpacity();
gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode();
@ -158,54 +148,6 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
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())
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>
BasicLayerManager::CreateThebesLayer()
{

View File

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