--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -311,16 +311,21 @@ ClientLayerManager::BeginTransaction()
bool
ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags)
{
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
GeckoProfilerTracingRAII tracer("Paint", "Rasterize");
+ Maybe<TimeStamp> startTime;
+ if (gfxPrefs::LayersDrawFPS()) {
+ startTime = Some(TimeStamp::Now());
+ }
+
#ifdef WIN32
if (aCallbackData) {
// Content processes don't get OnPaint called. So update here whenever we
// may do Thebes drawing.
gfxDWriteFont::UpdateClearTypeUsage();
}
#endif
@@ -379,16 +384,21 @@ ClientLayerManager::EndTransactionIntern
NS_ASSERTION(!aCallback || !mTransactionIncomplete,
"If callback is not null, transaction must be complete");
if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
FrameLayerBuilder::InvalidateAllLayers(this);
}
+ if (startTime) {
+ PaintTiming& pt = mForwarder->GetPaintTiming();
+ pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
+ }
+
return !mTransactionIncomplete;
}
void
ClientLayerManager::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>& aConfigurations)
{
if (mForwarder) {
mForwarder->StorePluginWidgetConfigurations(aConfigurations);
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -235,16 +235,26 @@ public:
virtual void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch) override;
virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
virtual already_AddRefed<PersistentBufferProvider>
CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override;
+ static PaintTiming* MaybeGetPaintTiming(LayerManager* aManager) {
+ if (!aManager) {
+ return nullptr;
+ }
+ if (ClientLayerManager* lm = aManager->AsClientLayerManager()) {
+ return &lm->AsShadowForwarder()->GetPaintTiming();
+ }
+ return nullptr;
+ }
+
protected:
enum TransactionPhase {
PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
};
TransactionPhase mPhase;
private:
// Listen memory-pressure event for ClientLayerManager
new file mode 100644
--- /dev/null
+++ b/gfx/layers/composite/Diagnostics.cpp
@@ -0,0 +1,81 @@
+/* -*- 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 "Diagnostics.h"
+#include "mozilla/layers/LayersMessages.h"
+#include "nsPrintfCString.h"
+
+namespace mozilla {
+namespace layers {
+
+float
+TimedMetric::Average() const
+{
+ // We take at most 2 seconds of history.
+ TimeStamp latest = TimeStamp::Now();
+ float total = 0.0f;
+ size_t count = 0;
+ for (auto iter = mHistory.rbegin(); iter != mHistory.rend(); iter++) {
+ if ((latest - iter->second).ToSeconds() > 2.0f) {
+ break;
+ }
+ total += iter->first;
+ count++;
+ }
+
+ if (!count) {
+ return 0.0f;
+ }
+ return total / float(count);
+}
+
+Diagnostics::Diagnostics()
+ : mCompositeFps("Compositor"),
+ mTransactionFps("LayerTransactions")
+{
+}
+
+void
+Diagnostics::RecordPaintTimes(const PaintTiming& aPaintTimes)
+{
+ mDlbMs.Add(aPaintTimes.dlMs());
+ mFlbMs.Add(aPaintTimes.flbMs());
+ mRasterMs.Add(aPaintTimes.rasterMs());
+ mSerializeMs.Add(aPaintTimes.serializeMs());
+ mSendMs.Add(aPaintTimes.sendMs());
+}
+
+std::string
+Diagnostics::GetFrameOverlayString()
+{
+ TimeStamp now = TimeStamp::Now();
+ unsigned fps = unsigned(mCompositeFps.AddFrameAndGetFps(now));
+ unsigned txnFps = unsigned(mTransactionFps.GetFPS(now));
+
+ // DL = nsDisplayListBuilder
+ // FLB = FrameLayerBuilder
+ // R = ClientLayerManager::EndTransaction
+ // CP = ShadowLayerForwarder::EndTransaction (txn build)
+ // TX = LayerTransactionChild::SendUpdate (IPDL serialize+send)
+ // UP = LayerTransactionParent::RecvUpdate (IPDL deserialize, update, APZ update)
+ // CC_BUILD = Container prepare/composite frame building
+ // CC_EXEC = Container render/composite drawing
+ nsPrintfCString line1("FPS: %d (TXN: %d)", fps, txnFps);
+ nsPrintfCString line2("CC_BUILD: %0.1f CC_EXEC: %0.1f",
+ mPrepareMs.Average(),
+ mCompositeMs.Average());
+ nsPrintfCString line3("DL: %0.1f FLB: %0.1f R: %0.1f CP: %0.1f TX: %0.1f UP: %0.1f",
+ mDlbMs.Average(),
+ mFlbMs.Average(),
+ mRasterMs.Average(),
+ mSerializeMs.Average(),
+ mSendMs.Average(),
+ mUpdateMs.Average());
+
+ return std::string(line1.get()) + ", " + std::string(line2.get()) + "\n" + std::string(line3.get());
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/composite/Diagnostics.h
@@ -0,0 +1,96 @@
+/* -*- 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_gfx_layers_composite_Diagnostics_h
+#define mozilla_gfx_layers_composite_Diagnostics_h
+
+#include "FPSCounter.h"
+#include "gfxPrefs.h"
+#include "mozilla/TimeStamp.h"
+#include <deque>
+#include <string>
+#include <utility>
+
+namespace mozilla {
+namespace layers {
+
+class PaintTiming;
+
+class TimedMetric
+{
+ typedef std::pair<float, TimeStamp> Entry;
+
+public:
+ void Add(float aValue) {
+ if (mHistory.size() > kMaxHistory) {
+ mHistory.pop_front();
+ }
+ mHistory.push_back(Entry(aValue, TimeStamp::Now()));
+ }
+
+ float Average() const;
+
+private:
+ static const size_t kMaxHistory = 60;
+
+ std::deque<Entry> mHistory;
+};
+
+class Diagnostics
+{
+public:
+ Diagnostics();
+
+ void RecordPaintTimes(const PaintTiming& aPaintTimes);
+ void RecordUpdateTime(float aValue) {
+ mUpdateMs.Add(aValue);
+ }
+ void RecordPrepareTime(float aValue) {
+ mPrepareMs.Add(aValue);
+ }
+ void RecordCompositeTime(float aValue) {
+ mCompositeMs.Add(aValue);
+ }
+ void AddTxnFrame() {
+ mTransactionFps.AddFrame(TimeStamp::Now());
+ }
+
+ std::string GetFrameOverlayString();
+
+ class Record {
+ public:
+ Record() {
+ if (gfxPrefs::LayersDrawFPS()) {
+ mStart = TimeStamp::Now();
+ }
+ }
+ bool Recording() const {
+ return !mStart.IsNull();
+ }
+ float Duration() const {
+ return (TimeStamp::Now() - mStart).ToMilliseconds();
+ }
+
+ private:
+ TimeStamp mStart;
+ };
+
+private:
+ FPSCounter mCompositeFps;
+ FPSCounter mTransactionFps;
+ TimedMetric mDlbMs;
+ TimedMetric mFlbMs;
+ TimedMetric mRasterMs;
+ TimedMetric mSerializeMs;
+ TimedMetric mSendMs;
+ TimedMetric mUpdateMs;
+ TimedMetric mPrepareMs;
+ TimedMetric mCompositeMs;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_composite_Diagnostics_h
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -5,16 +5,17 @@
#include "LayerManagerComposite.h"
#include <stddef.h> // for size_t
#include <stdint.h> // for uint16_t, uint32_t
#include "CanvasLayerComposite.h" // for CanvasLayerComposite
#include "ColorLayerComposite.h" // for ColorLayerComposite
#include "CompositableHost.h" // for CompositableHost
#include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc
+#include "Diagnostics.h"
#include "FPSCounter.h" // for FPSState, FPSCounter
#include "FrameMetrics.h" // for FrameMetrics
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc
#include "ImageLayerComposite.h" // for ImageLayerComposite
#include "Layers.h" // for Layer, ContainerLayer, etc
#include "LayerScope.h" // for LayerScope Tool
#include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
#include "PaintedLayerComposite.h" // for PaintedLayerComposite
@@ -119,28 +120,42 @@ HostLayerManager::HostLayerManager()
, mWindowOverlayChanged(false)
, mLastPaintTime(TimeDuration::Forever())
, mRenderStartTime(TimeStamp::Now())
{}
HostLayerManager::~HostLayerManager()
{}
+void
+HostLayerManager::RecordPaintTimes(const PaintTiming& aTiming)
+{
+ mDiagnostics->RecordPaintTimes(aTiming);
+}
+
+void
+HostLayerManager::RecordUpdateTime(float aValue)
+{
+ mDiagnostics->RecordUpdateTime(aValue);
+}
+
+
/**
* LayerManagerComposite
*/
LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
: mUnusedApzTransformWarning(false)
, mDisabledApzWarning(false)
, mCompositor(aCompositor)
, mInTransaction(false)
, mIsCompositorReady(false)
, mGeometryChanged(true)
{
mTextRenderer = new TextRenderer(aCompositor);
+ mDiagnostics = MakeUnique<Diagnostics>();
MOZ_ASSERT(aCompositor);
#ifdef USE_SKIA
mPaintCounter = nullptr;
#endif
}
LayerManagerComposite::~LayerManagerComposite()
@@ -920,18 +935,31 @@ LayerManagerComposite::Render(const nsIn
RefPtr<CompositingRenderTarget> previousTarget;
if (haveLayerEffects) {
previousTarget = PushGroupForLayerEffects();
} else {
mTwoPassTmpTarget = nullptr;
}
// Render our layers.
- RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
- RootLayer()->RenderLayer(clipRect.ToUnknownRect(), Nothing());
+ {
+ Diagnostics::Record record;
+ RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
+ if (record.Recording()) {
+ mDiagnostics->RecordPrepareTime(record.Duration());
+ }
+ }
+ // Execute draw commands.
+ {
+ Diagnostics::Record record;
+ RootLayer()->RenderLayer(clipRect.ToUnknownRect(), Nothing());
+ if (record.Recording()) {
+ mDiagnostics->RecordCompositeTime(record.Duration());
+ }
+ }
RootLayer()->Cleanup();
if (!mRegionToClear.IsEmpty()) {
for (auto iter = mRegionToClear.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& r = iter.Get();
mCompositor->ClearRect(Rect(r.x, r.y, r.width, r.height));
}
}
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -47,16 +47,17 @@ class DrawTarget;
} // namespace gfx
namespace layers {
class CanvasLayerComposite;
class ColorLayerComposite;
class Compositor;
class ContainerLayerComposite;
+class Diagnostics;
struct EffectChain;
class ImageLayer;
class ImageLayerComposite;
class LayerComposite;
class RefLayerComposite;
class PaintedLayerComposite;
class TextRenderer;
class CompositingRenderTarget;
@@ -164,16 +165,19 @@ public:
void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
virtual bool AlwaysScheduleComposite() const {
return false;
}
+ void RecordPaintTimes(const PaintTiming& aTiming);
+ void RecordUpdateTime(float aValue);
+
TimeStamp GetCompositionTime() const {
return mCompositionTime;
}
void SetCompositionTime(TimeStamp aTimeStamp) {
mCompositionTime = aTimeStamp;
if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
mCompositionTime >= mCompositeUntilTime) {
mCompositeUntilTime = TimeStamp();
@@ -191,16 +195,17 @@ public:
protected:
bool mDebugOverlayWantsNextFrame;
nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
// Testing property. If hardware composer is supported, this will return
// true if the last frame was deemed 'too complicated' to be rendered.
float mWarningLevel;
mozilla::TimeStamp mWarnTime;
+ UniquePtr<Diagnostics> mDiagnostics;
bool mWindowOverlayChanged;
TimeDuration mLastPaintTime;
TimeStamp mRenderStartTime;
// Render time for the current composition.
TimeStamp mCompositionTime;
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -142,16 +142,20 @@ public:
NS_IMETHOD_(MozExternalRefCountType) Release() override { return HostIPCAllocator::Release(); }
base::ProcessId RemotePid() override;
bool StartSharingMetrics(mozilla::ipc::SharedMemoryBasic::Handle aHandle,
CrossProcessMutexHandle aMutexHandle,
uint64_t aLayersId,
uint32_t aApzcId) override;
bool StopSharingMetrics(FrameMetrics::ViewID aScrollId,
uint32_t aApzcId) override;
+
+ virtual bool IsRemote() const {
+ return false;
+ }
};
class CompositorBridgeParent final : public CompositorBridgeParentBase
, public CompositorController
, public CompositorVsyncSchedulerOwner
{
friend class CompositorThreadHolder;
friend class InProcessCompositorSession;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -156,16 +156,20 @@ public:
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
const LayoutDeviceIntSize& aSize,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;
+ bool IsRemote() const override {
+ return true;
+ }
+
protected:
void OnChannelConnected(int32_t pid) override {
mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();
}
private:
// Private destructor, to discourage deletion outside of Release():
virtual ~CrossProcessCompositorBridgeParent();
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -144,19 +144,17 @@ LayerTransactionParent::RecvInitReadLock
mozilla::ipc::IPCResult
LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
{
GeckoProfilerTracingRAII tracer("Paint", "LayerTransaction");
PROFILER_LABEL("LayerTransactionParent", "RecvUpdate",
js::ProfileEntry::Category::GRAPHICS);
-#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp updateStart = TimeStamp::Now();
-#endif
MOZ_LAYERS_LOG(("[ParentSide] received txn with %" PRIuSIZE " edits", aInfo.cset().Length()));
UpdateFwdTransactionId(aInfo.fwdTransactionId());
AutoClearReadLocks clearLocks(mReadLocks);
if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
for (const auto& op : aInfo.toDestroy()) {
@@ -501,16 +499,18 @@ LayerTransactionParent::RecvUpdate(const
if (severity > 1.f) {
severity = 1.f;
}
mLayerManager->VisualFrameWarning(severity);
printf_stderr("LayerTransactionParent::RecvUpdate transaction from process %d took %f ms",
OtherPid(),
latency.ToMilliseconds());
}
+
+ mLayerManager->RecordUpdateTime((TimeStamp::Now() - updateStart).ToMilliseconds());
}
return IPC_OK();
}
bool
LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp)
{
@@ -1021,10 +1021,22 @@ LayerTransactionParent::RecvReleaseLayer
mozilla::ipc::IPCResult
LayerTransactionParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
{
ReleaseCompositable(aHandle);
return IPC_OK();
}
+mozilla::ipc::IPCResult
+LayerTransactionParent::RecvRecordPaintTimes(const PaintTiming& aTiming)
+{
+ // Currently we only add paint timings for remote layers. In the future
+ // we could be smarter and use paint timings from the UI process, either
+ // as a separate overlay or if no remote layers are attached.
+ if (mLayerManager && mCompositorBridge->IsRemote()) {
+ mLayerManager->RecordPaintTimes(aTiming);
+ }
+ return IPC_OK();
+}
+
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -135,16 +135,17 @@ protected:
const float& aX, const float& aY) override;
virtual mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aId,
const float& aValue) override;
virtual mozilla::ipc::IPCResult RecvFlushApzRepaints() override;
virtual mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* aOutData) override;
virtual mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, float* aValue) override;
virtual mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets) override;
+ virtual mozilla::ipc::IPCResult RecvRecordPaintTimes(const PaintTiming& aTiming) override;
bool SetLayerAttributes(const OpSetLayerAttributes& aOp);
virtual void ActorDestroy(ActorDestroyReason why) override;
template <typename T>
bool BindLayer(const RefPtr<Layer>& aLayer, const T& aCreateOp) {
return BindLayerToHandle(aLayer, aCreateOp.layer());
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -529,16 +529,24 @@ struct ImageCompositeNotification {
uint32_t frameID;
uint32_t producerID;
};
union AsyncParentMessageData {
OpNotifyNotUsed;
};
+struct PaintTiming {
+ float serializeMs;
+ float sendMs;
+ float dlMs;
+ float flbMs;
+ float rasterMs;
+};
+
struct TransactionInfo
{
Edit[] cset;
OpSetSimpleLayerAttributes[] setSimpleAttrs;
OpSetLayerAttributes[] setAttrs;
CompositableOperation[] paints;
OpDestroy[] toDestroy;
uint64_t fwdTransactionId;
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -117,15 +117,17 @@ parent:
// Query a named property from the last frame
sync RequestProperty(nsString property) returns (float value);
// Tell the compositor to notify APZ that a layer has been confirmed for an
// input event.
async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
+ async RecordPaintTimes(PaintTiming timing);
+
async Shutdown();
child:
async __delete__();
};
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -10,16 +10,17 @@
#include <set> // for _Rb_tree_const_iterator, etc
#include <vector> // for vector
#include "GeckoProfiler.h" // for PROFILER_LABEL
#include "ISurfaceAllocator.h" // for IsSurfaceDescriptorValid
#include "Layers.h" // for Layer
#include "RenderTrace.h" // for RenderTraceScope
#include "gfx2DGlue.h" // for Moz2D transition helpers
#include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform
+#include "gfxPrefs.h"
//#include "gfxSharedImageSurface.h" // for gfxSharedImageSurface
#include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t
#include "IPDLActor.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/CompositableClient.h" // for CompositableClient, etc
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ContentClient.h"
@@ -581,16 +582,21 @@ ShadowLayerForwarder::EndTransaction(con
TransactionInfo info;
MOZ_ASSERT(IPCOpen(), "no manager to forward to");
if (!IPCOpen()) {
return false;
}
+ Maybe<TimeStamp> startTime;
+ if (gfxPrefs::LayersDrawFPS()) {
+ startTime = Some(TimeStamp::Now());
+ }
+
GetCompositorBridgeChild()->WillEndTransaction();
MOZ_ASSERT(aId);
PROFILER_LABEL("ShadowLayerForwarder", "EndTransaction",
js::ProfileEntry::Category::GRAPHICS);
RenderTraceScope rendertrace("Foward Transaction", "000091");
@@ -719,32 +725,42 @@ ShadowLayerForwarder::EndTransaction(con
aRegionToClear);
info.targetConfig() = targetConfig;
if (!GetTextureForwarder()->IsSameProcess()) {
MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
PlatformSyncBeforeUpdate();
}
+ if (startTime) {
+ mPaintTiming.serializeMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
+ startTime = Some(TimeStamp::Now());
+ }
+
for (ReadLockVector& locks : mTxn->mReadLocks) {
if (locks.Length()) {
if (!mShadowManager->SendInitReadLocks(locks)) {
MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending read locks failed!"));
return false;
}
}
}
MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
RenderTraceScope rendertrace3("Forward Transaction", "000093");
if (!mShadowManager->SendUpdate(info)) {
MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
return false;
}
+ if (startTime) {
+ mPaintTiming.sendMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
+ mShadowManager->SendRecordPaintTimes(mPaintTiming);
+ }
+
*aSent = true;
mIsFirstPaint = false;
mPaintSyncId = 0;
MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
return true;
}
RefPtr<CompositableClient>
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -387,16 +387,20 @@ public:
virtual uint64_t GetFwdTransactionId() override;
void ReleaseLayer(const LayerHandle& aHandle);
bool InForwarderThread() override {
return NS_IsMainThread();
}
+ PaintTiming& GetPaintTiming() {
+ return mPaintTiming;
+ }
+
// Returns true if aSurface wraps a Shmem.
static bool IsShmem(SurfaceDescriptor* aSurface);
/**
* Sends a synchronous ping to the compsoitor.
*
* This is bad for performance and should only be called as a last resort if the
* compositor may be blocked for a long period of time, to avoid that the content
@@ -437,16 +441,17 @@ private:
DiagnosticTypes mDiagnosticTypes;
bool mIsFirstPaint;
bool mWindowOverlayChanged;
int32_t mPaintSyncId;
InfallibleTArray<PluginWindowData> mPluginWindowData;
UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
uint64_t mNextLayerHandle;
nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
+ PaintTiming mPaintTiming;
};
class CompositableClient;
/**
* A ShadowableLayer is a Layer can be shared with a parent context
* through a ShadowLayerForwarder. A ShadowableLayer maps to a
* Shadow*Layer in a parent context.
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -311,16 +311,17 @@ UNIFIED_SOURCES += [
'client/TiledContentClient.cpp',
'composite/AnimationMetricsTracker.cpp',
'composite/AsyncCompositionManager.cpp',
'composite/CanvasLayerComposite.cpp',
'composite/ColorLayerComposite.cpp',
'composite/CompositableHost.cpp',
'composite/ContainerLayerComposite.cpp',
'composite/ContentHost.cpp',
+ 'composite/Diagnostics.cpp',
'composite/FPSCounter.cpp',
'composite/FrameUniformityData.cpp',
'composite/GPUVideoTextureHost.cpp',
'composite/ImageComposite.cpp',
'composite/ImageHost.cpp',
'composite/ImageLayerComposite.cpp',
'composite/LayerManagerComposite.cpp',
'composite/PaintedLayerComposite.cpp',
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3667,16 +3667,24 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
canvasArea.IntersectRect(canvasArea, visibleRegion.GetBounds());
nsDisplayListBuilder::AutoBuildingDisplayList
buildingDisplayList(&builder, aFrame, canvasArea, false);
presShell->AddCanvasBackgroundColorItem(
builder, list, aFrame, canvasArea, aBackstop);
}
builder.LeavePresShell(aFrame, &list);
+
+ if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
+ if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
+ if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
+ pt->dlMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
+ }
+ }
+ }
}
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
startBuildDisplayList);
bool profilerNeedsDisplayList = profiler_feature_active("displaylistdump");
bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint();
#ifdef MOZ_DUMP_PAINTING
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -78,16 +78,17 @@
#include "mozilla/GeckoRestyleManager.h"
#include "nsCaret.h"
#include "nsISelection.h"
#include "nsDOMTokenList.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "nsCSSProps.h"
#include "nsPluginFrame.h"
#include "nsSVGMaskFrame.h"
+#include "ClientLayerManager.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderDisplayItemLayer.h"
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/WebRenderDisplayItemLayer.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
@@ -2110,19 +2111,26 @@ already_AddRefed<LayerManager> nsDisplay
rootLayer->SetScrollMetadata(nsTArray<ScrollMetadata>());
}
ContainerLayerParameters containerParameters
(presShell->GetResolution(), presShell->GetResolution());
{
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
+
root = layerBuilder->
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
containerParameters, nullptr);
+
+ if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
+ if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(layerManager)) {
+ pt->flbMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
+ }
+ }
}
if (!root) {
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
return nullptr;
}
// Root is being scaled up by the X/Y resolution. Scale it back down.
root->SetPostScale(1.0f/containerParameters.mXScale,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -4917,16 +4917,20 @@ class PaintTelemetry
COUNT,
};
class AutoRecord
{
public:
explicit AutoRecord(Metric aMetric);
~AutoRecord();
+
+ TimeStamp GetStart() const {
+ return mStart;
+ }
private:
Metric mMetric;
mozilla::TimeStamp mStart;
};
class AutoRecordPaint
{
public: