Bug 1429932 - Part 6: Attempt to skip Layer building if the display list hasn't changed. r=mstange
MozReview-Commit-ID: 1kBRIVteNb1
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3948,16 +3948,19 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
}
if (aFlags & PaintFrameFlags::PAINT_NO_COMPOSITE) {
flags |= nsDisplayList::PAINT_NO_COMPOSITE;
}
if (aFlags & PaintFrameFlags::PAINT_COMPRESSED) {
flags |= nsDisplayList::PAINT_COMPRESSED;
}
+ if (updateState == PartialUpdateResult::NoChange) {
+ flags |= nsDisplayList::PAINT_IDENTICAL_DISPLAY_LIST;
+ }
TimeStamp paintStart = TimeStamp::Now();
RefPtr<LayerManager> layerManager
= list.PaintRoot(&builder, aRenderingContext, flags);
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_RASTERIZE_TIME,
paintStart);
builder.Check();
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2586,67 +2586,77 @@ already_AddRefed<LayerManager> nsDisplay
}
} else {
if (!layerManager->BeginTransaction()) {
return nullptr;
}
}
}
- // Store the existing layer builder to reinstate it on return.
- FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
- FrameLayerBuilder *layerBuilder = BuildLayers(aBuilder, layerManager,
- aFlags, widgetTransaction);
-
- if (!layerBuilder) {
- layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
- return nullptr;
- }
-
- if (widgetTransaction ||
- // SVG-as-an-image docs don't paint as part of the retained layer tree,
- // but they still need the invalidation state bits cleared in order for
- // invalidation for CSS/SMIL animation to work properly.
- (document && document->IsBeingUsedAsImage())) {
- frame->ClearInvalidationStateBits();
- }
-
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT;
if (layerManager->NeedsWidgetInvalidation()) {
if (aFlags & PAINT_NO_COMPOSITE) {
flags = LayerManager::END_NO_COMPOSITE;
}
} else {
// Client layer managers never composite directly, so
// we don't need to worry about END_NO_COMPOSITE.
if (aBuilder->WillComputePluginGeometry()) {
flags = LayerManager::END_NO_REMOTE_COMPOSITE;
}
}
- // If this is the content process, we ship plugin geometry updates over with layer
- // updates, so calculate that now before we call EndTransaction.
- nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
- if (rootPresContext && XRE_IsContentProcess()) {
- if (aBuilder->WillComputePluginGeometry()) {
- rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
- }
- // The layer system caches plugin configuration information for forwarding
- // with layer updates which needs to get set during reflow. This must be
- // called even if there are no windowed plugins in the page.
- rootPresContext->CollectPluginGeometryUpdates(layerManager);
- }
-
MaybeSetupTransactionIdAllocator(layerManager, presContext);
- layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
- aBuilder, flags);
+ // Store the existing layer builder to reinstate it on return.
+ FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
+ FrameLayerBuilder *layerBuilder = nullptr;
+
+ bool sent = false;
+ if (aFlags & PAINT_IDENTICAL_DISPLAY_LIST) {
+ sent = layerManager->EndEmptyTransaction(flags);
+ }
+
+ if (!sent) {
+ layerBuilder = BuildLayers(aBuilder, layerManager,
+ aFlags, widgetTransaction);
+
+ if (!layerBuilder) {
+ layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
+ return nullptr;
+ }
+
+ // If this is the content process, we ship plugin geometry updates over with layer
+ // updates, so calculate that now before we call EndTransaction.
+ nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
+ if (rootPresContext && XRE_IsContentProcess()) {
+ if (aBuilder->WillComputePluginGeometry()) {
+ rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
+ }
+ // The layer system caches plugin configuration information for forwarding
+ // with layer updates which needs to get set during reflow. This must be
+ // called even if there are no windowed plugins in the page.
+ rootPresContext->CollectPluginGeometryUpdates(layerManager);
+ }
+
+ layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
+ aBuilder, flags);
+ layerBuilder->DidEndTransaction();
+ }
+
+ if (widgetTransaction ||
+ // SVG-as-an-image docs don't paint as part of the retained layer tree,
+ // but they still need the invalidation state bits cleared in order for
+ // invalidation for CSS/SMIL animation to work properly.
+ (document && document->IsBeingUsedAsImage())) {
+ frame->ClearInvalidationStateBits();
+ }
+
aBuilder->SetIsCompositingCheap(temp);
- layerBuilder->DidEndTransaction();
if (document && widgetTransaction) {
TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
}
nsIntRegion invalid;
bool areaOverflowed = false;
if (props) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3027,17 +3027,18 @@ public:
* We return the layer manager used for painting --- mainly so that
* callers can dump its layer tree if necessary.
*/
enum {
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_NO_COMPOSITE = 0x08,
- PAINT_COMPRESSED = 0x10
+ PAINT_COMPRESSED = 0x10,
+ PAINT_IDENTICAL_DISPLAY_LIST = 0x20
};
already_AddRefed<LayerManager> PaintRoot(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx,
uint32_t aFlags);
mozilla::FrameLayerBuilder* BuildLayers(nsDisplayListBuilder* aBuilder,
LayerManager* aLayerManager,
uint32_t aFlags,