# HG changeset patch # Parent 6b9fcd51adc138e2fdcb87e951effae8a0e7d022 Bug 1077651. Measure frame uniformity by synthesizing native events. r=kats diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3685,16 +3685,34 @@ nsDOMWindowUtils::SetChromeMargin(int32_ } } } return NS_OK; } NS_IMETHODIMP +nsDOMWindowUtils::GetFrameUniformity(int32_t aX, int32_t aY, float* aFrameUniformity) +{ + nsIWidget* widget = GetWidget(); + if (!widget) { + return NS_ERROR_NOT_AVAILABLE; + } + + LayerManager* manager = widget->GetLayerManager(); + if (!manager) { + return NS_ERROR_NOT_AVAILABLE; + } + + ScreenIntPoint touchPoint(aX, aY); + *aFrameUniformity = manager->GetFrameUniformity(touchPoint); + return NS_OK; +} + +NS_IMETHODIMP nsDOMWindowUtils::XpconnectArgument(nsIDOMWindowUtils* aThis) { // Do nothing. return NS_OK; } NS_IMETHODIMP nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -46,17 +46,17 @@ interface nsIDOMClientRect; interface nsIURI; interface nsIDOMEventTarget; interface nsIRunnable; interface nsITranslationNodeList; interface nsIJSRAIIHelper; interface nsIContentPermissionRequest; interface nsIObserver; -[scriptable, uuid(1a75c351-d115-4d51-94df-731dd1723a1f)] +[scriptable, uuid(4A438E29-5196-4EAD-B190-E2D40884510C)] interface nsIDOMWindowUtils : nsISupports { /** * Image animation mode of the window. When this attribute's value * is changed, the implementation should set all images in the window * to the given value. That is, when set to kDontAnimMode, all images * will stop animating. The attribute's value must be one of the * animationMode values from imgIContainer. @@ -1802,16 +1802,25 @@ interface nsIDOMWindowUtils : nsISupport in int32_t aRight, in int32_t aBottom, in int32_t aLeft); /** * Enable some service workers testing features. */ attribute boolean serviceWorkersTestingEnabled; + + /** + * Returns the frame uniformity of the Y axis on a scroll which is computed + * when the pref gfx.vsync.collect-scroll-data is enabled. + * The x,y coordinates passed are used to identify the layer + * whose frame uniformity is returned. A negative value indicates + * an invalid frame uniformity and an error has occured. + */ + float getFrameUniformity(in int32_t aX, in int32_t aY); }; [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)] interface nsITranslationNodeList : nsISupports { readonly attribute unsigned long length; nsIDOMNode item(in unsigned long index); // A translation root is a block element, or an inline element diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -639,16 +639,17 @@ public: // LayersBackend::LAYERS_NONE is an error state, but in that case we should try to // avoid loading the compositor! return LayersBackend::LAYERS_BASIC != aBackend && LayersBackend::LAYERS_NONE != aBackend; } virtual bool IsCompositingCheap() { return true; } bool IsInTransaction() const { return mInTransaction; } + virtual float GetFrameUniformity(const ScreenIntPoint& aTouchPoint) { return -1; } virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) { return true; } virtual void RunOverfillCallback(const uint32_t aOverfill) { } virtual void SetRegionToClear(const nsIntRegion& aRegion) { mRegionToClear = aRegion; } diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -1249,16 +1249,25 @@ APZCTreeManager::GetTargetAPZC(const Scr { MonitorAutoLock lock(mTreeLock); nsRefPtr node = GetTargetNode(aGuid, nullptr); MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC nsRefPtr apzc = node ? node->GetApzc() : nullptr; return apzc.forget(); } +void +APZCTreeManager::GetScrollableLayerGuid(const ScreenPoint& aPoint, ScrollableLayerGuid& aGuid) +{ + nsRefPtr apzc = GetTargetAPZC(aPoint, nullptr); + if (apzc) { + aGuid = apzc->GetGuid(); + } +} + already_AddRefed APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid, GuidComparator aComparator) { mTreeLock.AssertCurrentThreadOwns(); nsRefPtr target = FindTargetNode(mRootNode, aGuid, aComparator); return target.forget(); } diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -391,16 +391,17 @@ public: about it going away. These are public for testing code and generally should not be used by other production code. */ nsRefPtr GetRootNode() const; already_AddRefed GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult); gfx::Matrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const; gfx::Matrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const; + void GetScrollableLayerGuid(const ScreenPoint& aPoint, ScrollableLayerGuid& aGuid); private: typedef bool (*GuidComparator)(const ScrollableLayerGuid&, const ScrollableLayerGuid&); /* Helpers */ void AttachNodeToTree(HitTestingTreeNode* aNode, HitTestingTreeNode* aParent, HitTestingTreeNode* aNextSibling); already_AddRefed GetTargetAPZC(const ScrollableLayerGuid& aGuid); diff --git a/gfx/layers/apz/test/chrome.ini b/gfx/layers/apz/test/chrome.ini new file mode 100644 --- /dev/null +++ b/gfx/layers/apz/test/chrome.ini @@ -0,0 +1,7 @@ +[DEFAULT] +support-files = + apz_test_native_event_utils.js +tags = apz-chrome + +[test_smoothness.html] +skip-if = debug || (os != 'mac' && os != 'win') # hardware vsync only on win/mac diff --git a/gfx/layers/apz/test/test_smoothness.html b/gfx/layers/apz/test/test_smoothness.html new file mode 100644 --- /dev/null +++ b/gfx/layers/apz/test/test_smoothness.html @@ -0,0 +1,71 @@ + + + Test Frame Uniformity While Scrolling + + + + + + + + + +
+
+ + diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -421,16 +421,31 @@ ClientLayerManager::RequestProperty(cons void ClientLayerManager::StartNewRepaintRequest(SequenceNumber aSequenceNumber) { if (gfxPrefs::APZTestLoggingEnabled()) { mApzTestData.StartNewRepaintRequest(aSequenceNumber); } } +float +ClientLayerManager::GetFrameUniformity(const ScreenIntPoint& aTouchPoint) +{ + MOZ_ASSERT(XRE_IsParentProcess(), "Frame Uniformity only supported in parent process"); + + if (HasShadowManager()) { + CompositorChild* child = GetRemoteRenderer(); + float frameUniformity = -1; + child->SendGetFrameUniformity(aTouchPoint, &frameUniformity); + return frameUniformity; + } + + return LayerManager::GetFrameUniformity(aTouchPoint); +} + bool ClientLayerManager::RequestOverfill(mozilla::dom::OverfillCallback* aCallback) { MOZ_ASSERT(aCallback != nullptr); MOZ_ASSERT(HasShadowManager(), "Request Overfill only supported on b2g for now"); if (HasShadowManager()) { CompositorChild* child = GetRemoteRenderer(); diff --git a/gfx/layers/client/ClientLayerManager.h b/gfx/layers/client/ClientLayerManager.h --- a/gfx/layers/client/ClientLayerManager.h +++ b/gfx/layers/client/ClientLayerManager.h @@ -195,16 +195,17 @@ public: void SetNeedsComposite(bool aNeedsComposite) { mNeedsComposite = aNeedsComposite; } bool NeedsComposite() const { return mNeedsComposite; } virtual void Composite() override; + virtual float GetFrameUniformity(const ScreenIntPoint& aTouchPoint) override; virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) override; virtual void RunOverfillCallback(const uint32_t aOverfill) override; virtual void DidComposite(uint64_t aTransactionId); virtual bool SupportsMixBlendModes(EnumSet& aMixBlendModes) override { return (GetTextureFactoryIdentifier().mSupportedBlendModes & aMixBlendModes) == aMixBlendModes; diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -32,16 +32,17 @@ #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc #include "nsTArrayForwardDeclare.h" // for InfallibleTArray #include "UnitTransforms.h" // for TransformTo #if defined(MOZ_WIDGET_ANDROID) # include # include "AndroidBridge.h" #endif #include "GeckoProfiler.h" +#include "ScrollData.h" struct nsCSSValueSharedList; namespace mozilla { namespace layers { using namespace mozilla::gfx; @@ -89,16 +90,30 @@ WalkTheTree(Layer* aLayer, } } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { WalkTheTree(child, aReady, aTargetConfig); } } +AsyncCompositionManager::AsyncCompositionManager(LayerManagerComposite* aManager) + : mLayerManager(aManager) + , mIsFirstPaint(true) + , mLayersUpdated(false) + , mReadyForCompose(true) + , mScrollMeasurements(new ScrollData()) +{ +} + +AsyncCompositionManager::~AsyncCompositionManager() +{ + mScrollMeasurements = nullptr; +} + void AsyncCompositionManager::ResolveRefLayers() { if (!mLayerManager->GetRoot()) { return; } mReadyForCompose = true; @@ -525,31 +540,56 @@ SampleAnimations(Layer* aLayer, TimeStam child = child->GetNextSibling()) { activeAnimations |= SampleAnimations(child, aPoint); } return activeAnimations; } static bool -SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime) +SampleAPZAnimations(const LayerMetricsWrapper& aLayer, + TimeStamp aSampleTime) { bool activeAnimations = false; for (LayerMetricsWrapper child = aLayer.GetFirstChild(); child; child = child.GetNextSibling()) { activeAnimations |= SampleAPZAnimations(child, aSampleTime); } if (AsyncPanZoomController* apzc = aLayer.GetApzc()) { activeAnimations |= apzc->AdvanceAnimations(aSampleTime); } return activeAnimations; } +void +AsyncCompositionManager::RecordShadowTransforms(Layer* aLayer) +{ + MOZ_ASSERT(gfxPrefs::CollectScrollData()); + + for (Layer* child = aLayer->GetFirstChild(); + child; child = child->GetNextSibling()) { + RecordShadowTransforms(child); + } + + for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + AsyncPanZoomController* apzc = aLayer->GetAsyncPanZoomController(i); + if (!apzc) { + continue; + } + gfx::Matrix4x4 shadowTransform = aLayer->AsLayerComposite()->GetShadowTransform(); + if (shadowTransform.Is2DIntegerTranslation() && !shadowTransform.IsIdentity()) { + ScrollableLayerGuid scrollGuid = apzc->GetGuid(); + Point transform = shadowTransform.As2D().GetTranslation(); + mScrollMeasurements->AddMeasurement(scrollGuid, transform); + } + } +} + Matrix4x4 AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer) { Matrix4x4 result = asyncTransform; // Container layers start at the origin, but they are clipped to where they // actually have content on the screen. The tree transform is meant to apply // to the clipped area. If the tree transform includes a scale component, @@ -1037,16 +1077,22 @@ AsyncCompositionManager::TransformScroll oldTransform.PreScale(underZoomScale.width, underZoomScale.height, 1); // Make sure fixed position layers don't move away from their anchor points // when we're asynchronously panning or zooming AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform, aLayer->GetLocalTransform(), fixedLayerMargins); } +float +AsyncCompositionManager::GetFrameUniformity(ScrollableLayerGuid& aScrollLayer) +{ + return mScrollMeasurements->EndTest(aScrollLayer); +} + bool AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame, TransformsToSkip aSkip) { PROFILER_LABEL("AsyncCompositionManager", "TransformShadowTree", js::ProfileEntry::Category::GRAPHICS); Layer* root = mLayerManager->GetRoot(); @@ -1089,16 +1135,19 @@ AsyncCompositionManager::TransformShadow } LayerComposite* rootComposite = root->AsLayerComposite(); gfx::Matrix4x4 trans = rootComposite->GetShadowTransform(); trans *= gfx::Matrix4x4::From2D(mWorldTransform); rootComposite->SetShadowTransform(trans); + if (gfxPrefs::CollectScrollData()) { + RecordShadowTransforms(root); + } return wantNextFrame; } void AsyncCompositionManager::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect) diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -19,16 +19,17 @@ #include "nsISupportsImpl.h" // for LayerManager::AddRef, etc namespace mozilla { namespace layers { class AsyncPanZoomController; class Layer; class LayerManagerComposite; +class ScrollData; class AutoResolveRefLayers; // Represents (affine) transforms that are calculated from a content view. struct ViewTransform { explicit ViewTransform(LayerToParentLayerScale aScale = LayerToParentLayerScale(), ParentLayerPoint aTranslation = ParentLayerPoint()) : mScale(aScale) , mTranslation(aTranslation) @@ -65,44 +66,38 @@ struct ViewTransform { * (LayerManagerComposite) which deals with elements of composition which are * usually dealt with by dom or layout when main thread rendering, but which can * short circuit that stuff to directly affect layers as they are composited, * for example, off-main thread animation, async video, async pan/zoom. */ class AsyncCompositionManager final { friend class AutoResolveRefLayers; - ~AsyncCompositionManager() - { - } + ~AsyncCompositionManager(); + public: NS_INLINE_DECL_REFCOUNTING(AsyncCompositionManager) - explicit AsyncCompositionManager(LayerManagerComposite* aManager) - : mLayerManager(aManager) - , mIsFirstPaint(true) - , mLayersUpdated(false) - , mReadyForCompose(true) - { - } + explicit AsyncCompositionManager(LayerManagerComposite* aManager); /** * This forces the is-first-paint flag to true. This is intended to * be called by the widget code when it loses its viewport information * (or for whatever reason wants to refresh the viewport information). * The information refresh happens because the compositor will call * SetFirstPaintViewport on the next frame of composition. */ void ForceIsFirstPaint() { mIsFirstPaint = true; } // Sample transforms for layer trees. Return true to request // another animation frame. enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 }; bool TransformShadowTree(TimeStamp aCurrentFrame, TransformsToSkip aSkip = TransformsToSkip::NoneOfThem); + void RecordShadowTransforms(Layer* aLayer); // Calculates the correct rotation and applies the transform to // our layer manager void ComputeRotation(); // Call after updating our layer tree. void Updated(bool isFirstPaint, const TargetConfig& aTargetConfig) { @@ -117,16 +112,17 @@ public: } // True if the underlying layer tree is ready to be composited. bool ReadyForCompose() { return mReadyForCompose; } // Returns true if the next composition will be the first for a // particular document. bool IsFirstPaint() { return mIsFirstPaint; } + float GetFrameUniformity(ScrollableLayerGuid& aScrollLayer); private: void TransformScrollableLayer(Layer* aLayer); // Return true if an AsyncPanZoomController content transform was // applied for |aLayer|. bool ApplyAsyncContentTransformToTree(Layer* aLayer); /** * Update the shadow transform for aLayer assuming that is a scrollbar, @@ -203,16 +199,17 @@ private: // This flag is set during a layers update, so that the first composition // after a layers update has it set. It is cleared after that first composition. bool mLayersUpdated; bool mReadyForCompose; gfx::Matrix mWorldTransform; + nsRefPtr mScrollMeasurements; }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AsyncCompositionManager::TransformsToSkip) class MOZ_STACK_CLASS AutoResolveRefLayers { public: explicit AutoResolveRefLayers(AsyncCompositionManager* aManager) : mManager(aManager) { diff --git a/gfx/layers/composite/ScrollData.cpp b/gfx/layers/composite/ScrollData.cpp new file mode 100644 --- /dev/null +++ b/gfx/layers/composite/ScrollData.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ScrollData.h" + +#include + +#include "gfxPoint.h" +#include "mozilla/TimeStamp.h" +#include "nsTArray.h" +#include "Units.h" // for ScreenPoint, etc + +namespace mozilla { +namespace layers { + +using namespace gfx; + +gfx::Point +LayerTransforms::GetAverage() +{ + MOZ_ASSERT(!mTransforms.IsEmpty()); + + Point current = mTransforms[0]; + Point average; + size_t length = mTransforms.Length(); + + for (size_t i = 1; i < length; i++) { + Point nextTransform = mTransforms[i]; + Point movement = nextTransform - current; + average += Point(std::fabs(movement.x), std::fabs(movement.y)); + current = nextTransform; + } + + average.x = average.y / (float) length; + average.y = average.y / (float) length; + return average; +} + +gfx::Point +LayerTransforms::GetStdDev() +{ + gfx::Point average = GetAverage(); + Point current = mTransforms[0]; + gfx::Point stdDev; + for (size_t i = 1; i < mTransforms.Length(); i++) { + gfx::Point next = mTransforms[i]; + gfx::Point move = next - current; + move.x = fabs(move.x); + move.y = fabs(move.y); + + double diffX = move.x - average.x; + diffX *= diffX; + + double diffY = move.y - average.y; + diffY *= diffY; + + stdDev.x += diffX; + stdDev.y += diffY; + + current = next; + } + + stdDev.x = stdDev.x / mTransforms.Length(); + stdDev.y = stdDev.y / mTransforms.Length(); + + stdDev.x = sqrt(stdDev.x); + stdDev.y = sqrt(stdDev.y); + return stdDev; +} + +ScrollData::~ScrollData() +{ + Reset(); +} + +void +ScrollData::AddMeasurement(ScrollableLayerGuid& aScrollId, Point aTransform) +{ + LayerTransforms* layerTransforms = GetLayerTransforms(aScrollId); + layerTransforms->mTransforms.AppendElement(aTransform); +} + +double +ScrollData::EndTest(ScrollableLayerGuid& aScrollLayer) +{ + double result = CalculateFrameUniformity(aScrollLayer); + Reset(); + return result; +} + +LayerTransforms* +ScrollData::GetLayerTransforms(ScrollableLayerGuid& aScrollLayerId) +{ + if (!mFrameTransforms.count(aScrollLayerId)) { + LayerTransforms* newTransform = new LayerTransforms(); + newTransform->mGuid = aScrollLayerId; + + std::pair newLayer(aScrollLayerId, newTransform); + mFrameTransforms.insert(newLayer); + } + + return mFrameTransforms.find(aScrollLayerId)->second; +} +void +ScrollData::Reset() +{ + std::map::iterator iter; + for (iter = mFrameTransforms.begin(); iter != mFrameTransforms.end(); ++iter) { + LayerTransforms* LayerTransforms = iter->second; + delete LayerTransforms; + } + + mFrameTransforms.clear(); +} + +double +ScrollData::CalculateFrameUniformity(ScrollableLayerGuid& aScrollLayerId) +{ + LayerTransforms* layerTransform = GetLayerTransforms(aScrollLayerId); + double yUniformity = -1; + if (!layerTransform->mTransforms.IsEmpty()) { + Point stdDev = layerTransform->GetStdDev(); + yUniformity = stdDev.y; + } + return yUniformity; +} + +} +} diff --git a/gfx/layers/composite/ScrollData.h b/gfx/layers/composite/ScrollData.h new file mode 100644 --- /dev/null +++ b/gfx/layers/composite/ScrollData.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_ScrollData_h_ +#define mozilla_layers_ScrollData_h_ + +#include "nsRefPtr.h" + +namespace mozilla { +namespace layers { + +struct LayerTransforms { + gfx::Point GetAverage(); + gfx::Point GetStdDev(); + + ScrollableLayerGuid mGuid; + // 60 fps * 5 seconds worth of data + nsAutoTArray mTransforms; +}; + +class ScrollData { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ScrollData); + +public: + ScrollData() {} + + void AddMeasurement(ScrollableLayerGuid& aGuid, gfx::Point aTransform); + void Reset(); + double EndTest(ScrollableLayerGuid& aScrollLayer); + protected: + ~ScrollData(); + +private: + double CalculateFrameUniformity(ScrollableLayerGuid& aScrollLayerId); + LayerTransforms* GetLayerTransforms(ScrollableLayerGuid& aLayerId); + std::map mFrameTransforms; +}; + +} +} + +#endif // mozilla_layers_ScrollData_h_ diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1313,16 +1313,25 @@ CompositorParent::ApplyAsyncProperties(L CancelCurrentCompositeTask(); // Pretend we composited in case someone is waiting for this event. DidComposite(); } } } bool +CompositorParent::RecvGetFrameUniformity(const ScreenIntPoint& aTouchPoint, float* aFrameUniformity) +{ + ScrollableLayerGuid scrollLayer; + mApzcTreeManager->GetScrollableLayerGuid(aTouchPoint, scrollLayer); + *aFrameUniformity = mCompositionManager->GetFrameUniformity(scrollLayer); + return true; +} + +bool CompositorParent::RecvRequestOverfill() { uint32_t overfillRatio = mCompositor->GetFillRatio(); unused << SendOverfill(overfillRatio); return true; } void @@ -1697,16 +1706,23 @@ public: virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray* intervals) override { return true; } virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override { *aWidth = gfxPlatform::GetPlatform()->GetTileWidth(); *aHeight = gfxPlatform::GetPlatform()->GetTileHeight(); return true; } + virtual bool RecvGetFrameUniformity(const ScreenIntPoint& aTouchPoint, float* aFrameUniformity) + { + // Don't support calculating frame uniformity on the child process and + // this is just a stub for now. + *aFrameUniformity = -1.0; + return true; + } /** * Tells this CompositorParent to send a message when the compositor has received the transaction. */ virtual bool RecvRequestNotifyAfterRemotePaint() override; virtual PLayerTransactionParent* AllocPLayerTransactionParent(const nsTArray& aBackendHints, diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -224,16 +224,17 @@ public: int aSurfaceWidth = -1, int aSurfaceHeight = -1); // IToplevelProtocol::CloneToplevel() virtual IToplevelProtocol* CloneToplevel(const InfallibleTArray& aFds, base::ProcessHandle aPeerProcess, mozilla::ipc::ProtocolCloneContext* aCtx) override; + virtual bool RecvGetFrameUniformity(const ScreenIntPoint& aTouchPoint, float* aFrameUniformity) override; virtual bool RecvRequestOverfill() override; virtual bool RecvWillStop() override; virtual bool RecvStop() override; virtual bool RecvPause() override; virtual bool RecvResume() override; virtual bool RecvNotifyChildCreated(const uint64_t& child) override; virtual bool RecvAdoptChild(const uint64_t& child) override; virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot, diff --git a/gfx/layers/ipc/PCompositor.ipdl b/gfx/layers/ipc/PCompositor.ipdl --- a/gfx/layers/ipc/PCompositor.ipdl +++ b/gfx/layers/ipc/PCompositor.ipdl @@ -13,16 +13,17 @@ include "nsRegion.h"; using struct mozilla::null_t from "ipc/IPCMessageUtils.h"; using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h"; using struct mozilla::layers::FrameMetrics from "FrameMetrics.h"; using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h"; using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h"; using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h"; using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h"; +using mozilla::ScreenIntPoint from "Units.h"; using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; namespace mozilla { namespace layers { /** * The PCompositor protocol is used to manage communication between @@ -69,16 +70,20 @@ child: * list of plugin window ids. */ async UpdatePluginVisibility(uintptr_t[] aVisibleIdList); parent: // Child sends the parent a request for fill ratio numbers. async RequestOverfill(); + // Child requests frame uniformity measurements + sync GetFrameUniformity(ScreenIntPoint aTouchPoint) + returns (float frameUniformity); + // The child is about to be destroyed, so perform any necessary cleanup. sync WillStop(); // Clean up in preparation for own destruction. sync Stop(); // Pause/resume the compositor. These are intended to be used on mobile, when // the compositor needs to pause/resume in lockstep with the application. diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -276,16 +276,17 @@ UNIFIED_SOURCES += [ 'composite/CompositableHost.cpp', 'composite/ContainerLayerComposite.cpp', 'composite/ContentHost.cpp', 'composite/FPSCounter.cpp', 'composite/ImageHost.cpp', 'composite/ImageLayerComposite.cpp', 'composite/LayerManagerComposite.cpp', 'composite/PaintedLayerComposite.cpp', + 'composite/ScrollData.cpp', 'composite/TextRenderer.cpp', 'composite/TextureHost.cpp', 'composite/TiledContentHost.cpp', 'Compositor.cpp', 'CopyableCanvasLayer.cpp', 'Effects.cpp', 'GLImages.cpp', 'ImageDataSerializer.cpp', @@ -384,11 +385,12 @@ CXXFLAGS += [ 'frameworks/base/include/media/stagefright', 'frameworks/base/include/media/stagefright/openmax', 'frameworks/av/include/media/stagefright', 'frameworks/native/include/media/openmax', ] ] MOCHITEST_MANIFESTS += ['apz/test/mochitest.ini'] +MOCHITEST_CHROME_MANIFESTS += ['apz/test/chrome.ini'] CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] CXXFLAGS += CONFIG['TK_CFLAGS'] diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -229,16 +229,17 @@ private: DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false); // These times should be in milliseconds DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold", TouchResampleVsyncDelayThreshold, int32_t, 20); DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8); DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17); DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust", TouchVsyncSampleAdjust, int32_t, 5); + DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-data", CollectScrollData, bool, false); DECL_GFX_PREF(Once, "gfx.vsync.compositor", VsyncAlignedCompositor, bool, false); // On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread // processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10. DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10); // Use vsync events generated by hardware DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled", HardwareVsyncEnabled, bool, false); DECL_GFX_PREF(Once, "gfx.vsync.refreshdriver", VsyncAlignedRefreshDriver, bool, false); DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);