Bug 539356 - Part 8b - Move painting of retained layers to the view manager flush, and only composite on the paint event. r=roc

* * *
Fix Empty transactions with the new paint timing
This commit is contained in:
Matt Woodrow 2012-08-13 22:10:10 +12:00
parent 8e8f866f65
commit 2ebb996f8c
19 changed files with 102 additions and 53 deletions

View File

@ -181,6 +181,13 @@ public:
* EndTransaction returns.
*/
virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
enum EndTransactionFlags {
END_DEFAULT = 0,
END_NO_IMMEDIATE_REDRAW = 1 << 0, // Do not perform the drawing phase
END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
};
/**
* Attempts to end an "empty transaction". There must have been no
* changes to the layer tree since the BeginTransaction().
@ -189,7 +196,7 @@ public:
* returns false, and the caller must proceed with a normal layer tree
* update and EndTransaction.
*/
virtual bool EndEmptyTransaction() = 0;
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) = 0;
/**
* Function called to draw the contents of each ThebesLayer.
@ -223,12 +230,6 @@ public:
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);
enum EndTransactionFlags {
END_DEFAULT = 0,
END_NO_IMMEDIATE_REDRAW = 1 << 0, // Do not perform the drawing phase
END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
};
/**
* Finish the construction phase of the transaction, perform the
* drawing phase, and end the transaction.
@ -240,6 +241,9 @@ public:
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) = 0;
virtual bool HasShadowManagerInternal() const { return false; }
bool HasShadowManager() const { return HasShadowManagerInternal(); }
bool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; }
/**

View File

@ -524,13 +524,13 @@ BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
}
bool
BasicLayerManager::EndEmptyTransaction()
BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
{
if (!mRoot) {
return false;
}
return EndTransactionInternal(nullptr, nullptr);
return EndTransactionInternal(nullptr, nullptr, aFlags);
}
void
@ -1055,9 +1055,9 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
}
bool
BasicShadowLayerManager::EndEmptyTransaction()
BasicShadowLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
{
if (!BasicLayerManager::EndEmptyTransaction()) {
if (!BasicLayerManager::EndEmptyTransaction(aFlags)) {
// Return without calling ForwardTransaction. This leaves the
// ShadowLayerForwarder transaction open; the following
// EndTransaction will complete it.

View File

@ -87,7 +87,7 @@ public:
virtual void BeginTransaction();
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
virtual bool EndEmptyTransaction();
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT);
@ -150,8 +150,6 @@ public:
void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
virtual bool IsCompositingCheap() { return false; }
virtual bool HasShadowManagerInternal() const { return false; }
bool HasShadowManager() const { return HasShadowManagerInternal(); }
virtual PRInt32 GetMaxTextureSize() const { return PR_INT32_MAX; }
protected:
@ -221,7 +219,7 @@ public:
virtual void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering,
ScreenRotation aRotation) MOZ_OVERRIDE;
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
virtual bool EndEmptyTransaction();
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT);

View File

@ -200,7 +200,7 @@ LayerManagerD3D10::Initialize(bool force)
mInputLayout = attachments->mInputLayout;
}
if (HasShadowManager()) {
if (ShadowLayerForwarder::HasShadowManager()) {
reporter.SetSuccessful();
return true;
}
@ -335,12 +335,12 @@ LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget)
}
bool
LayerManagerD3D10::EndEmptyTransaction()
LayerManagerD3D10::EndEmptyTransaction(EndTransactionFlags aFlags)
{
if (!mRoot)
return false;
EndTransaction(nullptr, nullptr);
EndTransaction(nullptr, nullptr, aFlags);
return true;
}

View File

@ -85,7 +85,7 @@ public:
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
virtual bool EndEmptyTransaction();
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
struct CallbackInfo {
DrawThebesLayerCallback Callback;

View File

@ -121,7 +121,7 @@ LayerManagerD3D9::EndConstruction()
}
bool
LayerManagerD3D9::EndEmptyTransaction()
LayerManagerD3D9::EndEmptyTransaction(EndTransactionFlags aFlags)
{
// If the device reset count from our last EndTransaction doesn't match
// the current device reset count, the device must have been reset one or
@ -130,7 +130,7 @@ LayerManagerD3D9::EndEmptyTransaction()
if (!mRoot || mDeviceResetCount != mDeviceManager->GetDeviceResetCount())
return false;
EndTransaction(nullptr, nullptr);
EndTransaction(nullptr, nullptr, aFlags);
return true;
}

View File

@ -98,7 +98,7 @@ public:
void EndConstruction();
virtual bool EndEmptyTransaction();
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
struct CallbackInfo {
DrawThebesLayerCallback Callback;

View File

@ -380,12 +380,12 @@ LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
}
bool
LayerManagerOGL::EndEmptyTransaction()
LayerManagerOGL::EndEmptyTransaction(EndTransactionFlags aFlags)
{
if (!mRoot)
return false;
EndTransaction(nullptr, nullptr);
EndTransaction(nullptr, nullptr, aFlags);
return true;
}

View File

@ -102,7 +102,7 @@ public:
void EndConstruction();
virtual bool EndEmptyTransaction();
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT);

View File

@ -1037,7 +1037,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
layerBuilder->WillEndTransaction(layerManager);
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
aBuilder);
aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT);
aBuilder->SetIsCompositingCheap(temp);
layerBuilder->DidEndTransaction(layerManager);

View File

@ -24,6 +24,7 @@
#include "FrameLayerBuilder.h"
#include "nsThemeConstants.h"
#include "ImageLayers.h"
#include "nsLayoutUtils.h"
#include "mozilla/StandardInteger.h"
@ -1177,7 +1178,8 @@ public:
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_FLUSH_LAYERS = 0x02,
PAINT_EXISTING_TRANSACTION = 0x04
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_NO_COMPOSITE = 0x08
};
void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
PRUint32 aFlags) const;

View File

@ -1217,9 +1217,12 @@ public:
*/
virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
bool aWillSendDidPaint) = 0;
enum PaintType {
PaintType_Composite,
PaintType_NoComposite
};
virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
PaintType aType, bool aWillSendDidPaint) = 0;
virtual nsresult HandleEvent(nsIFrame* aFrame,
nsGUIEvent* aEvent,
bool aDontRetargetEvents,

View File

@ -1861,6 +1861,9 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
if (aFlags & PAINT_EXISTING_TRANSACTION) {
flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
}
if (aFlags & PAINT_NO_COMPOSITE) {
flags |= nsDisplayList::PAINT_NO_COMPOSITE;
}
list.PaintRoot(&builder, aRenderingContext, flags);

View File

@ -598,7 +598,8 @@ public:
PAINT_HIDE_CARET = 0x20,
PAINT_ALL_CONTINUATIONS = 0x40,
PAINT_TO_WINDOW = 0x80,
PAINT_EXISTING_TRANSACTION = 0x100
PAINT_EXISTING_TRANSACTION = 0x100,
PAINT_NO_COMPOSITE = 0x200
};
/**

View File

@ -5249,9 +5249,8 @@ private:
void
PresShell::Paint(nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
const nsIntRegion& aIntDirtyRegion,
PaintType aType,
bool aWillSendDidPaint)
{
#ifdef NS_FUNCTION_TIMER
@ -5268,7 +5267,6 @@ PresShell::Paint(nsIView* aViewToPaint,
SAMPLE_LABEL("Paint", "PresShell::Paint");
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aViewToPaint, "null view");
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
nsAutoNotifyDidPaint notifyDidPaint(aWillSendDidPaint);
@ -5279,14 +5277,13 @@ PresShell::Paint(nsIView* aViewToPaint,
bool isRetainingManager;
LayerManager* layerManager =
aWidgetToPaint->GetLayerManager(&isRetainingManager);
aViewToPaint->GetWidget()->GetLayerManager(&isRetainingManager);
NS_ASSERTION(layerManager, "Must be in paint event");
if (mIsFirstPaint) {
layerManager->SetIsFirstPaint();
mIsFirstPaint = false;
}
layerManager->BeginTransaction();
if (frame && isRetainingManager) {
// Try to do an empty transaction, if the frame tree does not
@ -5295,21 +5292,39 @@ PresShell::Paint(nsIView* aViewToPaint,
// draws the window title bar on Mac), because a) it won't work
// and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
// that will cause us to forget to update the real layer manager!
if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
if (aType == PaintType_Composite) {
if (layerManager->HasShadowManager()) {
return;
}
layerManager->BeginTransaction();
if (layerManager->EndEmptyTransaction()) {
return;
}
NS_WARNING("Must complete empty transaction when compositing!");
} else if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
layerManager->BeginTransaction();
if (layerManager->EndEmptyTransaction(LayerManager::END_NO_COMPOSITE)) {
frame->UpdatePaintCountForPaintedPresShells();
presContext->NotifyDidPaintForSubtree();
return;
}
} else {
layerManager->BeginTransaction();
}
frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
} else {
layerManager->BeginTransaction();
}
if (frame) {
frame->ClearPresShellsFromLastPaint();
}
nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
PRUint32 flags = nsLayoutUtils::PAINT_WIDGET_LAYERS | nsLayoutUtils::PAINT_EXISTING_TRANSACTION;
if (aType == PaintType_NoComposite) {
flags |= nsLayoutUtils::PAINT_NO_COMPOSITE;
}
if (frame) {
// Defer invalidates that are triggered during painting, and discard
@ -5319,12 +5334,12 @@ PresShell::Paint(nsIView* aViewToPaint,
frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
// We can paint directly into the widget using its layer manager.
nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
nsLayoutUtils::PAINT_WIDGET_LAYERS |
nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags);
frame->EndDeferringInvalidatesForDisplayRoot();
presContext->NotifyDidPaintForSubtree();
if (aType != PaintType_Composite) {
presContext->NotifyDidPaintForSubtree();
}
return;
}
@ -5338,9 +5353,13 @@ PresShell::Paint(nsIView* aViewToPaint,
root->SetVisibleRegion(bounds);
layerManager->SetRoot(root);
}
layerManager->EndTransaction(NULL, NULL);
layerManager->EndTransaction(NULL, NULL, aType == PaintType_NoComposite ?
LayerManager::END_NO_COMPOSITE :
LayerManager::END_DEFAULT);
presContext->NotifyDidPaintForSubtree();
if (aType != PaintType_Composite) {
presContext->NotifyDidPaintForSubtree();
}
}
// static

View File

@ -184,9 +184,8 @@ public:
//nsIViewObserver interface
virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
bool aWillSendDidPaint);
virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
PaintType aType, bool aWillSendDidPaint);
virtual nsresult HandleEvent(nsIFrame* aFrame,
nsGUIEvent* aEvent,
bool aDontRetargetEvents,

View File

@ -414,8 +414,14 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
}
if (mViewManagerFlushIsPending) {
#ifdef DEBUG_INVALIDATIONS
printf("Starting ProcessPendingUpdates\n");
#endif
mViewManagerFlushIsPending = false;
mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
#ifdef DEBUG_INVALIDATIONS
printf("Ending ProcessPendingUpdates\n");
#endif
}
if (mThrottled ||

View File

@ -298,11 +298,9 @@ nsIView* nsIViewManager::GetDisplayRootFor(nsIView* aView)
aContext may be null, in which case layers should be used for
rendering.
*/
void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
const nsIntRegion& aRegion,
void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
bool aWillSendDidPaint)
{
NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
// damageRegion is the damaged area, in twips, relative to the view origin
@ -335,8 +333,14 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
"Widgets that we paint must all be display roots");
if (mPresShell) {
mPresShell->Paint(aView, aWidget, damageRegion, aRegion,
#ifdef DEBUG_INVALIDATIONS
printf("--COMPOSITE-- %p\n", mPresShell);
#endif
mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Composite,
aWillSendDidPaint);
#ifdef DEBUG_INVALIDATIONS
printf("--ENDCOMPOSITE--\n");
#endif
mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
}
@ -372,6 +376,17 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
// Push out updates after we've processed the children; ensures that
// damage is applied based on the final widget geometry
if (aFlushDirtyRegion) {
nsIWidget *widget = aView->GetWidget();
if (widget) {
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
#endif
nsAutoScriptBlocker scriptBlocker;
mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, false);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT END ----\n");
#endif
}
FlushDirtyRegionToWidget(aView);
}
}
@ -760,7 +775,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
break;
// Paint.
Refresh(view, event->widget, event->region, event->willSendDidPaint);
Refresh(view, event->region, event->willSendDidPaint);
break;
}

View File

@ -129,8 +129,7 @@ private:
void InvalidateViews(nsView *aView);
// aView is the view for aWidget and aRegion is relative to aWidget.
void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion,
bool aWillSendDidPaint);
void Refresh(nsView *aView, const nsIntRegion& aRegion, bool aWillSendDidPaint);
void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut);
void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,