Bug 1257641 - Use empty transactions to carry scroll offset updates to APZ that don't require a repaint. r=mattwoodrow,mstange,botond

MozReview-Commit-ID: KNeGSKldmp7
This commit is contained in:
Kartikaya Gupta
2016-04-13 10:21:13 -04:00
parent dae38a48d5
commit c3335edd95
6 changed files with 89 additions and 7 deletions

View File

@@ -26,6 +26,15 @@ template <typename T> struct ParamTraits;
namespace mozilla {
namespace layers {
/**
* Helper struct to hold a couple of fields that can be updated as part of
* an empty transaction.
*/
struct ScrollUpdateInfo {
uint32_t mScrollGeneration;
CSSPoint mScrollOffset;
};
/**
* The viewport and displayport metrics for the painted frame at the
* time of a layer-tree transaction. These metrics are especially
@@ -44,6 +53,9 @@ public:
enum ScrollOffsetUpdateType : uint8_t {
eNone, // The default; the scroll offset was not updated
eMainThread, // The scroll offset was updated by the main thread.
ePending, // The scroll offset was updated on the main thread, but not
// painted, so the layer texture data is still at the old
// offset.
eSentinel // For IPC use only
};
@@ -241,6 +253,13 @@ public:
mDoSmoothScroll = aOther.mDoSmoothScroll;
}
void UpdatePendingScrollInfo(const ScrollUpdateInfo& aInfo)
{
mScrollOffset = aInfo.mScrollOffset;
mScrollGeneration = aInfo.mScrollGeneration;
mScrollUpdateType = ePending;
}
void UpdateScrollInfo(uint32_t aScrollGeneration, const CSSPoint& aScrollOffset)
{
mScrollOffset = aScrollOffset;
@@ -380,6 +399,11 @@ public:
mScrollGeneration = aScrollGeneration;
}
ScrollOffsetUpdateType GetScrollUpdateType() const
{
return mScrollUpdateType;
}
bool GetScrollOffsetUpdated() const
{
return mScrollUpdateType != eNone;

View File

@@ -567,6 +567,11 @@ Layer::ApplyPendingUpdatesToSubtree()
for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
child->ApplyPendingUpdatesToSubtree();
}
if (!GetParent()) {
// Once we're done recursing through the whole tree, clear the pending
// updates from the manager.
Manager()->ClearPendingScrollInfoUpdate();
}
}
bool
@@ -946,6 +951,15 @@ Layer::ApplyPendingUpdatesForThisTransaction()
mPendingAnimations = nullptr;
Mutated();
}
for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
FrameMetrics& fm = mScrollMetadata[i].GetMetrics();
Maybe<ScrollUpdateInfo> update = Manager()->GetPendingScrollInfoUpdate(fm.GetScrollId());
if (update) {
fm.UpdatePendingScrollInfo(update.value());
Mutated();
}
}
}
float
@@ -2446,6 +2460,29 @@ LayerManager::IsLogEnabled()
return MOZ_LOG_TEST(GetLog(), LogLevel::Debug);
}
void
LayerManager::SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
const ScrollUpdateInfo& aUpdateInfo)
{
mPendingScrollUpdates[aScrollId] = aUpdateInfo;
}
Maybe<ScrollUpdateInfo>
LayerManager::GetPendingScrollInfoUpdate(FrameMetrics::ViewID aScrollId)
{
auto it = mPendingScrollUpdates.find(aScrollId);
if (it != mPendingScrollUpdates.end()) {
return Some(it->second);
}
return Nothing();
}
void
LayerManager::ClearPendingScrollInfoUpdate()
{
mPendingScrollUpdates.clear();
}
void
PrintInfo(std::stringstream& aStream, LayerComposite* aLayerComposite)
{

View File

@@ -6,6 +6,7 @@
#ifndef GFX_LAYERS_H
#define GFX_LAYERS_H
#include <map>
#include <stdint.h> // for uint32_t, uint64_t, uint8_t
#include <stdio.h> // for FILE
#include <sys/types.h> // for int32_t, int64_t
@@ -698,6 +699,19 @@ private:
FramesTimingRecording mRecording;
TimeStamp mTabSwitchStart;
public:
/*
* Methods to store/get/clear a "pending scroll info update" object on a
* per-scrollid basis. This is used for empty transactions that push over
* scroll position updates to the APZ code.
*/
void SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
const ScrollUpdateInfo& aUpdateInfo);
Maybe<ScrollUpdateInfo> GetPendingScrollInfoUpdate(FrameMetrics::ViewID aScrollId);
void ClearPendingScrollInfoUpdate();
private:
std::map<FrameMetrics::ViewID,ScrollUpdateInfo> mPendingScrollUpdates;
};
typedef InfallibleTArray<Animation> AnimationArray;
@@ -857,6 +871,7 @@ public:
*/
void SetScrollMetadata(const ScrollMetadata& aScrollMetadata)
{
Manager()->ClearPendingScrollInfoUpdate();
if (mScrollMetadata.Length() != 1 || mScrollMetadata[0] != aScrollMetadata) {
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
mScrollMetadata.ReplaceElementsAt(0, mScrollMetadata.Length(), aScrollMetadata);
@@ -884,6 +899,7 @@ public:
*/
void SetScrollMetadata(const nsTArray<ScrollMetadata>& aMetadataArray)
{
Manager()->ClearPendingScrollInfoUpdate();
if (mScrollMetadata != aMetadataArray) {
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
mScrollMetadata = aMetadataArray;

View File

@@ -191,7 +191,7 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
AppendToString(aStream, m.GetZoom(), " z=");
AppendToString(aStream, m.GetExtraResolution(), " er=");
aStream << nsPrintfCString(")] [u=(%d %d %lu)",
m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(),
m.GetScrollUpdateType(), m.GetDoSmoothScroll(),
m.GetScrollGeneration()).get();
AppendToString(aStream, m.GetScrollParentId(), "] [p=");
aStream << nsPrintfCString("] [i=(%ld %lld %d)] }",

View File

@@ -3388,7 +3388,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
APZC_LOG("%p NotifyLayersUpdated short-circuit\n", this);
return;
}
mLastContentPaintMetrics = aLayerMetrics;
if (aLayerMetrics.GetScrollUpdateType() != FrameMetrics::ScrollOffsetUpdateType::ePending) {
mLastContentPaintMetrics = aLayerMetrics;
}
mFrameMetrics.SetScrollParentId(aLayerMetrics.GetScrollParentId());
APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d, aThisLayerTreeUpdated=%d",

View File

@@ -66,7 +66,6 @@
#include <mozilla/layers/AxisPhysicsMSDModel.h>
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/ScrollLinkedEffectDetector.h"
#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/unused.h"
#include "LayersLogging.h" // for Stringify
#include <algorithm>
@@ -2752,14 +2751,18 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
!content->GetComposedDoc()->HasScrollLinkedEffect()) {
nsIWidget* widget = presContext->GetNearestWidget();
LayerManager* manager = widget ? widget->GetLayerManager() : nullptr;
ShadowLayerForwarder* forwarder = manager ? manager->AsShadowForwarder() : nullptr;
if (forwarder && forwarder->HasShadowManager()) {
if (manager) {
mozilla::layers::FrameMetrics::ViewID id;
DebugOnly<bool> success = nsLayoutUtils::FindIDFor(content, &id);
MOZ_ASSERT(success); // we have a displayport, we better have an ID
forwarder->GetShadowManager()->SendUpdateScrollOffset(id,
mScrollGeneration, CSSPoint::FromAppUnits(GetScrollPosition()));
// Schedule an empty transaction to carry over the scroll offset update,
// instead of a full transaction. This empty transaction might still get
// squashed into a full transaction if something happens to trigger one.
schedulePaint = false;
manager->SetPendingScrollUpdateForNextTransaction(id,
{ mScrollGeneration, CSSPoint::FromAppUnits(GetScrollPosition()) });
mOuter->SchedulePaint(nsIFrame::PAINT_COMPOSITE_ONLY);
PAINT_SKIP_LOG("Skipping due to APZ-forwarded main-thread scroll\n");
}
}